├── .github └── workflows │ ├── build.yml │ ├── build_per_profile.yml │ └── build_per_profile_per_branch.yml ├── .gitignore ├── README.md ├── doc └── wsl-buildenv.md ├── main.py ├── module ├── AAA.py ├── AAB.py ├── ABB.py ├── args.py ├── checksum.py ├── debug.py ├── fetch.py ├── path.py ├── prepare_source.py ├── profile.py └── util.py ├── patch ├── binutils │ ├── fix-path-corruption_2.41.patch │ └── fix-path-corruption_2.43.patch ├── crt │ ├── fix-i386-strtoi64-strtoui64.patch │ ├── fix-x64-difftime64.patch │ ├── fix-x64-wassert_11.patch │ └── fix-x64-wassert_12.patch ├── gcc │ ├── disable-vectorized-lexer_13.patch │ ├── disable-vectorized-lexer_15.patch │ ├── fix-libcpp-setlocale.patch │ ├── fix-make-variable_12.patch │ ├── fix-make-variable_14.patch │ ├── fix-ucrt-pipe.patch │ └── fix-vt-seq.patch ├── gdb │ ├── fix-iconv-cp65001.patch │ ├── fix-pythondir.patch │ ├── fix-thread_14.patch │ ├── fix-thread_16.patch │ └── fix-ui-style-regex-init.patch ├── python │ ├── disable-shared-xxlimited_3.12.patch │ ├── fix-mingw-build_3.12.patch │ ├── fix-mingw-build_3.13.patch │ ├── fix-thread-touch-last-error_3.12.patch │ ├── python-config.sh │ ├── xmake_3.12.lua │ └── xmake_3.13.lua └── xmake │ ├── fix-module-mapper-path.patch │ └── tbox-ignore-process-group.patch ├── sat.py ├── support ├── buildenv-alpine │ └── Dockerfile ├── buildenv-ubuntu │ └── Dockerfile ├── intl │ ├── .clang-format │ ├── .gitignore │ ├── LICENSE │ ├── include │ │ └── libintl.h │ ├── src │ │ ├── _nl_expand_alias.cc │ │ ├── _nl_msg_cat_cntr.cc │ │ ├── bindtextdomain.cc │ │ ├── dcgettext.cc │ │ ├── dcngettext.cc │ │ ├── dgettext.cc │ │ ├── dngettext.cc │ │ ├── gettext.cc │ │ ├── internal-state.h │ │ ├── ngettext.cc │ │ └── textdomain.cc │ └── xmake.lua ├── test │ ├── .clang-format │ ├── .gitignore │ ├── Makefile │ ├── c++11 │ │ └── thread.cc │ ├── c++17 │ │ ├── filesystem.cc │ │ └── fstream.cc │ ├── c++23 │ │ ├── import-std.cc │ │ └── print.cc │ ├── c++98 │ │ └── hello.cc │ ├── c23 │ │ ├── embed.c │ │ └── message.txt │ ├── c89 │ │ └── hello.c │ ├── chimaera.lua │ ├── debug │ │ └── breakpoint.cc │ ├── enable_if.lua │ ├── gnu++98 │ │ └── bits-stdc++.cc │ └── xmake.lua ├── thunk │ ├── .clang-format │ ├── .gitignore │ ├── LICENSE │ ├── include │ │ └── thunk │ │ │ ├── _common.h │ │ │ ├── addrinfo.h │ │ │ ├── ddk │ │ │ ├── ntifs.h │ │ │ └── wdm.h │ │ │ ├── findvolumedata.h │ │ │ ├── libc │ │ │ ├── ctype.h │ │ │ ├── rand.h │ │ │ ├── stdlib.h │ │ │ ├── string.h │ │ │ └── wchar.h │ │ │ ├── misc.h │ │ │ ├── os.h │ │ │ ├── stl │ │ │ ├── algorithm.h │ │ │ ├── iterator.h │ │ │ └── mutex.h │ │ │ ├── string.h │ │ │ ├── test.h │ │ │ ├── try_get.h │ │ │ ├── wntcrt │ │ │ ├── errno.h │ │ │ └── time.h │ │ │ └── yy │ │ │ ├── api-ms-win-core-localization.h │ │ │ ├── api-ms-win-core-path.h │ │ │ ├── api-ms-win-core-processtopology-obsolete.h │ │ │ ├── memory.h │ │ │ ├── strsafe.h │ │ │ └── yy.h │ ├── module │ │ ├── thunk_list_core.py │ │ └── thunk_list_toolchain.py │ ├── patch.py │ ├── src │ │ ├── 5.0 │ │ │ ├── advapi32 │ │ │ │ └── ConvertStringSecurityDescriptorToSecurityDescriptorW.cc │ │ │ ├── kernel32 │ │ │ │ ├── CreateHardLinkW.cc │ │ │ │ ├── CreateToolhelp32Snapshot.cc │ │ │ │ ├── FindFirstVolumeW.cc │ │ │ │ ├── FindNextVolumeW.cc │ │ │ │ ├── FindVolumeClose.cc │ │ │ │ ├── GetCPInfoExA.cc │ │ │ │ ├── GetFileSizeEx.cc │ │ │ │ ├── GetLongPathNameW.cc │ │ │ │ ├── GetVolumePathNameW.cc │ │ │ │ ├── GlobalMemoryStatusEx.cc │ │ │ │ ├── Module32First.cc │ │ │ │ ├── Module32Next.cc │ │ │ │ └── SetFilePointerEx.cc │ │ │ └── msvcrt │ │ │ │ ├── _ctime64.cc │ │ │ │ ├── _findfirst64.cc │ │ │ │ ├── _findfirst64.test.cc │ │ │ │ ├── _findnext64.cc │ │ │ │ ├── _fstat64.cc │ │ │ │ ├── _futime64.cc │ │ │ │ ├── _futime64.test.cc │ │ │ │ ├── _gmtime64.cc │ │ │ │ ├── _gmtime64.test.cc │ │ │ │ ├── _localtime64.cc │ │ │ │ ├── _localtime64.test.cc │ │ │ │ ├── _stat64.cc │ │ │ │ ├── _time64.cc │ │ │ │ ├── _utime64.cc │ │ │ │ ├── _utime64.test.cc │ │ │ │ ├── _wfindfirst64.cc │ │ │ │ ├── _wfindfirst64.test.cc │ │ │ │ ├── _wfindnext64.cc │ │ │ │ ├── _wstat64.cc │ │ │ │ ├── _wutime64.cc │ │ │ │ └── _wutime64.test.cc │ │ ├── 5.1 │ │ │ ├── kernel32 │ │ │ │ ├── AddVectoredExceptionHandler.cc │ │ │ │ ├── GetConsoleProcessList.cc │ │ │ │ ├── GetModuleHandleExW.cc │ │ │ │ ├── GetNumaHighestNodeNumber.cc │ │ │ │ ├── GetNumaNodeProcessorMask.cc │ │ │ │ ├── GetSystemTimes.cc │ │ │ │ ├── GetSystemWow64DirectoryA.cc │ │ │ │ ├── GetVolumePathNamesForVolumeNameW.cc │ │ │ │ └── RemoveVectoredExceptionHandler.cc │ │ │ ├── msvcrt │ │ │ │ ├── _aligned_free.cc │ │ │ │ ├── _aligned_malloc.cc │ │ │ │ └── _aligned_malloc.test.cc │ │ │ └── ws2_32 │ │ │ │ ├── freeaddrinfo.cc │ │ │ │ ├── getaddrinfo.cc │ │ │ │ ├── getaddrinfo.test.cc │ │ │ │ └── getnameinfo.cc │ │ ├── 5.2 │ │ │ ├── advapi32 │ │ │ │ ├── RegDeleteKeyExA.cc │ │ │ │ └── RegDeleteKeyExW.cc │ │ │ └── kernel32 │ │ │ │ ├── FlsAlloc.cc │ │ │ │ ├── FlsFree.cc │ │ │ │ ├── FlsGetValue.cc │ │ │ │ ├── FlsSetValue.cc │ │ │ │ ├── GetCurrentProcessorNumber.cc │ │ │ │ ├── GetLargePageMinimum.cc │ │ │ │ ├── NeedCurrentDirectoryForExePathA.cc │ │ │ │ └── NeedCurrentDirectoryForExePathW.cc │ │ ├── 6.0 │ │ │ ├── bcrypt │ │ │ │ └── BCryptGenRandom.cc │ │ │ ├── kernel32 │ │ │ │ ├── CancelIoEx.cc │ │ │ │ ├── CompareStringOrdinal.cc │ │ │ │ ├── CreateSymbolicLinkA.cc │ │ │ │ ├── CreateSymbolicLinkW.cc │ │ │ │ ├── CreateWaitableTimerExW.cc │ │ │ │ ├── DeleteProcThreadAttributeList.cc │ │ │ │ ├── GetFileInformationByHandleEx.cc │ │ │ │ ├── GetFinalPathNameByHandleA.cc │ │ │ │ ├── GetFinalPathNameByHandleW.cc │ │ │ │ ├── GetTickCount64.cc │ │ │ │ ├── InitializeProcThreadAttributeList.cc │ │ │ │ ├── LCMapStringEx.cc │ │ │ │ ├── LocaleNameToLCID.cc │ │ │ │ ├── SetFileInformationByHandle.cc │ │ │ │ └── UpdateProcThreadAttribute.cc │ │ │ └── msvcrt │ │ │ │ ├── _wputenv_s.cc │ │ │ │ ├── _wputenv_s.test.cc │ │ │ │ ├── wcscat_s.cc │ │ │ │ ├── wcscat_s.test.cc │ │ │ │ ├── wcscpy_s.cc │ │ │ │ ├── wcscpy_s.test.cc │ │ │ │ ├── wcsncat_s.cc │ │ │ │ ├── wcsncat_s.test.cc │ │ │ │ ├── wcsncpy_s.cc │ │ │ │ ├── wcsncpy_s.test.cc │ │ │ │ └── wcstok_s.cc │ │ ├── 6.1 │ │ │ └── kernel32 │ │ │ │ ├── GetActiveProcessorCount.cc │ │ │ │ ├── GetActiveProcessorGroupCount.cc │ │ │ │ ├── GetMaximumProcessorCount.cc │ │ │ │ ├── GetMaximumProcessorGroupCount.cc │ │ │ │ └── SetWaitableTimerEx.cc │ │ └── 6.2 │ │ │ ├── api-ms-win-core-path-l1-1-0 │ │ │ ├── PathAllocCanonicalize.cc │ │ │ ├── PathAllocCombine.cc │ │ │ ├── PathCchAddBackslash.cc │ │ │ ├── PathCchAddBackslashEx.cc │ │ │ ├── PathCchAddExtension.cc │ │ │ ├── PathCchAppend.cc │ │ │ ├── PathCchAppendEx.cc │ │ │ ├── PathCchCanonicalize.cc │ │ │ ├── PathCchCanonicalizeEx.cc │ │ │ ├── PathCchCombine.cc │ │ │ ├── PathCchCombineEx.cc │ │ │ ├── PathCchFindExtension.cc │ │ │ ├── PathCchIsRoot.cc │ │ │ ├── PathCchRemoveBackslash.cc │ │ │ ├── PathCchRemoveBackslashEx.cc │ │ │ ├── PathCchRemoveExtension.cc │ │ │ ├── PathCchRemoveFileSpec.cc │ │ │ ├── PathCchRenameExtension.cc │ │ │ ├── PathCchSkipRoot.cc │ │ │ ├── PathCchStripPrefix.cc │ │ │ ├── PathCchStripToRoot.cc │ │ │ └── PathIsUNCEx.cc │ │ │ └── kernel32 │ │ │ ├── AddDllDirectory.cc │ │ │ ├── CopyFile2.cc │ │ │ ├── CopyFile2.test.cc │ │ │ ├── GetSystemTimePreciseAsFileTime.cc │ │ │ ├── GetSystemTimePreciseAsFileTime.test.cc │ │ │ └── RemoveDllDirectory.cc │ └── xmake.lua └── utf8 │ ├── utf8-init.c │ └── utf8-manifest.rc └── test.py /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | name: Build (${{ matrix.profile }}) 8 | strategy: 9 | fail-fast: false 10 | matrix: 11 | profile: [ 12 | 64-mcf, 64-win32, 64-ucrt, 64-msvcrt, 13 | 32-mcf, 32-win32, 32-ucrt, 32-msvcrt, 14 | 15 | # profile variants 16 | 64-ucrt_ws2003, 64-msvcrt_ws2003, 17 | 32-ucrt_winxp, 32-msvcrt_winnt40, 18 | ] 19 | uses: ./.github/workflows/build_per_profile.yml 20 | with: 21 | profile: ${{ matrix.profile }} 22 | release_skip_profile: ${{ contains(fromJson('["64-ucrt_ws2003", "64-msvcrt_ws2003", "32-ucrt_winxp"]'), matrix.profile) }} 23 | release_do_release_xmake: ${{ contains(fromJson('["32-msvcrt_winnt40"]'), matrix.profile) }} 24 | -------------------------------------------------------------------------------- /.github/workflows/build_per_profile.yml: -------------------------------------------------------------------------------- 1 | name: Build per profile 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | profile: 7 | required: true 8 | type: string 9 | release_skip_profile: 10 | required: true 11 | type: boolean 12 | release_do_release_xmake: 13 | required: true 14 | type: boolean 15 | 16 | jobs: 17 | build: 18 | name: Build (${{ matrix.branch }}, ${{ inputs.profile }}) 19 | strategy: 20 | fail-fast: false 21 | matrix: 22 | branch: [16, 15, 14, 13] 23 | include: 24 | - prerelease: false 25 | - { branch: 16, prerelease: true } 26 | - { branch: 15, prerelease: true } 27 | - make_latest: false 28 | - { branch: 14, make_latest: true } 29 | uses: ./.github/workflows/build_per_profile_per_branch.yml 30 | with: 31 | profile: ${{ inputs.profile }} 32 | branch: ${{ matrix.branch }} 33 | prerelease: ${{ matrix.prerelease }} 34 | make_latest: ${{ matrix.make_latest }} 35 | release_skip_profile_branch: ${{ github.ref_type == 'tag' && (inputs.release_skip_profile || !startsWith(github.ref_name, matrix.branch)) }} 36 | release_do_release: ${{ github.ref_type == 'tag' && !inputs.release_skip_profile && startsWith(github.ref_name, matrix.branch) }} 37 | release_do_release_xmake: ${{ inputs.release_do_release_xmake }} 38 | 39 | target_sat_archive: 40 | name: Target semi-automated testing archive (${{ inputs.profile }}) 41 | if: github.ref_type != 'tag' 42 | runs-on: ubuntu-24.04 43 | needs: build 44 | 45 | steps: 46 | - uses: actions/checkout@v4 47 | 48 | - uses: ConorMacBride/install-package@v1 49 | with: 50 | apt: libarchive-tools 51 | 52 | - uses: actions/download-artifact@v4 53 | with: 54 | pattern: mingw${{ inputs.profile }}-* 55 | path: dist 56 | 57 | - name: Create test archive 58 | run: | 59 | mv dist/*/*.tar.zst dist/ 60 | 61 | ./sat.py -b 16 -p ${{ inputs.profile }} 62 | ./sat.py -b 15 -p ${{ inputs.profile }} 63 | ./sat.py -b 14 -p ${{ inputs.profile }} 64 | ./sat.py -b 13 -p ${{ inputs.profile }} 65 | 66 | ( 67 | cd pkg 68 | 7z a -t7z -mx9 -ms=on -m0=LZMA:d=256m:fb64 ../dist/sat${{ inputs.profile }}.7z sat${{ inputs.profile }} 69 | ) 70 | 71 | - uses: actions/upload-artifact@v4 72 | with: 73 | name: sat${{ inputs.profile }} 74 | path: dist/sat${{ inputs.profile }}.7z 75 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | assets 3 | build 4 | dist 5 | layer 6 | pkg 7 | -------------------------------------------------------------------------------- /doc/wsl-buildenv.md: -------------------------------------------------------------------------------- 1 | # Prepare WSL Build Environment 2 | 3 | The build scripts make use of overlayfs and require root privileges, so AN EXCLUSIVE WSL 2 DISTRO is required. 4 | 5 | ## Install WSL 6 | 7 | See [Microsoft Learn](https://learn.microsoft.com/en-us/windows/wsl/install). 8 | 9 | ## Create an Exclusive Distro 10 | 11 | 1. Download Ubuntu 24.04 WSL rootfs tarball from [Ubuntu Cloud Images](https://cloud-images.ubuntu.com/wsl/noble/current/). 12 | 2. Import it into WSL, for example: 13 | ```pwsh 14 | wsl --import mingw-lite-buildenv C:\wsl\mingw-lite-buildenv Downloads\ubuntu-noble-wsl-amd64-ubuntu.rootfs.tar.gz 15 | ``` 16 | 3. Restart Windows Terminal. “mingw-lite-buildenv” now appears in the dropdown list. 17 | 18 | ## Install Dependencies 19 | 20 | 1. Launch the exclusive distro (launch “Terminal”, select “mingw-lite-buildenv” from the dropdown list). 21 | 2. Install required packages: 22 | ```bash 23 | apt update 24 | apt install --no-install-recommends -y \ 25 | autoconf automake build-essential flex libtool meson texinfo \ 26 | 7zip ca-certificates curl file gawk libarchive-tools python3 python3-packaging zstd 27 | ``` 28 | 29 | ## Clone the Repository 30 | 31 | Cloning to Windows filesystem is recommended. For example with Windows Git Bash: 32 | ```bash 33 | git clone https://github.com/redpanda-cpp/mingw-lite.git /d/mingw-lite --config=core.autocrlf=false 34 | ``` 35 | 36 | Auto-converting line endings must be disabled. To disable in an existing repo, run: 37 | ```bash 38 | # save workspace 39 | git add * 40 | git stash 41 | 42 | # do convertion 43 | git config core.autocrlf false 44 | git reset --hard 45 | 46 | # restore workspace 47 | git stash pop 48 | ``` 49 | -------------------------------------------------------------------------------- /module/args.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import logging 3 | import os 4 | import subprocess 5 | from subprocess import PIPE 6 | 7 | def get_gcc_triplet(): 8 | try: 9 | result = subprocess.run(['gcc', '-dumpmachine'], stdout = PIPE, stderr = PIPE, check = True) 10 | return result.stdout.decode('utf-8').strip() 11 | except Exception as e: 12 | logging.error(f'Failed to get GCC triplet: {e}') 13 | return None 14 | 15 | def parse_args() -> argparse.Namespace: 16 | parser = argparse.ArgumentParser() 17 | parser.add_argument( 18 | '-b', '--branch', 19 | type = str, 20 | choices = ['16', '15', '14', '13'], 21 | required = True, 22 | help = 'GCC branch to build', 23 | ) 24 | parser.add_argument( 25 | '-p', '--profile', 26 | type = str, 27 | choices = [ 28 | '64-mcf', '64-win32', '64-ucrt', '64-msvcrt', 29 | '32-mcf', '32-win32', '32-ucrt', '32-msvcrt', 30 | '64-ucrt_ws2003', '64-msvcrt_ws2003', 31 | '32-ucrt_winxp', '32-msvcrt_winnt40', 32 | ], 33 | required = True, 34 | help = 'MinGW profile to build', 35 | ) 36 | 37 | gcc_triplet = get_gcc_triplet() 38 | parser.add_argument( 39 | '--build', 40 | type = str, 41 | default = gcc_triplet, 42 | required = not gcc_triplet, 43 | help = 'Build system triplet', 44 | ) 45 | 46 | parser.add_argument( 47 | '-c', '--clean', 48 | action = 'store_true', 49 | help = 'Clean build directories', 50 | ) 51 | parser.add_argument( 52 | '-j', '--jobs', 53 | type = int, 54 | default = os.cpu_count(), 55 | ) 56 | parser.add_argument( 57 | '-nx', '--no-cross', 58 | action = 'store_true', 59 | help = 'Do not build cross toolchain', 60 | ) 61 | parser.add_argument( 62 | '-v', '--verbose', 63 | action = 'count', 64 | default = 0, 65 | help = 'Increase verbosity (up to 2)', 66 | ) 67 | 68 | result = parser.parse_args() 69 | return result 70 | -------------------------------------------------------------------------------- /module/checksum.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | 3 | CHECKSUMS: Dict[str, str] = { 4 | 'PDCurses-3.9.tar.gz': '590dbe0f5835f66992df096d3602d0271103f90cf8557a5d124f693c2b40d7ec', 5 | 6 | 'Python-3.12.10.tar.xz': '07ab697474595e06f06647417d3c7fa97ded07afc1a7e4454c5639919b46eaea', 7 | 'Python-3.13.3.tar.xz': '40f868bcbdeb8149a3149580bb9bfd407b3321cd48f0be631af955ac92c0e041', 8 | 9 | 'binutils-2.41.tar.xz': 'ae9a5789e23459e59606e6714723f2d3ffc31c03174191ef0d015bdf06007450', 10 | 'binutils-2.43.1.tar.zst': 'ad1b625031099c8ac09c7864bf9d352f908510de4bd25cf50ff21022bc66f7ca', 11 | 'binutils-2.44.tar.zst': '79cb120b39a195ad588cd354aed886249bfab36c808e746b30208d15271cc95c', 12 | 13 | 'expat-2.5.0.tar.xz': 'ef2420f0232c087801abf705e89ae65f6257df6b7931d37846a193ef2e8cdcbe', 14 | 'expat-2.6.4.tar.xz': 'a695629dae047055b37d50a0ff4776d1d45d0a4c842cf4ccee158441f55ff7ee', 15 | 'expat-2.7.1.tar.xz': '354552544b8f99012e5062f7d570ec77f14b412a3ff5c7d8d0dae62c0d217c30', 16 | 17 | 'gcc-13.3.0.tar.xz': '0845e9621c9543a13f484e94584a49ffc0129970e9914624235fc1d061a0c083', 18 | 'gcc-14.2.0.tar.xz': 'a7b39bc69cbf9e25826c5a60ab26477001f7c08d85cec04bc0e29cabed6f3cc9', 19 | 'gcc-15.1.0.tar.xz': 'e2b09ec21660f01fecffb715e0120265216943f038d0e48a9868713e54f06cea', 20 | 'gcc-16-20250511.tar.xz': '4086bd9369a82d087d1bd60e2fdd926ee0401115a52542d962c085bf99f41a24', 21 | 22 | 'gdb-14.2.tar.xz': '2d4dd8061d8ded12b6c63f55e45344881e8226105f4d2a9b234040efa5ce7772', 23 | 'gdb-15.2.tar.xz': '83350ccd35b5b5a0cba6b334c41294ea968158c573940904f00b92f76345314d', 24 | 'gdb-16.3.tar.xz': 'bcfcd095528a987917acf9fff3f1672181694926cc18d609c99d0042c00224c5', 25 | 26 | 'gmp-6.3.0.tar.zst': '7f55d73f472c29cc14d7fa985f3654d48829415b649eaf61646b7b33f2a80e27', 27 | 28 | 'libiconv-1.17.tar.gz': '8f74213b56238c85a50a5329f77e06198771e70dd9a739779f4c02f65d971313', 29 | 'libiconv-1.18.tar.gz': '3b08f5f4f9b4eb82f151a7040bfd6fe6c6fb922efe4b1659c66ea933276965e8', 30 | 31 | 'make-4.4.1.tar.lz': '8814ba072182b605d156d7589c19a43b89fc58ea479b9355146160946f8cf6e9', 32 | 33 | 'mcfgthread-1.8-ga.4.tar.gz': 'd2318ef761927860b7a8963308145065047d8ad2102313b26e6eb2d88d9ef1e3', 34 | 'mcfgthread-2.1-ga.1.tar.gz': '73d4ea39e8eee30738ed3f4a35f6cc4e5c6cba62570908ee37d1fc0bf5a7d722', 35 | 36 | 'mingw-w64-v11.0.1.tar.bz2': '3f66bce069ee8bed7439a1a13da7cb91a5e67ea6170f21317ac7f5794625ee10', 37 | 'mingw-w64-v12.0.0.tar.bz2': 'cc41898aac4b6e8dd5cffd7331b9d9515b912df4420a3a612b5ea2955bbeed2f', 38 | 39 | 'mpc-1.3.1.tar.gz': 'ab642492f5cf882b74aa0cb730cd410a81edcdbec895183ce930e706c1c759b8', 40 | 41 | 'mpfr-4.2.2.tar.xz': 'b67ba0383ef7e8a8563734e2e889ef5ec3c3b898a01d00fa0a6869ad81c6ce01', 42 | 43 | 'xmake-2.9.9.tar.gz': 'e92505b83bc9776286eae719d58bcea7ff2577afe12cb5ccb279c81e7dbc702d', 44 | 45 | 'zlib-1.3.1.tar.gz': '9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23', 46 | } 47 | -------------------------------------------------------------------------------- /module/debug.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | import subprocess 3 | from typing import Optional 4 | 5 | def shell_here(path: Optional[Path] = None): 6 | if path is None: 7 | path = Path.cwd() 8 | if Path('/bin/bash').exists(): 9 | subprocess.run('/bin/bash', cwd = path) 10 | else: 11 | subprocess.run('/bin/sh', cwd = path) 12 | -------------------------------------------------------------------------------- /module/fetch.py: -------------------------------------------------------------------------------- 1 | from hashlib import sha256 2 | import logging 3 | from pathlib import Path 4 | import subprocess 5 | import time 6 | from urllib.error import URLError 7 | from urllib.request import urlopen 8 | 9 | from module.checksum import CHECKSUMS 10 | 11 | def validate_and_download(path: Path, url: str): 12 | MAX_RETRY = 5 13 | checksum = CHECKSUMS[path.name] 14 | if path.exists(): 15 | with open(path, 'rb') as f: 16 | body = f.read() 17 | if checksum != sha256(body).hexdigest(): 18 | message = 'Validate fail: %s exists but checksum mismatch' % path.name 19 | logging.critical(message) 20 | logging.info('Please delete %s and try again' % path.name) 21 | raise Exception(message) 22 | else: 23 | logging.info('Downloading %s' % path.name) 24 | retry_count = 0 25 | while True: 26 | retry_count += 1 27 | try: 28 | response = urlopen(url) 29 | body = response.read() 30 | if checksum != sha256(body).hexdigest(): 31 | message = 'Download fail: checksum mismatch for %s' % path.name 32 | logging.critical(message) 33 | raise Exception(message) 34 | with open(path, "wb") as f: 35 | f.write(body) 36 | return 37 | except URLError as e: 38 | message = f'Download fail: {e.reason} (retry {retry_count}/{MAX_RETRY})' 39 | if retry_count < MAX_RETRY: 40 | logging.warning(message) 41 | wait_time = 2 ** retry_count 42 | logging.warning(f'Retry in {wait_time} seconds...') 43 | time.sleep(wait_time) 44 | else: 45 | logging.critical(message) 46 | raise e 47 | 48 | def check_and_extract(path: Path, arx: Path): 49 | # check if already extracted 50 | if path.exists(): 51 | mark = path / '.patched' 52 | if mark.exists(): 53 | return False 54 | else: 55 | message = 'Extract fail: %s exists but not marked as fully patched' % path.name 56 | logging.critical(message) 57 | logging.info('Please delete %s and try again' % path.name) 58 | raise Exception(message) 59 | 60 | # extract 61 | res = subprocess.run([ 62 | 'bsdtar', 63 | '-xf', 64 | arx, 65 | '--no-same-owner', 66 | ], cwd = path.parent) 67 | if res.returncode != 0: 68 | message = 'Extract fail: bsdtar returned %d extracting %s' % (res.returncode, arx.name) 69 | logging.critical(message) 70 | raise Exception(message) 71 | 72 | return True 73 | 74 | def patch_done(path: Path): 75 | mark = path / '.patched' 76 | mark.touch() 77 | -------------------------------------------------------------------------------- /patch/binutils/fix-path-corruption_2.41.patch: -------------------------------------------------------------------------------- 1 | diff --git a/bfd/bfdio.c b/bfd/bfdio.c 2 | index 22c39a7b0cc..d47e4ca827b 100644 3 | --- a/bfd/bfdio.c 4 | +++ b/bfd/bfdio.c 5 | @@ -120,13 +120,8 @@ _bfd_real_fopen (const char *filename, const char *modes) 6 | /* PR 25713: Handle extra long path names possibly containing '..' and '.'. */ 7 | wchar_t ** lpFilePart = {NULL}; 8 | const wchar_t prefix[] = L"\\\\?\\"; 9 | - const size_t partPathLen = strlen (filename) + 1; 10 | #ifdef __MINGW32__ 11 | -#if !HAVE_DECL____LC_CODEPAGE_FUNC 12 | -/* This prototype was added to locale.h in version 9.0 of MinGW-w64. */ 13 | - _CRTIMP unsigned int __cdecl ___lc_codepage_func (void); 14 | -#endif 15 | - const unsigned int cp = ___lc_codepage_func (); 16 | + const unsigned int cp = CP_ACP; 17 | #else 18 | const unsigned int cp = CP_UTF8; 19 | #endif 20 | @@ -136,13 +131,14 @@ _bfd_real_fopen (const char *filename, const char *modes) 21 | 2) Convert the string: Calling with cbMultiByte set to -1 includes the terminating null. */ 22 | size_t partPathWSize = MultiByteToWideChar (cp, 0, filename, -1, NULL, 0); 23 | wchar_t * partPath = calloc (partPathWSize, sizeof(wchar_t)); 24 | + const size_t partPathLen = partPathWSize - 1; 25 | size_t ix; 26 | 27 | MultiByteToWideChar (cp, 0, filename, -1, partPath, partPathWSize); 28 | 29 | /* Convert any UNIX style path separators into the DOS i.e. backslash separator. */ 30 | for (ix = 0; ix < partPathLen; ix++) 31 | - if (IS_UNIX_DIR_SEPARATOR(filename[ix])) 32 | + if (IS_UNIX_DIR_SEPARATOR(partPath[ix])) 33 | partPath[ix] = '\\'; 34 | 35 | /* Getting the full path from the provided partial path. 36 | -------------------------------------------------------------------------------- /patch/binutils/fix-path-corruption_2.43.patch: -------------------------------------------------------------------------------- 1 | diff --git a/bfd/bfdio.c b/bfd/bfdio.c 2 | index 7063bcc1ae6..adcf4aa8519 100644 3 | --- a/bfd/bfdio.c 4 | +++ b/bfd/bfdio.c 5 | @@ -122,7 +122,6 @@ _bfd_real_fopen (const char *filename, const char *modes) 6 | const wchar_t prefixDOS[] = L"\\\\?\\"; 7 | const wchar_t prefixUNC[] = L"\\\\?\\UNC\\"; 8 | const wchar_t prefixNone[] = L""; 9 | - const size_t partPathLen = strlen (filename) + 1; 10 | const wchar_t * prefix; 11 | size_t sizeof_prefix; 12 | bool strip_network_prefix = false; 13 | @@ -189,11 +188,7 @@ _bfd_real_fopen (const char *filename, const char *modes) 14 | } 15 | 16 | #ifdef __MINGW32__ 17 | -#if !HAVE_DECL____LC_CODEPAGE_FUNC 18 | - /* This prototype was added to locale.h in version 9.0 of MinGW-w64. */ 19 | - _CRTIMP unsigned int __cdecl ___lc_codepage_func (void); 20 | -#endif 21 | - const unsigned int cp = ___lc_codepage_func (); 22 | + const unsigned int cp = CP_ACP; 23 | #else 24 | const unsigned int cp = CP_UTF8; 25 | #endif 26 | @@ -203,13 +198,14 @@ _bfd_real_fopen (const char *filename, const char *modes) 27 | 2) Convert the string: Calling with cbMultiByte set to -1 includes the terminating null. */ 28 | size_t partPathWSize = MultiByteToWideChar (cp, 0, filename, -1, NULL, 0); 29 | wchar_t * partPath = calloc (partPathWSize, sizeof(wchar_t)); 30 | + size_t partPathLen = partPathWSize - 1; 31 | size_t ix; 32 | 33 | MultiByteToWideChar (cp, 0, filename, -1, partPath, partPathWSize); 34 | 35 | /* Convert any UNIX style path separators into the DOS i.e. backslash separator. */ 36 | for (ix = 0; ix < partPathLen; ix++) 37 | - if (IS_UNIX_DIR_SEPARATOR(filename[ix])) 38 | + if (IS_UNIX_DIR_SEPARATOR(partPath[ix])) 39 | partPath[ix] = '\\'; 40 | 41 | /* Getting the full path from the provided partial path. 42 | -------------------------------------------------------------------------------- /patch/crt/fix-i386-strtoi64-strtoui64.patch: -------------------------------------------------------------------------------- 1 | diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am 2 | index 0454ecec3..f578c8c3c 100644 3 | --- a/mingw-w64-crt/Makefile.am 4 | +++ b/mingw-w64-crt/Makefile.am 5 | @@ -291,6 +291,8 @@ src_msvcrt32=\ 6 | misc/imaxabs.c \ 7 | misc/lc_locale_func.c \ 8 | misc/seterrno.c \ 9 | + misc/strtoimax.c \ 10 | + misc/strtoumax.c \ 11 | misc/wassert.c \ 12 | stdio/_scprintf.c \ 13 | stdio/_vscprintf.c 14 | diff --git a/mingw-w64-crt/lib-common/msvcrt.def.in b/mingw-w64-crt/lib-common/msvcrt.def.in 15 | index 1f8f95b17..dc216b08c 100644 16 | --- a/mingw-w64-crt/lib-common/msvcrt.def.in 17 | +++ b/mingw-w64-crt/lib-common/msvcrt.def.in 18 | @@ -1037,16 +1037,16 @@ _strset_s 19 | _strtime 20 | ; _strtime_s replaced by emu 21 | _strtod_l 22 | -_strtoi64 23 | -strtoll == _strtoi64 24 | -strtoimax == _strtoi64 25 | +F_NON_I386(_strtoi64) ; i386 _strtoi64 replaced by emu 26 | +F_NON_I386(strtoll == _strtoi64) ; i386 strtoll alias provided by emu 27 | +F_NON_I386(strtoimax == _strtoi64) ; i386 strtoimax alias provided by emu 28 | _strtoi64_l 29 | _strtoll_l == _strtoi64_l 30 | _strtoimax_l == _strtoi64_l 31 | _strtol_l 32 | -_strtoui64 33 | -strtoull == _strtoui64 34 | -strtoumax == _strtoui64 35 | +F_NON_I386(_strtoui64) ; i386 _strtoui64 replaced by emu 36 | +F_NON_I386(strtoull == _strtoui64) ; i386 strtoull alias provided by emu 37 | +F_NON_I386(strtoumax == _strtoui64) ; i386 strtoumax alias provided by emu 38 | _strtoui64_l 39 | _strtoull_l == _strtoui64_l 40 | _strtoumax_l == _strtoui64_l 41 | -------------------------------------------------------------------------------- /patch/crt/fix-x64-difftime64.patch: -------------------------------------------------------------------------------- 1 | diff --git a/mingw-w64-crt/lib-common/msvcrt.def.in b/mingw-w64-crt/lib-common/msvcrt.def.in 2 | index 1f8f95b17..546a676ba 100644 3 | --- a/mingw-w64-crt/lib-common/msvcrt.def.in 4 | +++ b/mingw-w64-crt/lib-common/msvcrt.def.in 5 | @@ -465,7 +465,7 @@ _cwscanf_s_l 6 | F_X86_ANY(_dstbias DATA) 7 | _daylight DATA 8 | _difftime32 F_I386(== difftime) 9 | -_difftime64 10 | +_difftime64 F_X64(== difftime) ; x64 _difftime64 replaced by alias 11 | _dup 12 | _dup2 13 | _ecvt 14 | -------------------------------------------------------------------------------- /patch/crt/fix-x64-wassert_11.patch: -------------------------------------------------------------------------------- 1 | diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am 2 | index 0454ecec3..363dbd963 100644 3 | --- a/mingw-w64-crt/Makefile.am 4 | +++ b/mingw-w64-crt/Makefile.am 5 | @@ -305,7 +305,8 @@ src_msvcrt64=\ 6 | misc/_create_locale.c \ 7 | misc/_free_locale.c \ 8 | misc/_get_current_locale.c \ 9 | - misc/seterrno.c 10 | + misc/seterrno.c \ 11 | + misc/wassert.c 12 | 13 | src_msvcrtarm32=\ 14 | $(src_msvcrt) \ 15 | diff --git a/mingw-w64-crt/lib-common/msvcrt.def.in b/mingw-w64-crt/lib-common/msvcrt.def.in 16 | index 1f8f95b17..f491a7938 100644 17 | --- a/mingw-w64-crt/lib-common/msvcrt.def.in 18 | +++ b/mingw-w64-crt/lib-common/msvcrt.def.in 19 | @@ -1160,7 +1160,7 @@ _waccess 20 | ; _waccess_s Replaced by emu 21 | _wasctime 22 | ; _wasctime_s Replaced by emu 23 | -F_NON_I386(_wassert) 24 | +F_ARM_ANY(_wassert) 25 | _wchdir 26 | _wchmod 27 | _wcmdln DATA 28 | -------------------------------------------------------------------------------- /patch/crt/fix-x64-wassert_12.patch: -------------------------------------------------------------------------------- 1 | diff --git a/mingw-w64-crt/Makefile.in b/mingw-w64-crt/Makefile.in 2 | index 7512bfe42..74a487b51 100644 3 | --- a/mingw-w64-crt/Makefile.in 4 | +++ b/mingw-w64-crt/Makefile.in 5 | @@ -11208,7 +11208,8 @@ src_msvcrt64 = \ 6 | misc/_create_locale.c \ 7 | misc/_free_locale.c \ 8 | misc/_get_current_locale.c \ 9 | - misc/seterrno.c 10 | + misc/seterrno.c \ 11 | + misc/wassert.c 12 | 13 | 14 | # Files included in libmsvcrt-os.a (for msvcrt.dll) on arm32 15 | diff --git a/mingw-w64-crt/lib-common/msvcrt.def.in b/mingw-w64-crt/lib-common/msvcrt.def.in 16 | index 69068ae4b..5c6039720 100644 17 | --- a/mingw-w64-crt/lib-common/msvcrt.def.in 18 | +++ b/mingw-w64-crt/lib-common/msvcrt.def.in 19 | @@ -1648,7 +1648,7 @@ _vwprintf_p_l 20 | _vwprintf_s_l 21 | ; _waccess_s replaced by emu 22 | ; _wasctime_s replaced by emu 23 | -F_NON_I386(_wassert) ; i386 _wassert replaced by emu 24 | +F_ARM_ANY(_wassert) ; i386 and x64 _wassert replaced by emu 25 | _wcscoll_l 26 | _wcsdup_dbg 27 | _wcserror_s 28 | -------------------------------------------------------------------------------- /patch/gcc/disable-vectorized-lexer_13.patch: -------------------------------------------------------------------------------- 1 | diff --git a/libcpp/lex.cc b/libcpp/lex.cc 2 | index 8951ac56ee2..0047dfd79c7 100644 3 | --- a/libcpp/lex.cc 4 | +++ b/libcpp/lex.cc 5 | @@ -24,6 +24,11 @@ along with this program; see the file COPYING3. If not see 6 | #include "cpplib.h" 7 | #include "internal.h" 8 | 9 | +#if defined(_WIN32) && !defined(_WIN64) 10 | +#define WIN32_LEAN_AND_MEAN 11 | +#include 12 | +#endif 13 | + 14 | enum spell_type 15 | { 16 | SPELL_OPERATOR = 0, 17 | @@ -501,6 +506,22 @@ static search_line_fast_type search_line_fast; 18 | static inline void 19 | init_vectorized_lexer (void) 20 | { 21 | +#if defined(_WIN32) && !defined(_WIN64) 22 | + /* Windows prior to 2000 does not enable SSE by default. If not enabled, 23 | + SSE bits are still set, but SSE instructions will trap #UD. Checking 24 | + availability is possible by invoking an SSE instruction, for example, 25 | + stmxcsr, and handling illegal instruction exception. But that's so tricky 26 | + that we simply check OS version and disable this optimization. */ 27 | + 28 | + OSVERSIONINFOA osvi = { sizeof(osvi) }; 29 | + GetVersionExA(&osvi); 30 | + if (osvi.dwMajorVersion < 5) 31 | + { 32 | + search_line_fast = search_line_acc_char; 33 | + return; 34 | + } 35 | +#endif 36 | + 37 | unsigned dummy, ecx = 0, edx = 0; 38 | search_line_fast_type impl = search_line_acc_char; 39 | int minimum = 0; 40 | -------------------------------------------------------------------------------- /patch/gcc/disable-vectorized-lexer_15.patch: -------------------------------------------------------------------------------- 1 | diff --git a/libcpp/lex.cc b/libcpp/lex.cc 2 | index e7705a64f39..15ddcc983ce 100644 3 | --- a/libcpp/lex.cc 4 | +++ b/libcpp/lex.cc 5 | @@ -24,6 +24,11 @@ along with this program; see the file COPYING3. If not see 6 | #include "cpplib.h" 7 | #include "internal.h" 8 | 9 | +#if defined(_WIN32) && !defined(_WIN64) 10 | +#define WIN32_LEAN_AND_MEAN 11 | +#include 12 | +#endif 13 | + 14 | enum spell_type 15 | { 16 | SPELL_OPERATOR = 0, 17 | @@ -408,6 +413,19 @@ static search_line_fast_type search_line_fast 18 | static inline void 19 | init_vectorized_lexer (void) 20 | { 21 | +#if defined(_WIN32) && !defined(_WIN64) 22 | + /* Windows prior to 2000 does not enable SSE by default. If not enabled, 23 | + SSE bits are still set, but SSE instructions will trap #UD. Checking 24 | + availability is possible by invoking an SSE instruction, for example, 25 | + stmxcsr, and handling illegal instruction exception. But that's so tricky 26 | + that we simply check OS version and disable this optimization. */ 27 | + 28 | + OSVERSIONINFOA osvi = { sizeof(osvi) }; 29 | + GetVersionExA(&osvi); 30 | + if (osvi.dwMajorVersion < 5) 31 | + return; 32 | +#endif 33 | + 34 | unsigned ax, bx, cx, dx; 35 | 36 | if (!__get_cpuid (1, &ax, &bx, &cx, &dx)) 37 | -------------------------------------------------------------------------------- /patch/gcc/fix-libcpp-setlocale.patch: -------------------------------------------------------------------------------- 1 | diff --git a/libcpp/system.h b/libcpp/system.h 2 | index 4e3dff8ed0e..ed95aba69f8 100644 3 | --- a/libcpp/system.h 4 | +++ b/libcpp/system.h 5 | @@ -267,10 +267,6 @@ extern int errno; 6 | # include 7 | #endif 8 | 9 | -#ifndef HAVE_SETLOCALE 10 | -# define setlocale(category, locale) (locale) 11 | -#endif 12 | - 13 | #ifdef ENABLE_NLS 14 | #include 15 | #else 16 | -------------------------------------------------------------------------------- /patch/gcc/fix-make-variable_12.patch: -------------------------------------------------------------------------------- 1 | diff --git a/config/mh-mingw b/config/mh-mingw 2 | index e91367a7112..854a500f696 100644 3 | --- a/config/mh-mingw 4 | +++ b/config/mh-mingw 5 | @@ -2,8 +2,8 @@ 6 | # Vista (see PR33281 for details). 7 | BOOT_CFLAGS += -D__USE_MINGW_ACCESS -Wno-pedantic-ms-format 8 | BOOT_CXXFLAGS += -D__USE_MINGW_ACCESS -Wno-pedantic-ms-format 9 | -CFLAGS += -D__USE_MINGW_ACCESS 10 | -CXXFLAGS += -D__USE_MINGW_ACCESS 11 | +override CFLAGS += -D__USE_MINGW_ACCESS 12 | +override CXXFLAGS += -D__USE_MINGW_ACCESS 13 | STAGE1_CXXFLAGS += -D__USE_MINGW_ACCESS 14 | STAGE2_CXXFLAGS += -D__USE_MINGW_ACCESS 15 | STAGE3_CXXFLAGS += -D__USE_MINGW_ACCESS 16 | -------------------------------------------------------------------------------- /patch/gcc/fix-make-variable_14.patch: -------------------------------------------------------------------------------- 1 | diff --git a/config/mh-mingw b/config/mh-mingw 2 | index f5fb064813f..96be2211ce6 100644 3 | --- a/config/mh-mingw 4 | +++ b/config/mh-mingw 5 | @@ -1,8 +1,8 @@ 6 | # Add -D__USE_MINGW_ACCESS to enable the built compiler to work on Windows 7 | # Vista (see PR33281 for details). 8 | BOOT_CFLAGS += -D__USE_MINGW_ACCESS -Wno-pedantic-ms-format 9 | -CFLAGS += -D__USE_MINGW_ACCESS 10 | -CXXFLAGS += -D__USE_MINGW_ACCESS 11 | +override CFLAGS += -D__USE_MINGW_ACCESS 12 | +override CXXFLAGS += -D__USE_MINGW_ACCESS 13 | STAGE1_CXXFLAGS += -D__USE_MINGW_ACCESS 14 | STAGE2_CXXFLAGS += -D__USE_MINGW_ACCESS 15 | STAGE3_CXXFLAGS += -D__USE_MINGW_ACCESS 16 | -------------------------------------------------------------------------------- /patch/gcc/fix-ucrt-pipe.patch: -------------------------------------------------------------------------------- 1 | diff --git a/gcc/main.cc b/gcc/main.cc 2 | index 5f682c2bf52..16ce61f6dee 100644 3 | --- a/gcc/main.cc 4 | +++ b/gcc/main.cc 5 | @@ -24,6 +24,11 @@ along with GCC; see the file COPYING3. If not see 6 | #include "diagnostic-core.h" 7 | #include "toplev.h" 8 | 9 | +#if defined (__MINGW32__) && defined (_UCRT) 10 | +# include 11 | +# include 12 | +#endif 13 | + 14 | int main (int argc, char **argv); 15 | 16 | /* We define main() to call toplev::main(), which is defined in toplev.cc. 17 | @@ -33,6 +38,15 @@ int main (int argc, char **argv); 18 | int 19 | main (int argc, char **argv) 20 | { 21 | +#if defined (__MINGW32__) && defined (_UCRT) 22 | + /* UCRT randomly eats linefeeds when piping on Windows Vista. Compiling 23 | + any non-trivial program compiled with '-g3 -pipe' is likely to fail. 24 | + 25 | + Anbang LI reported it also occasionally occurring on Windows 10. So 26 | + we apply the workaround without checking Windows version. */ 27 | + _setmode (_fileno (stdout), O_BINARY); 28 | +#endif 29 | + 30 | toplev toplev (NULL, /* external_timer */ 31 | true /* init_signals */); 32 | 33 | -------------------------------------------------------------------------------- /patch/gcc/fix-vt-seq.patch: -------------------------------------------------------------------------------- 1 | diff --git a/gcc/pretty-print.cc b/gcc/pretty-print.cc 2 | index 3ee206d2a42..263e1fd07ba 100644 3 | --- a/gcc/pretty-print.cc 4 | +++ b/gcc/pretty-print.cc 5 | @@ -70,6 +70,7 @@ write_all (HANDLE h, const char *s, size_t n) 6 | the third character into *head. 7 | 2. If the sequence begins with a character X in [0x80,0x9F], returns 8 | (X-0x40) and stores a pointer to the second character into *head. 9 | + * Case 2 is imcompatible with UTF-8, here we ignore it. 10 | Stores the number of ESC character(s) in *prefix_len. 11 | Returns 0 if no such sequence can be found. */ 12 | static int 13 | @@ -94,13 +95,6 @@ find_esc_head (int *prefix_len, const char **head, const char *str) 14 | *head = r + 1; 15 | return c; 16 | } 17 | - if (0x80 <= c && c <= 0x9F) 18 | - { 19 | - /* Found (case 2). */ 20 | - *prefix_len = 1; 21 | - *head = r + 1; 22 | - return c - 0x40; 23 | - } 24 | ++r; 25 | escaped = c == 0x1B; 26 | } 27 | -------------------------------------------------------------------------------- /patch/gdb/fix-iconv-cp65001.patch: -------------------------------------------------------------------------------- 1 | diff --git a/gdb/charset.c b/gdb/charset.c 2 | index 5835fd40872..21d7ad03728 100644 3 | --- a/gdb/charset.c 4 | +++ b/gdb/charset.c 5 | @@ -1029,8 +1029,11 @@ _initialize_charset (void) 6 | /* "CP" + x<=5 digits + paranoia. */ 7 | static char w32_host_default_charset[16]; 8 | 9 | - snprintf (w32_host_default_charset, sizeof w32_host_default_charset, 10 | - "CP%d", GetACP()); 11 | + if (GetACP () == CP_UTF8) 12 | + strncpy (w32_host_default_charset, "UTF-8", sizeof w32_host_default_charset); 13 | + else 14 | + snprintf (w32_host_default_charset, sizeof w32_host_default_charset, 15 | + "CP%d", GetACP()); 16 | auto_host_charset_name = w32_host_default_charset; 17 | auto_target_charset_name = auto_host_charset_name; 18 | } 19 | -------------------------------------------------------------------------------- /patch/gdb/fix-pythondir.patch: -------------------------------------------------------------------------------- 1 | diff --git a/gdb/python/python.c b/gdb/python/python.c 2 | index 8121e5d6f2a..d3eeae38c79 100644 3 | --- a/gdb/python/python.c 4 | +++ b/gdb/python/python.c 5 | @@ -2538,6 +2538,22 @@ which don't seem to make sense, indicate that it's on/enabled."), 6 | 7 | #ifdef HAVE_PYTHON 8 | 9 | +#ifdef _WIN32 10 | +#define WIN32_LEAN_AND_MEAN 11 | +#define NOMINMAX 12 | +#include 13 | +static std::string local_to_utf8(const std::string &local) 14 | +{ 15 | + int len = MultiByteToWideChar(CP_ACP, 0, local.data(), local.size(), NULL, 0); 16 | + std::wstring wide(len, 0); 17 | + MultiByteToWideChar(CP_ACP, 0, local.data(), local.size(), &wide[0], len); 18 | + len = WideCharToMultiByte(CP_UTF8, 0, wide.data(), wide.size(), NULL, 0, NULL, NULL); 19 | + std::string utf8(len, 0); 20 | + WideCharToMultiByte(CP_UTF8, 0, wide.data(), wide.size(), &utf8[0], len, NULL, NULL); 21 | + return utf8; 22 | +} 23 | +#endif 24 | + 25 | /* Helper function for gdbpy_initialize. This does the work and then 26 | returns false if an error has occurred and must be displayed, or true on 27 | success. */ 28 | @@ -2552,6 +2568,10 @@ do_initialize (const struct extension_language_defn *extlang) 29 | 30 | std::string gdb_pythondir = (std::string (gdb_datadir) + SLASH_STRING 31 | + "python"); 32 | +#ifdef _WIN32 33 | + if (GetACP() != CP_UTF8) 34 | + gdb_pythondir = local_to_utf8(gdb_pythondir); 35 | +#endif 36 | 37 | sys_path = PySys_GetObject ("path"); 38 | 39 | -------------------------------------------------------------------------------- /patch/gdb/fix-thread_14.patch: -------------------------------------------------------------------------------- 1 | diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c 2 | index 7a139c8d36f..c5ae7e50bca 100644 3 | --- a/gdb/windows-nat.c 4 | +++ b/gdb/windows-nat.c 5 | @@ -36,6 +36,7 @@ 6 | #include 7 | #include 8 | #include 9 | +#include 10 | #ifdef __CYGWIN__ 11 | #include 12 | #include 13 | @@ -1268,6 +1269,8 @@ windows_nat_target::windows_continue (DWORD continue_status, int id, 14 | if (id == -1 || id == (int) th->tid) 15 | { 16 | #ifdef __x86_64__ 17 | + if (!IsWindows7OrGreater() && !th->suspended) 18 | + continue; 19 | if (windows_process.wow64_process) 20 | { 21 | if (th->debug_registers_changed) 22 | -------------------------------------------------------------------------------- /patch/gdb/fix-thread_16.patch: -------------------------------------------------------------------------------- 1 | diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c 2 | index 2fd943ea973..8f2bdab83a4 100644 3 | --- a/gdb/windows-nat.c 4 | +++ b/gdb/windows-nat.c 5 | @@ -36,6 +36,7 @@ 6 | #include 7 | #include 8 | #include 9 | +#include 10 | #ifdef __CYGWIN__ 11 | #include 12 | #include 13 | @@ -1224,6 +1225,10 @@ windows_nat_target::windows_continue (DWORD continue_status, int id, 14 | for (auto &th : windows_process.thread_list) 15 | if (id == -1 || id == (int) th->tid) 16 | { 17 | +#ifdef __x86_64__ 18 | + if (!IsWindows7OrGreater() && !th->suspended) 19 | + continue; 20 | +#endif 21 | windows_process.with_context (th.get (), [&] (auto *context) 22 | { 23 | if (th->debug_registers_changed) 24 | -------------------------------------------------------------------------------- /patch/gdb/fix-ui-style-regex-init.patch: -------------------------------------------------------------------------------- 1 | diff --git a/gdb/ui-style.c b/gdb/ui-style.c 2 | index be4c7aca046..063e8e73119 100644 3 | --- a/gdb/ui-style.c 4 | +++ b/gdb/ui-style.c 5 | @@ -44,7 +44,8 @@ static const char ansi_regex_text[] = 6 | 7 | /* The compiled form of ansi_regex_text. */ 8 | 9 | -static regex_t ansi_regex; 10 | +static compiled_regex ansi_regex (ansi_regex_text, REG_EXTENDED, 11 | + _("Error in ANSI terminal escape sequences regex")); 12 | 13 | /* This maps bright colors to RGB triples. The index is the bright 14 | color index, starting with bright black. The values come from 15 | @@ -232,7 +233,7 @@ ui_file_style::parse (const char *buf, size_t *n_read) 16 | { 17 | regmatch_t subexps[NUM_SUBEXPRESSIONS]; 18 | 19 | - int match = regexec (&ansi_regex, buf, ARRAY_SIZE (subexps), subexps, 0); 20 | + int match = ansi_regex.exec (buf, ARRAY_SIZE (subexps), subexps, 0); 21 | if (match == REG_NOMATCH) 22 | { 23 | *n_read = 0; 24 | @@ -399,20 +400,10 @@ skip_ansi_escape (const char *buf, int *n_read) 25 | { 26 | regmatch_t subexps[NUM_SUBEXPRESSIONS]; 27 | 28 | - int match = regexec (&ansi_regex, buf, ARRAY_SIZE (subexps), subexps, 0); 29 | + int match = ansi_regex.exec (buf, ARRAY_SIZE (subexps), subexps, 0); 30 | if (match == REG_NOMATCH || buf[subexps[FINAL_SUBEXP].rm_so] != 'm') 31 | return false; 32 | 33 | *n_read = subexps[FINAL_SUBEXP].rm_eo; 34 | return true; 35 | } 36 | - 37 | -void _initialize_ui_style (); 38 | -void 39 | -_initialize_ui_style () 40 | -{ 41 | - int code = regcomp (&ansi_regex, ansi_regex_text, REG_EXTENDED); 42 | - /* If the regular expression was incorrect, it was a programming 43 | - error. */ 44 | - gdb_assert (code == 0); 45 | -} 46 | -------------------------------------------------------------------------------- /patch/python/disable-shared-xxlimited_3.12.patch: -------------------------------------------------------------------------------- 1 | diff --git a/configure b/configure 2 | index 89edc42f45c..6e4ccafbd30 100755 3 | --- a/configure 4 | +++ b/configure 5 | @@ -31254,7 +31254,7 @@ printf %s "checking for stdlib extension module xxlimited... " >&6; } 6 | if test "$py_cv_module_xxlimited" != "n/a" 7 | then : 8 | 9 | - if test "$with_trace_refs" = "no" 10 | + if test "$with_trace_refs" = "no" -a "$TEST_MODULES" = yes 11 | then : 12 | if test "$ac_cv_func_dlopen" = yes 13 | then : 14 | @@ -31292,7 +31292,7 @@ printf %s "checking for stdlib extension module xxlimited_35... " >&6; } 15 | if test "$py_cv_module_xxlimited_35" != "n/a" 16 | then : 17 | 18 | - if test "$with_trace_refs" = "no" 19 | + if test "$with_trace_refs" = "no" -a "$TEST_MODULES" = yes 20 | then : 21 | if test "$ac_cv_func_dlopen" = yes 22 | then : 23 | diff --git a/configure.ac b/configure.ac 24 | index 1a02d19f1b2..c722e212bf2 100644 25 | --- a/configure.ac 26 | +++ b/configure.ac 27 | @@ -7575,8 +7575,8 @@ PY_STDLIB_MOD([_ctypes_test], 28 | dnl Limited API template modules. 29 | dnl The limited C API is not compatible with the Py_TRACE_REFS macro. 30 | dnl Emscripten does not support shared libraries yet. 31 | -PY_STDLIB_MOD([xxlimited], [test "$with_trace_refs" = "no"], [test "$ac_cv_func_dlopen" = yes]) 32 | -PY_STDLIB_MOD([xxlimited_35], [test "$with_trace_refs" = "no"], [test "$ac_cv_func_dlopen" = yes]) 33 | +PY_STDLIB_MOD([xxlimited], [test "$with_trace_refs" = "no" -a "$TEST_MODULES" = yes], [test "$ac_cv_func_dlopen" = yes]) 34 | +PY_STDLIB_MOD([xxlimited_35], [test "$with_trace_refs" = "no" -a "$TEST_MODULES" = yes], [test "$ac_cv_func_dlopen" = yes]) 35 | 36 | # substitute multiline block, must come after last PY_STDLIB_MOD() 37 | AC_SUBST([MODULE_BLOCK]) 38 | -------------------------------------------------------------------------------- /patch/python/fix-mingw-build_3.12.patch: -------------------------------------------------------------------------------- 1 | diff --git a/Modules/_winapi.c b/Modules/_winapi.c 2 | index ac3ee113ffd..c28c01db120 100644 3 | --- a/Modules/_winapi.c 4 | +++ b/Modules/_winapi.c 5 | @@ -571,7 +571,7 @@ _winapi_CreateJunction_impl(PyObject *module, LPCWSTR src_path, 6 | tp.base.PrivilegeCount = 1; 7 | tp.base.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 8 | if (!AdjustTokenPrivileges(token, FALSE, &tp.base, sizeof(previousTp), 9 | - &previousTp.base, &previousTpSize)) { 10 | + &previousTp.base, (DWORD *)&previousTpSize)) { 11 | goto cleanup; 12 | } 13 | 14 | diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c 15 | index c21c6f06c72..a8f388706d0 100644 16 | --- a/Modules/posixmodule.c 17 | +++ b/Modules/posixmodule.c 18 | @@ -39,6 +39,7 @@ 19 | # if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) 20 | # define HAVE_SYMLINK 21 | # endif /* MS_WINDOWS_DESKTOP | MS_WINDOWS_SYSTEM */ 22 | +# include 23 | #endif 24 | 25 | #include "structmember.h" // PyMemberDef 26 | @@ -4961,7 +4962,7 @@ os__path_splitroot_impl(PyObject *module, path_t *path) 27 | } 28 | 29 | Py_BEGIN_ALLOW_THREADS 30 | - ret = PathCchSkipRoot(buffer, &end); 31 | + ret = PathCchSkipRoot(buffer, (const wchar_t **)&end); 32 | Py_END_ALLOW_THREADS 33 | if (FAILED(ret)) { 34 | result = Py_BuildValue("sO", "", path->object); 35 | diff --git a/Python/sysmodule.c b/Python/sysmodule.c 36 | index 1f7cc655c45..89eb72b1774 100644 37 | --- a/Python/sysmodule.c 38 | +++ b/Python/sysmodule.c 39 | @@ -3319,6 +3319,8 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) 40 | #ifdef MS_COREDLL 41 | SET_SYS("dllhandle", PyLong_FromVoidPtr(PyWin_DLLhModule)); 42 | SET_SYS_FROM_STRING("winver", PyWin_DLLVersionString); 43 | +#else 44 | + SET_SYS_FROM_STRING("winver", ""); 45 | #endif 46 | #ifdef ABIFLAGS 47 | SET_SYS_FROM_STRING("abiflags", ABIFLAGS); 48 | -------------------------------------------------------------------------------- /patch/python/fix-mingw-build_3.13.patch: -------------------------------------------------------------------------------- 1 | diff --git a/Include/internal/pycore_time.h b/Include/internal/pycore_time.h 2 | index 205ac5d3781..c30e07f4b4a 100644 3 | --- a/Include/internal/pycore_time.h 4 | +++ b/Include/internal/pycore_time.h 5 | @@ -58,9 +58,7 @@ extern "C" { 6 | #endif 7 | 8 | 9 | -#ifdef __clang__ 10 | struct timeval; 11 | -#endif 12 | 13 | #define _SIZEOF_PYTIME_T 8 14 | 15 | diff --git a/Modules/_winapi.c b/Modules/_winapi.c 16 | index d51586e6025..c5a1ff1c01d 100644 17 | --- a/Modules/_winapi.c 18 | +++ b/Modules/_winapi.c 19 | @@ -642,7 +642,7 @@ _winapi_CreateJunction_impl(PyObject *module, LPCWSTR src_path, 20 | tp.base.PrivilegeCount = 1; 21 | tp.base.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 22 | if (!AdjustTokenPrivileges(token, FALSE, &tp.base, sizeof(previousTp), 23 | - &previousTp.base, &previousTpSize)) { 24 | + &previousTp.base, (DWORD *)&previousTpSize)) { 25 | goto cleanup; 26 | } 27 | 28 | diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c 29 | index 40d0f86e6ae..88b1dcf3856 100644 30 | --- a/Modules/posixmodule.c 31 | +++ b/Modules/posixmodule.c 32 | @@ -43,6 +43,7 @@ 33 | # if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) 34 | # define HAVE_SYMLINK 35 | # endif /* MS_WINDOWS_DESKTOP | MS_WINDOWS_SYSTEM */ 36 | +# include 37 | #endif 38 | 39 | #ifndef MS_WINDOWS 40 | @@ -5144,7 +5145,7 @@ os__path_splitroot_impl(PyObject *module, path_t *path) 41 | } 42 | 43 | Py_BEGIN_ALLOW_THREADS 44 | - ret = PathCchSkipRoot(buffer, &end); 45 | + ret = PathCchSkipRoot(buffer, (const wchar_t **)&end); 46 | Py_END_ALLOW_THREADS 47 | if (FAILED(ret)) { 48 | result = Py_BuildValue("sO", "", path->object); 49 | diff --git a/Python/sysmodule.c b/Python/sysmodule.c 50 | index 9cf4a580d44..106661305a7 100644 51 | --- a/Python/sysmodule.c 52 | +++ b/Python/sysmodule.c 53 | @@ -3522,6 +3522,8 @@ _PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) 54 | #ifdef MS_COREDLL 55 | SET_SYS("dllhandle", PyLong_FromVoidPtr(PyWin_DLLhModule)); 56 | SET_SYS_FROM_STRING("winver", PyWin_DLLVersionString); 57 | +#else 58 | + SET_SYS_FROM_STRING("winver", ""); 59 | #endif 60 | #ifdef ABIFLAGS 61 | SET_SYS_FROM_STRING("abiflags", ABIFLAGS); 62 | -------------------------------------------------------------------------------- /patch/python/fix-thread-touch-last-error_3.12.patch: -------------------------------------------------------------------------------- 1 | diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c 2 | index c1ab5883568..9ede73b35c6 100644 3 | --- a/Python/ceval_gil.c 4 | +++ b/Python/ceval_gil.c 5 | @@ -703,11 +703,19 @@ PyEval_SaveThread(void) 6 | void 7 | PyEval_RestoreThread(PyThreadState *tstate) 8 | { 9 | +#ifdef MS_WINDOWS 10 | + int err = GetLastError(); 11 | +#endif 12 | + 13 | _Py_EnsureTstateNotNULL(tstate); 14 | 15 | take_gil(tstate); 16 | 17 | _PyThreadState_SwapNoGIL(tstate); 18 | + 19 | +#ifdef MS_WINDOWS 20 | + SetLastError(err); 21 | +#endif 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /patch/python/python-config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | prefix=$(dirname $0) 4 | 5 | while [ $# -gt 0 ]; do 6 | case $1 in 7 | --includes) 8 | echo "-I$prefix/include/python -DPy_NO_ENABLE_SHARED" 9 | shift 10 | ;; 11 | --ldflags) 12 | echo "-L$prefix/lib -lpythoncore -lbcrypt -lpathcch -lversion -lws2_32" 13 | shift 14 | ;; 15 | --exec-prefix) 16 | echo "$prefix" 17 | shift 18 | ;; 19 | *) 20 | shift 21 | ;; 22 | esac 23 | done 24 | -------------------------------------------------------------------------------- /patch/xmake/fix-module-mapper-path.patch: -------------------------------------------------------------------------------- 1 | diff --git a/xmake/rules/c++/modules/modules_support/gcc/builder.lua b/xmake/rules/c++/modules/modules_support/gcc/builder.lua 2 | index a0a43db5a..4ccc6404d 100644 3 | --- a/xmake/rules/c++/modules/modules_support/gcc/builder.lua 4 | +++ b/xmake/rules/c++/modules/modules_support/gcc/builder.lua 5 | @@ -135,7 +135,8 @@ end 6 | -- 7 | function _generate_modulemapper_file(target, module, cppfile) 8 | local maplines = _get_maplines(target, module) 9 | - local mapper_path = path.join(os.tmpdir(), target:name():replace(" ", "_"), name or cppfile:replace(" ", "_")) 10 | + local mapper_path = path.join(os.tmpdir(), (target:name():replace(" ", "_")), 11 | + name or (cppfile:replace("[%s:]", "_"))) -- @see https://github.com/xmake-io/xmake/issues/6350 12 | local mapper_content = {} 13 | table.insert(mapper_content, "root " .. path.unix(os.projectdir())) 14 | for _, mapline in ipairs(maplines) do 15 | -------------------------------------------------------------------------------- /patch/xmake/tbox-ignore-process-group.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/tbox/platform/windows/process.c b/src/tbox/platform/windows/process.c 2 | index 50188544..51c47e29 100644 3 | --- a/src/tbox/platform/windows/process.c 4 | +++ b/src/tbox/platform/windows/process.c 5 | @@ -140,6 +140,10 @@ tb_bool_t tb_process_group_init() 6 | { 7 | if (!g_process_group) 8 | { 9 | + // ignore if not supported 10 | + if (!tb_kernel32()->CreateJobObjectW) 11 | + return tb_true; 12 | + 13 | // create process job 14 | g_process_group = tb_kernel32()->CreateJobObjectW(tb_null, tb_null); 15 | tb_assert_and_check_return_val(g_process_group && g_process_group != INVALID_HANDLE_VALUE, tb_false); 16 | -------------------------------------------------------------------------------- /support/buildenv-alpine/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.io/amd64/alpine:3.20 2 | 3 | RUN apk update && \ 4 | apk add \ 5 | autoconf automake build-base flex gettext libtool meson texinfo \ 6 | 7zip ca-certificates curl file gawk libarchive-tools py3-packaging python3 zstd 7 | 8 | ENV XMAKE_ROOT=y 9 | -------------------------------------------------------------------------------- /support/buildenv-ubuntu/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.io/amd64/ubuntu:24.04 2 | 3 | RUN apt-get update && \ 4 | env DEBIAN_FRONTEND=noninteractive \ 5 | apt-get install --no-install-recommends -y \ 6 | autoconf automake build-essential flex gettext libtool meson texinfo \ 7 | 7zip ca-certificates curl file gawk libarchive-tools python3 python3-packaging zstd 8 | 9 | ENV XMAKE_ROOT=y 10 | -------------------------------------------------------------------------------- /support/intl/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | 4 | AllowShortEnumsOnASingleLine: false 5 | AllowShortFunctionsOnASingleLine: false 6 | AlwaysBreakTemplateDeclarations: Yes 7 | BinPackArguments: false 8 | BinPackParameters: false 9 | BraceWrapping: 10 | AfterClass: true 11 | AfterEnum: true 12 | AfterStruct: true 13 | AfterUnion: true 14 | AfterFunction: true 15 | AfterNamespace: true 16 | AfterExternBlock: true 17 | BreakBeforeBraces: Custom 18 | NamespaceIndentation: All 19 | -------------------------------------------------------------------------------- /support/intl/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .xmake 3 | build 4 | -------------------------------------------------------------------------------- /support/intl/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 MinGW Lite developers 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /support/intl/include/libintl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __cplusplus 4 | extern "C" 5 | { 6 | #endif 7 | 8 | char *bindtextdomain(const char *domainname, const char *dirname); 9 | char *textdomain(const char *domainname); 10 | 11 | char *gettext(const char *msgid); 12 | char *dgettext(const char *domainname, const char *msgid); 13 | char *dcgettext(const char *domainname, const char *msgid, int category); 14 | 15 | char * 16 | ngettext(const char *msgid, const char *msgid_plural, unsigned long int n); 17 | char *dngettext(const char *domainname, 18 | const char *msgid, 19 | const char *msgid_plural, 20 | unsigned long int n); 21 | char *dcngettext(const char *domainname, 22 | const char *msgid, 23 | const char *msgid_plural, 24 | unsigned long int n, 25 | int category); 26 | 27 | #ifdef __cplusplus 28 | } 29 | #endif 30 | -------------------------------------------------------------------------------- /support/intl/src/_nl_expand_alias.cc: -------------------------------------------------------------------------------- 1 | // workaround AC check for GNU libintl 2 | extern "C" const char *_nl_expand_alias(const char *) 3 | { 4 | return ""; 5 | } 6 | -------------------------------------------------------------------------------- /support/intl/src/_nl_msg_cat_cntr.cc: -------------------------------------------------------------------------------- 1 | extern "C" int _nl_msg_cat_cntr; 2 | 3 | // workaround AC check for GNU libintl 4 | int _nl_msg_cat_cntr = 0; 5 | -------------------------------------------------------------------------------- /support/intl/src/bindtextdomain.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace intl 4 | { 5 | extern "C" char *bindtextdomain(const char *domainname [[maybe_unused]], 6 | const char *dirname [[maybe_unused]]) 7 | { 8 | return nullptr; 9 | } 10 | } // namespace intl 11 | -------------------------------------------------------------------------------- /support/intl/src/dcgettext.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace intl 4 | { 5 | extern "C" char *dcgettext(const char *domainname, 6 | const char *msgid, 7 | int category [[maybe_unused]]) 8 | { 9 | return dgettext(domainname, msgid); 10 | } 11 | } // namespace intl 12 | -------------------------------------------------------------------------------- /support/intl/src/dcngettext.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace intl 4 | { 5 | extern "C" char *dcngettext(const char *domainname, 6 | const char *msgid, 7 | const char *msgid_plural, 8 | unsigned long int n, 9 | int category [[maybe_unused]]) 10 | { 11 | return dngettext(domainname, msgid, msgid_plural, n); 12 | } 13 | } // namespace intl 14 | -------------------------------------------------------------------------------- /support/intl/src/dngettext.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace intl 4 | { 5 | extern "C" char *dngettext(const char *domainname, 6 | const char *msgid, 7 | const char *msgid_plural, 8 | unsigned long int n) 9 | { 10 | return dgettext(domainname, n == 1 ? msgid : msgid_plural); 11 | } 12 | } // namespace intl 13 | -------------------------------------------------------------------------------- /support/intl/src/gettext.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace intl 4 | { 5 | extern "C" char *gettext(const char *msgid) 6 | { 7 | return dgettext(nullptr, msgid); 8 | } 9 | } // namespace intl 10 | -------------------------------------------------------------------------------- /support/intl/src/internal-state.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace intl 9 | { 10 | inline std::string default_domain; 11 | } // namespace intl 12 | -------------------------------------------------------------------------------- /support/intl/src/ngettext.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace intl 4 | { 5 | extern "C" char * 6 | ngettext(const char *msgid, const char *msgid_plural, unsigned long int n) 7 | { 8 | return dngettext(nullptr, msgid, msgid_plural, n); 9 | } 10 | } // namespace intl 11 | -------------------------------------------------------------------------------- /support/intl/src/textdomain.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "internal-state.h" 9 | 10 | namespace intl 11 | { 12 | extern "C" char *textdomain(const char *domainname) 13 | { 14 | if (!domainname) 15 | return default_domain.data(); 16 | 17 | try { 18 | default_domain = domainname; 19 | return default_domain.data(); 20 | } catch (const std::bad_alloc &) { 21 | _set_errno(ENOMEM); 22 | return nullptr; 23 | } 24 | } 25 | } // namespace intl 26 | -------------------------------------------------------------------------------- /support/intl/xmake.lua: -------------------------------------------------------------------------------- 1 | set_plat('mingw') 2 | add_rules('mode.release') 3 | set_languages('c11', 'cxx17') 4 | 5 | target('intl') 6 | set_kind('static') 7 | add_includedirs('include') 8 | set_exceptions('none') 9 | 10 | add_files('src/*.cc') 11 | 12 | add_headerfiles('include/libintl.h') 13 | -------------------------------------------------------------------------------- /support/test/.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | -------------------------------------------------------------------------------- /support/test/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .xmake 3 | build 4 | -------------------------------------------------------------------------------- /support/test/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CXX = g++ 3 | CPPFLAGS = 4 | CFLAGS = -std=c99 -O0 -g3 5 | CXXFLAGS = -std=c++11 -O0 -g3 6 | LDFLAGS = 7 | LIBS = 8 | 9 | $(DIR)/breakpoint$(SUFFIX): $(DIR)/breakpoint.o 10 | $(CXX) $(LDFLAGS) $^ $(LIBS) -o $@ 11 | 12 | $(DIR)/breakpoint.o: debug/breakpoint.cc 13 | $(CC) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@ 14 | 15 | clean: 16 | -del $(DIR)/breakpoint$(SUFFIX) $(DIR)/breakpoint.o 17 | -------------------------------------------------------------------------------- /support/test/c++11/thread.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | std::atomic g; 9 | thread_local int64_t l; 10 | 11 | struct accumulator { 12 | void operator()() { 13 | for (int i = 0; i < 1000000; ++i) { 14 | l++; 15 | g++; 16 | } 17 | printf("l = %" PRId64 "\n", l); 18 | } 19 | }; 20 | 21 | int main() { 22 | std::vector accumulators; 23 | for (int i = 0; i < 10; ++i) 24 | accumulators.emplace_back(accumulator{}); 25 | 26 | for (auto &t : accumulators) 27 | t.join(); 28 | printf("g = %" PRId64 "\n", g.load()); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /support/test/c++17/fstream.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace fs = std::filesystem; 6 | 7 | int main() { 8 | static std::string_view content = "Hello, world!\n"; 9 | 10 | const fs::path::value_type *name = 11 | #ifdef _WIN32 12 | L"" 13 | #endif 14 | "test__fstream_filesystem_path_value_type__‘name’.txt"; 15 | 16 | { 17 | std::fstream ofs(name, std::ios::out); 18 | ofs << content; 19 | } 20 | 21 | { 22 | std::fstream ifs(fs::path(name), std::ios::in); 23 | std::string line; 24 | while (std::getline(ifs, line)) { 25 | std::cout << line << '\n'; 26 | } 27 | } 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /support/test/c++23/import-std.cc: -------------------------------------------------------------------------------- 1 | import std; 2 | 3 | int main() { 4 | std::println("Hello, {0}!", "world"); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /support/test/c++23/print.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | std::println("Hello, {0}!", "world"); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /support/test/c++98/hello.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | std::cout << "Hello, world!" << std::endl; 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /support/test/c23/embed.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const char message[] = { 4 | #embed "message.txt" 5 | , 6 | '\0', 7 | }; 8 | 9 | int main() { 10 | printf("%s", message); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /support/test/c23/message.txt: -------------------------------------------------------------------------------- 1 | Hello, world! 2 | -------------------------------------------------------------------------------- /support/test/c89/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | printf("Hello, world!\n"); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /support/test/chimaera.lua: -------------------------------------------------------------------------------- 1 | function chimaera() 2 | end 3 | -------------------------------------------------------------------------------- /support/test/debug/breakpoint.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | enum { 5 | MAX = 5, 6 | }; 7 | 8 | int main(void) { 9 | constexpr int MAX = 5; 10 | int fib[MAX + 1] = {0, 1}; 11 | 12 | for (int i = 2; i <= MAX; i++) { 13 | fib[i] = fib[i - 1] + fib[i - 2]; 14 | printf("%d\n", fib[i]); 15 | } 16 | 17 | std::vector fib_vec(fib, fib + MAX + 1); 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /support/test/enable_if.lua: -------------------------------------------------------------------------------- 1 | function enable_if_c_macro(macro, opt) 2 | local optname = "__enable_if_c_macro_" .. macro 3 | interp_save_scope() 4 | option(optname) 5 | set_showmenu(false) 6 | local snippet = ([[ 7 | #if defined(%s) 8 | #else 9 | #error %s is not satisfied! 10 | #endif 11 | ]]):format(macro, macro) 12 | add_csnippets(macro, snippet) 13 | if opt.languages then 14 | set_languages(opt.languages) 15 | end 16 | if opt.cflags then 17 | add_cflags(opt.cflags) 18 | end 19 | if opt.cxflags then 20 | add_cxxflags(opt.cxflags) 21 | end 22 | option_end() 23 | interp_restore_scope() 24 | set_enabled(get_config(optname)) 25 | end 26 | 27 | function enable_if_cxx_feature(macro, minvalue, opt) 28 | local optname = "__enable_if_cxx_feature_" .. macro .. "_" .. minvalue 29 | interp_save_scope() 30 | option(optname) 31 | set_showmenu(false) 32 | local snippet = ([[ 33 | #include 34 | #if %s >= %d 35 | #else 36 | #error %s >= %d is not satisfied! 37 | #endif 38 | ]]):format(macro, minvalue, macro, minvalue) 39 | add_cxxsnippets(macro, snippet) 40 | if opt.languages then 41 | set_languages(opt.languages) 42 | end 43 | if opt.cxflags then 44 | add_cflags(opt.cxflags) 45 | end 46 | if opt.cxxflags then 47 | add_cxxflags(opt.cxxflags) 48 | end 49 | option_end() 50 | interp_restore_scope() 51 | set_enabled(get_config(optname)) 52 | end 53 | 54 | function enable_if_cxx_header(header) 55 | local optname = "__enable_if_cxx_header_" .. header 56 | interp_save_scope() 57 | option(optname) 58 | set_showmenu(false) 59 | add_cxxincludes(header) 60 | option_end() 61 | interp_restore_scope() 62 | set_enabled(get_config(optname)) 63 | end 64 | -------------------------------------------------------------------------------- /support/test/gnu++98/bits-stdc++.cc: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int main() { 5 | cout << "Hello, world!" << endl; 6 | return 0; 7 | } 8 | -------------------------------------------------------------------------------- /support/test/xmake.lua: -------------------------------------------------------------------------------- 1 | add_rules("mode.debug", "mode.release") 2 | set_policy("build.c++.gcc.modules.cxx11abi", true) 3 | 4 | includes("chimaera.lua") 5 | includes("enable_if.lua") 6 | 7 | target("c89/hello") 8 | add_files("c89/hello.c") 9 | add_tests("default", {pass_outputs = "Hello, world!\n"}) 10 | chimaera() 11 | 12 | target("c23/embed") 13 | enable_if_c_macro("__has_embed", {languages = "c23"}) 14 | set_languages("c23") 15 | add_files("c23/embed.c") 16 | add_tests("default", {pass_outputs = "Hello, world!\n"}) 17 | chimaera() 18 | 19 | target("c++98/hello") 20 | add_files("c++98/hello.cc") 21 | add_tests("default", {pass_outputs = "Hello, world!\n"}) 22 | chimaera() 23 | 24 | target("gnu++98/bits-stdc++") 25 | add_files("gnu++98/bits-stdc++.cc") 26 | add_tests("default", {pass_outputs = "Hello, world!\n"}) 27 | chimaera() 28 | 29 | target("c++11/thread") 30 | set_languages("c++11") 31 | add_files("c++11/thread.cc") 32 | add_tests("default", { 33 | pass_outputs = 34 | "l = 1000000\n" .. 35 | "l = 1000000\n" .. 36 | "l = 1000000\n" .. 37 | "l = 1000000\n" .. 38 | "l = 1000000\n" .. 39 | "l = 1000000\n" .. 40 | "l = 1000000\n" .. 41 | "l = 1000000\n" .. 42 | "l = 1000000\n" .. 43 | "l = 1000000\n" .. 44 | "g = 10000000\n"}) 45 | chimaera() 46 | 47 | target("c++17/filesystem") 48 | enable_if_cxx_header("filesystem") 49 | set_languages("c++17") 50 | add_files("c++17/filesystem.cc") 51 | add_tests("default", { 52 | pass_outputs = 53 | "test__filesystem__‘dir_copy’\n" .. 54 | "test__filesystem__‘dir_copy’/‘file_copy’.txt\n" .. 55 | "test__filesystem__‘dir_copy’/‘file’.txt\n" .. 56 | "test__filesystem__‘dir’\n" .. 57 | "test__filesystem__‘dir’/‘file_copy’.txt\n" .. 58 | "test__filesystem__‘dir’/‘file’.txt\n"}) 59 | chimaera() 60 | 61 | target("c++17/fstream") 62 | enable_if_cxx_header("filesystem") 63 | set_languages("c++17") 64 | add_files("c++17/fstream.cc") 65 | add_tests("default", {pass_outputs = "Hello, world!\n"}) 66 | chimaera() 67 | 68 | target("c++23/print") 69 | enable_if_cxx_header("print") 70 | set_languages("c++23") 71 | add_files("c++23/print.cc") 72 | add_tests("default", {pass_outputs = "Hello, world!\n"}) 73 | chimaera() 74 | 75 | target("c++23/import-std") 76 | enable_if_cxx_feature("__cpp_lib_modules", 202207, {languages = "c++23", cxxflags = {"-fmodules"}}) 77 | set_languages("c++23") 78 | set_policy("build.c++.modules", true) 79 | add_files("c++23/import-std.cc") 80 | add_tests("default", {pass_outputs = "Hello, world!\n"}) 81 | chimaera() 82 | -------------------------------------------------------------------------------- /support/thunk/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | 4 | AllowShortEnumsOnASingleLine: false 5 | AllowShortFunctionsOnASingleLine: false 6 | AlwaysBreakTemplateDeclarations: Yes 7 | BinPackArguments: false 8 | BinPackParameters: false 9 | BraceWrapping: 10 | AfterClass: true 11 | AfterEnum: true 12 | AfterStruct: true 13 | AfterUnion: true 14 | AfterFunction: true 15 | AfterNamespace: true 16 | AfterExternBlock: true 17 | BreakBeforeBraces: Custom 18 | NamespaceIndentation: All 19 | -------------------------------------------------------------------------------- /support/thunk/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .xmake 3 | __pycache__ 4 | build 5 | -------------------------------------------------------------------------------- /support/thunk/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Chuyu-Team 4 | Copyright (c) 2025 MinGW Lite developers 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/addrinfo.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk::internal 7 | { 8 | inline addrinfo *addrinfo_from_hostent(const hostent *host, 9 | int flags, 10 | int socktype, 11 | int protocol, 12 | int port, 13 | int &wsa_error) 14 | { 15 | wsa_error = 0; 16 | 17 | int n_addr = 0; 18 | while (host->h_addr_list[n_addr] != nullptr) 19 | n_addr++; 20 | 21 | addrinfo *head = nullptr; 22 | addrinfo *next = nullptr; 23 | for (int i = n_addr - 1; i >= 0; i--) { 24 | head = (addrinfo *)internal::malloc(sizeof(addrinfo)); 25 | if (!head) { 26 | freeaddrinfo(next); 27 | wsa_error = WSA_NOT_ENOUGH_MEMORY; 28 | return nullptr; 29 | } 30 | head->ai_flags = flags; 31 | head->ai_family = AF_INET; 32 | head->ai_socktype = socktype; 33 | head->ai_protocol = protocol; 34 | head->ai_canonname = nullptr; 35 | head->ai_addrlen = sizeof(sockaddr_in); 36 | sockaddr_in *addr = (sockaddr_in *)internal::malloc(sizeof(sockaddr_in)); 37 | if (!addr) { 38 | internal::free(head); 39 | freeaddrinfo(next); 40 | wsa_error = WSA_NOT_ENOUGH_MEMORY; 41 | return nullptr; 42 | } 43 | addr->sin_family = AF_INET; 44 | addr->sin_port = htons(port); 45 | addr->sin_addr = *(in_addr *)host->h_addr_list[i]; 46 | memset(addr->sin_zero, 0, sizeof(addr->sin_zero)); 47 | head->ai_addr = (sockaddr *)addr; 48 | head->ai_next = next; 49 | next = head; 50 | } 51 | return head; 52 | } 53 | } // namespace mingw_thunk::internal 54 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/ddk/ntifs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | NTSYSCALLAPI 6 | NTSTATUS 7 | NTAPI 8 | NtQueryDirectoryFile(IN HANDLE FileHandle, 9 | IN HANDLE Event OPTIONAL, 10 | IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, 11 | IN PVOID ApcContext OPTIONAL, 12 | OUT PIO_STATUS_BLOCK IoStatusBlock, 13 | OUT PVOID FileInformation, 14 | IN ULONG Length, 15 | IN FILE_INFORMATION_CLASS FileInformationClass, 16 | IN BOOLEAN ReturnSingleEntry, 17 | IN PUNICODE_STRING FileName OPTIONAL, 18 | IN BOOLEAN RestartScan); 19 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/ddk/wdm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | namespace 8 | { 9 | constexpr FILE_INFORMATION_CLASS FileIoPriorityHintInformation = 10 | FILE_INFORMATION_CLASS(43); 11 | constexpr FILE_INFORMATION_CLASS FileRemoteProtocolInformation = 12 | FILE_INFORMATION_CLASS(55); 13 | } // namespace 14 | } // namespace mingw_thunk 15 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/findvolumedata.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace mingw_thunk::internal 6 | { 7 | struct find_volume_data 8 | { 9 | DWORD volumes; 10 | DWORD current; 11 | }; 12 | } // namespace mingw_thunk::internal 13 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/libc/ctype.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace mingw_thunk::internal 4 | { 5 | inline int isalpha(int c) 6 | { 7 | return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); 8 | } 9 | } // namespace mingw_thunk::internal 10 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/libc/rand.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace mingw_thunk::internal 9 | { 10 | inline uint64_t c_rand_seed = GetTickCount64(); 11 | 12 | inline uint32_t rand32() 13 | { 14 | uint64_t &seed = internal::c_rand_seed; 15 | seed = 6364136223846793005ULL * seed + 1; // musl's choice 16 | return seed >> 32; 17 | } 18 | 19 | inline int rand() 20 | { 21 | return internal::rand32() >> 1; 22 | } 23 | 24 | inline void srand(unsigned s) 25 | { 26 | internal::c_rand_seed = s - 1; // musl's choice 27 | } 28 | } // namespace mingw_thunk::internal 29 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/libc/stdlib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef NOMINMAX 4 | #define NOMINMAX 1 5 | #endif 6 | #ifndef WIN32_LEAN_AND_MEAN 7 | #define WIN32_LEAN_AND_MEAN 8 | #endif 9 | #include 10 | 11 | namespace mingw_thunk::internal 12 | { 13 | inline int atoi(const char *nptr) 14 | { 15 | int result = 0; 16 | while (*nptr >= '0' && *nptr <= '9') { 17 | result = result * 10 + (*nptr - '0'); 18 | nptr++; 19 | } 20 | return result; 21 | } 22 | 23 | template 24 | void free(T *ptr) noexcept 25 | { 26 | if (ptr) 27 | HeapFree(GetProcessHeap(), 0, ptr); 28 | } 29 | 30 | template 31 | T *malloc(size_t size) noexcept 32 | { 33 | return reinterpret_cast(HeapAlloc(GetProcessHeap(), 0, size)); 34 | } 35 | 36 | template 37 | T *realloc(T *ptr, size_t size) noexcept 38 | { 39 | return reinterpret_cast(HeapReAlloc(GetProcessHeap(), 0, ptr, size)); 40 | } 41 | } // namespace mingw_thunk::internal 42 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/libc/string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace mingw_thunk::internal 6 | { 7 | inline char *strchr(const char *str, int c) noexcept 8 | { 9 | while (*str) { 10 | if (*str == c) { 11 | return const_cast(str); 12 | } 13 | ++str; 14 | } 15 | return nullptr; 16 | } 17 | 18 | inline void *strcpy(char *dst, const char *src) noexcept 19 | { 20 | char *cur = dst; 21 | while (*src) { 22 | *cur++ = *src++; 23 | } 24 | *cur = 0; 25 | return dst; 26 | } 27 | 28 | inline char *stpncpy(char *dst, const char *src, size_t dsize) noexcept 29 | { 30 | char *dend = dst + dsize; 31 | while (dst < dend && *src) 32 | *dst++ = *src++; 33 | char *ret = dst; 34 | while (dst < dend) 35 | *dst++ = 0; 36 | return ret; 37 | } 38 | 39 | inline void *memcpy(void *dest, const void *src, size_t size) noexcept 40 | { 41 | char *dest_char = static_cast(dest); 42 | const char *src_char = static_cast(src); 43 | while (size) { 44 | --size; 45 | *dest_char++ = *src_char++; 46 | } 47 | return dest; 48 | } 49 | } // namespace mingw_thunk::internal 50 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/libc/wchar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace mingw_thunk::internal 6 | { 7 | inline size_t wcslen(const wchar_t *str) noexcept 8 | { 9 | size_t len = 0; 10 | while (*str++) 11 | ++len; 12 | return len; 13 | } 14 | 15 | inline size_t wcsnlen(const wchar_t *str, size_t maxlen) noexcept 16 | { 17 | size_t len = 0; 18 | while (len < maxlen && *str++) 19 | ++len; 20 | return len; 21 | } 22 | 23 | inline wchar_t * 24 | wcspncpy(wchar_t *dst, const wchar_t *src, size_t dsize) noexcept 25 | { 26 | wchar_t *dend = dst + dsize; 27 | while (dst < dend && *src) 28 | *dst++ = *src++; 29 | wchar_t *ret = dst; 30 | while (dst < dend) 31 | *dst++ = 0; 32 | return ret; 33 | } 34 | 35 | inline wchar_t *wcschr(const wchar_t *wcs, wchar_t wc) noexcept 36 | { 37 | while (*wcs) { 38 | if (*wcs == wc) 39 | return const_cast(wcs); 40 | ++wcs; 41 | } 42 | return nullptr; 43 | } 44 | } // namespace mingw_thunk::internal 45 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/misc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define _In_NLS_string_(s) 4 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/os.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace mingw_thunk::internal 8 | { 9 | inline const OSVERSIONINFOA &os_version() noexcept 10 | { 11 | static OSVERSIONINFOA osvi = {sizeof(OSVERSIONINFOA)}; 12 | if (!osvi.dwMajorVersion) 13 | GetVersionExA(&osvi); 14 | return osvi; 15 | } 16 | 17 | #ifdef ENABLE_TEST_OVERRIDE 18 | 19 | inline bool is_nt() noexcept 20 | { 21 | touched = true; 22 | return false; 23 | } 24 | 25 | #else 26 | 27 | inline bool is_nt() noexcept 28 | { 29 | return os_version().dwPlatformId >= VER_PLATFORM_WIN32_NT; 30 | } 31 | 32 | #endif 33 | 34 | inline bool os_lt(int major, int minor) noexcept 35 | { 36 | auto osvi = os_version(); 37 | if (!is_nt()) 38 | return true; 39 | return osvi.dwMajorVersion < major || 40 | (osvi.dwMajorVersion == major && osvi.dwMinorVersion < minor); 41 | } 42 | 43 | inline bool os_geq(int major, int minor) noexcept 44 | { 45 | return !os_lt(major, minor); 46 | } 47 | } // namespace mingw_thunk::internal 48 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/stl/algorithm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace mingw_thunk::internal 4 | { 5 | template 6 | constexpr const T &min(const T &a, const T &b) noexcept 7 | { 8 | return b < a ? b : a; 9 | } 10 | 11 | template 12 | constexpr const T &max(const T &a, const T &b) noexcept 13 | { 14 | return a < b ? b : a; 15 | } 16 | 17 | template 18 | RandomAccessIt lower_bound(RandomAccessIt first, 19 | RandomAccessIt last, 20 | const T &value, 21 | Compare comp) 22 | { 23 | auto len = last - first; 24 | while (len != 0) { 25 | auto l2 = len / 2; 26 | auto m = first + l2; 27 | if (comp(*m, value)) { 28 | first = ++m; 29 | len -= l2 + 1; 30 | } else { 31 | len = l2; 32 | } 33 | } 34 | return first; 35 | } 36 | } // namespace mingw_thunk::internal 37 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/stl/iterator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace mingw_thunk::internal 6 | { 7 | template 8 | constexpr T *begin(T (&array)[N]) noexcept 9 | { 10 | return array; 11 | } 12 | 13 | template 14 | constexpr const T *cbegin(const T (&array)[N]) noexcept 15 | { 16 | return array; 17 | } 18 | 19 | template 20 | constexpr const T *cend(const T (&array)[N]) noexcept 21 | { 22 | return array + N; 23 | } 24 | 25 | template 26 | constexpr T *end(T (&array)[N]) noexcept 27 | { 28 | return array + N; 29 | } 30 | 31 | template 32 | constexpr size_t size(const T (&)[N]) noexcept 33 | { 34 | return N; 35 | } 36 | } // namespace mingw_thunk::internal 37 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/stl/mutex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | struct mutex 8 | { 9 | using native_handle_type = CRITICAL_SECTION; 10 | 11 | mutex() 12 | { 13 | InitializeCriticalSection(&cs); 14 | } 15 | 16 | mutex(const mutex &) = delete; 17 | 18 | ~mutex() 19 | { 20 | DeleteCriticalSection(&cs); 21 | } 22 | 23 | void lock() 24 | { 25 | EnterCriticalSection(&cs); 26 | } 27 | 28 | void try_lock() 29 | { 30 | TryEnterCriticalSection(&cs); 31 | } 32 | 33 | void unlock() 34 | { 35 | LeaveCriticalSection(&cs); 36 | } 37 | 38 | private: 39 | CRITICAL_SECTION cs; 40 | }; 41 | } // namespace mingw_thunk 42 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace mingw_thunk::internal 9 | { 10 | inline wstring widen(const char *str, size_t length) 11 | { 12 | if (length == 0) 13 | return {}; 14 | int requiredLength = 15 | MultiByteToWideChar(CP_ACP, 0, str, length, nullptr, 0); 16 | wstring result(requiredLength, 0); 17 | if (!result.valid()) 18 | return result; 19 | MultiByteToWideChar(CP_ACP, 0, str, length, result.data(), requiredLength); 20 | return result; 21 | } 22 | 23 | inline wstring widen(const char *str) noexcept 24 | { 25 | size_t length = _strlen(str); 26 | return widen(str, length); 27 | } 28 | 29 | inline string narrow(const wchar_t *str, size_t length) 30 | { 31 | if (length == 0) 32 | return {}; 33 | int requiredLength = WideCharToMultiByte( 34 | CP_ACP, 0, str, length, nullptr, 0, nullptr, nullptr); 35 | string result(requiredLength, 0); 36 | if (!result.valid()) 37 | return result; 38 | WideCharToMultiByte(CP_ACP, 39 | 0, 40 | str, 41 | length, 42 | result.data(), 43 | requiredLength, 44 | nullptr, 45 | nullptr); 46 | return result; 47 | } 48 | 49 | inline string narrow(const wchar_t *str) noexcept 50 | { 51 | size_t length = _strlen(str); 52 | return narrow(str, length); 53 | } 54 | } // namespace mingw_thunk::internal 55 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/test.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef ENABLE_TEST_OVERRIDE 4 | 5 | #include 6 | 7 | namespace mingw_thunk::internal 8 | { 9 | inline bool touched; 10 | } 11 | 12 | #define CLEAR_TOUCH_FLAG() mingw_thunk::internal::touched = false 13 | 14 | #define REQUIRE_TOUCHED() REQUIRE(mingw_thunk::internal::touched) 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/try_get.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace mingw_thunk 12 | { 13 | #define __DECLARE_NON_THUNK_TRY_GET_FUNCTION(module, name) \ 14 | inline auto *try_get_##name() noexcept \ 15 | { \ 16 | static auto *pfn = \ 17 | internal::module_##module.get_function(#name); \ 18 | return pfn; \ 19 | } 20 | 21 | namespace 22 | { 23 | __DECLARE_NON_THUNK_TRY_GET_FUNCTION(advapi32, SystemFunction036) 24 | 25 | __DECLARE_NON_THUNK_TRY_GET_FUNCTION(ntdll, NtQueryDirectoryFile) 26 | __DECLARE_NON_THUNK_TRY_GET_FUNCTION(ntdll, NtQueryInformationFile) 27 | __DECLARE_NON_THUNK_TRY_GET_FUNCTION(ntdll, NtQueryObject) 28 | __DECLARE_NON_THUNK_TRY_GET_FUNCTION(ntdll, NtSetInformationFile) 29 | __DECLARE_NON_THUNK_TRY_GET_FUNCTION(ntdll, RtlDosPathNameToNtPathName_U) 30 | __DECLARE_NON_THUNK_TRY_GET_FUNCTION(ntdll, RtlFreeUnicodeString) 31 | __DECLARE_NON_THUNK_TRY_GET_FUNCTION(ntdll, RtlNtStatusToDosError) 32 | __DECLARE_NON_THUNK_TRY_GET_FUNCTION(ntdll, RtlPcToFileHeader) 33 | } // namespace 34 | 35 | #undef __DECLARE_NON_THUNK_TRY_GET_FUNCTION 36 | 37 | } // namespace mingw_thunk 38 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/yy/api-ms-win-core-processtopology-obsolete.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // YY-Thunk 1.1.6 6 | namespace mingw_thunk 7 | { 8 | namespace Downlevel 9 | { 10 | // 我们Windows 7以后才引入了组的概念,因此我们可以统一的假定 11 | // 只有一组,并且不支持CPU热插拔。 12 | static DWORD WINAPI GetProcessorCount(_In_ WORD GroupNumber) 13 | { 14 | if (GroupNumber == 0 || GroupNumber == ALL_PROCESSOR_GROUPS) { 15 | SYSTEM_INFO SystemInfo; 16 | GetSystemInfo(&SystemInfo); 17 | 18 | return SystemInfo.dwNumberOfProcessors; 19 | } 20 | 21 | SetLastError(ERROR_INVALID_PARAMETER); 22 | 23 | return 0; 24 | } 25 | } // namespace Downlevel 26 | } // namespace mingw_thunk 27 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/yy/memory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace std 6 | { 7 | struct nothrow_t; 8 | } 9 | 10 | namespace mingw_thunk::internal 11 | { 12 | template 13 | T *New(Args &&...args) noexcept 14 | { 15 | T *ptr = static_cast(malloc(sizeof(T))); 16 | if (ptr) 17 | new (ptr) T(static_cast(args)...); 18 | return ptr; 19 | } 20 | 21 | template 22 | void Delete(T *ptr) noexcept 23 | { 24 | if (ptr) { 25 | ptr->~T(); 26 | free(ptr); 27 | } 28 | } 29 | 30 | struct CppAlloc 31 | { 32 | void *operator new(size_t count) noexcept { return malloc(count); } 33 | void *operator new[](size_t count) noexcept { return malloc(count); } 34 | void operator delete(void *ptr) noexcept { free(ptr); } 35 | void operator delete[](void *ptr) noexcept { free(ptr); } 36 | 37 | void *operator new(size_t count, const std::nothrow_t &) noexcept 38 | { 39 | return malloc(count); 40 | } 41 | void *operator new[](size_t count, const std::nothrow_t &) noexcept 42 | { 43 | return malloc(count); 44 | } 45 | void operator delete(void *ptr, const std::nothrow_t &) noexcept 46 | { 47 | free(ptr); 48 | } 49 | void operator delete[](void *ptr, const std::nothrow_t &) noexcept 50 | { 51 | free(ptr); 52 | } 53 | 54 | void *operator new(size_t count, void *ptr) noexcept { return ptr; } 55 | void *operator new[](size_t count, void *ptr) noexcept { return ptr; } 56 | void operator delete(void *ptr, void *) noexcept {} 57 | void operator delete[](void *ptr, void *) noexcept {} 58 | }; 59 | } // namespace mingw_thunk::internal 60 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/yy/strsafe.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // workaround mingw-w64 11.0.1 4 | #define STRSAFE_NO_DEPRECATE 5 | 6 | #include 7 | #include 8 | 9 | // libmingwex provides non-inline version of strsafe functions, which will 10 | // cause link error if we use (by default, inline version of) them. Here we 11 | // have to provide our version. 12 | 13 | namespace mingw_thunk::internal 14 | { 15 | inline HRESULT WINAPI StringCchLengthW(_In_ LPCWSTR psz, 16 | _In_ size_t cchMax, 17 | _Out_ size_t *pcchLength) noexcept 18 | { 19 | *pcchLength = internal::wcsnlen(psz, cchMax); 20 | return S_OK; 21 | } 22 | 23 | inline HRESULT WINAPI StringCchCopyW(_Out_ LPWSTR pszDest, 24 | _In_ size_t cchDest, 25 | _In_ LPCWSTR pszSrc) 26 | { 27 | wchar_t *end = internal::wcspncpy(pszDest, pszSrc, cchDest - 1); 28 | *end = 0; 29 | return (end - pszDest < cchDest - 1) ? S_OK : STRSAFE_E_INSUFFICIENT_BUFFER; 30 | } 31 | } // namespace mingw_thunk::internal 32 | -------------------------------------------------------------------------------- /support/thunk/include/thunk/yy/yy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define _In_NLS_string_(s) 6 | 7 | #define __WarningMessage__(...) 8 | 9 | #define MAXIMUM_FILENAME_LENGTH 256 10 | 11 | namespace mingw_thunk::internal 12 | { 13 | inline int __ascii_towlower(int c) noexcept 14 | { 15 | if (c >= 'A' && c <= 'Z') 16 | return c + ('a' - 'A'); 17 | else 18 | return c; 19 | } 20 | } // namespace mingw_thunk::internal 21 | 22 | // YY-Thunks 1.1.6 23 | namespace mingw_thunk::internal 24 | { 25 | // Implements wcsncpmp for ASCII chars only. 26 | // NOTE: We can't use wcsncmp in this context because we may end up trying to 27 | // modify locale data structs or even calling the same function in NLS code. 28 | template 29 | static int __fastcall StringCompareIgnoreCaseByAscii(const Char1 *string1, 30 | const Char2 *string2, 31 | size_t count) noexcept 32 | { 33 | wchar_t f, l; 34 | int result = 0; 35 | 36 | if (count) { 37 | /* validation section */ 38 | do { 39 | f = __ascii_towlower(*string1); 40 | l = __ascii_towlower(*string2); 41 | string1++; 42 | string2++; 43 | } while ((--count) && f && (f == l)); 44 | 45 | result = (int)(f - l); 46 | } 47 | 48 | return result; 49 | } 50 | 51 | static DWORD __fastcall NtStatusToDosError(_In_ NTSTATUS Status) 52 | { 53 | if (STATUS_TIMEOUT == Status) { 54 | /* 55 | https://github.com/Chuyu-Team/YY-Thunks/issues/10 56 | 57 | 用户报告,Windows XP 无法转换 58 | STATUS_TIMEOUT。实际结果也是rubin,因此,特殊处理一下。 59 | */ 60 | return ERROR_TIMEOUT; 61 | } 62 | 63 | #if !defined(__USING_NTDLL_LIB) 64 | const auto RtlNtStatusToDosError = try_get_RtlNtStatusToDosError(); 65 | if (!RtlNtStatusToDosError) { 66 | // 如果没有RtlNtStatusToDosError就直接设置Status代码吧,反正至少比没有错误代码强 67 | return Status; 68 | } 69 | #endif 70 | return RtlNtStatusToDosError(Status); 71 | } 72 | 73 | static DWORD __fastcall BaseSetLastNTError(_In_ NTSTATUS Status) 74 | { 75 | auto lStatus = NtStatusToDosError(Status); 76 | SetLastError(lStatus); 77 | return lStatus; 78 | } 79 | 80 | } // namespace mingw_thunk::internal 81 | -------------------------------------------------------------------------------- /support/thunk/module/thunk_list_core.py: -------------------------------------------------------------------------------- 1 | THUNK_LIST_CORE = { 2 | '5.0': { 3 | 'kernel32': [ 4 | 'CreateHardLinkW', 5 | 'FindFirstVolumeW', 6 | 'FindNextVolumeW', 7 | 'FindVolumeClose', 8 | 'GetFileSizeEx', 9 | ], 10 | 'msvcrt': [ 11 | ('_fstat64', lambda v_major: v_major < 13), 12 | ('_wstat64', lambda v_major: v_major < 13), 13 | ] 14 | }, 15 | '5.1': { 16 | 'kernel32': [ 17 | # winpthreads: no longer required since 12 18 | ('AddVectoredExceptionHandler', lambda v_major: v_major < 12), 19 | ('RemoveVectoredExceptionHandler', lambda v_major: v_major < 12), 20 | ], 21 | }, 22 | '5.2': {}, 23 | '6.0': {}, 24 | } 25 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/advapi32/ConvertStringSecurityDescriptorToSecurityDescriptorW.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_THUNK(kernel32, 9 | 16, 10 | BOOL, 11 | WINAPI, 12 | ConvertStringSecurityDescriptorToSecurityDescriptorW, 13 | _In_ LPCWSTR StringSecurityDescriptor, 14 | _In_ DWORD StringSDRevision, 15 | _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor, 16 | _Out_ PULONG SecurityDescriptorSize) 17 | { 18 | if (const auto pfn = 19 | try_get_ConvertStringSecurityDescriptorToSecurityDescriptorW()) 20 | return pfn(StringSecurityDescriptor, 21 | StringSDRevision, 22 | SecurityDescriptor, 23 | SecurityDescriptorSize); 24 | 25 | *SecurityDescriptor = nullptr; 26 | *SecurityDescriptorSize = 0; 27 | return TRUE; 28 | } 29 | } // namespace mingw_thunk 30 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/kernel32/CreateHardLinkW.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | __DEFINE_THUNK(kernel32, 8 | 12, 9 | BOOL, 10 | WINAPI, 11 | CreateHardLinkW, 12 | _In_ LPCWSTR lpFileName, 13 | _In_ LPCWSTR lpExistingFileName, 14 | _Reserved_ LPSECURITY_ATTRIBUTES lpSecurityAttributes) 15 | { 16 | if (const auto pfn = try_get_CreateHardLinkW()) 17 | return pfn(lpFileName, lpExistingFileName, lpSecurityAttributes); 18 | 19 | SetLastError(ERROR_NOT_SUPPORTED); 20 | return FALSE; 21 | } 22 | } // namespace mingw_thunk 23 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/kernel32/CreateToolhelp32Snapshot.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace mingw_thunk 8 | { 9 | __DEFINE_THUNK(kernel32, 10 | 8, 11 | HANDLE, 12 | WINAPI, 13 | CreateToolhelp32Snapshot, 14 | _In_ DWORD dwFlags, 15 | _In_ DWORD th32ProcessID) 16 | { 17 | if (const auto pfn = try_get_CreateToolhelp32Snapshot()) 18 | return pfn(dwFlags, th32ProcessID); 19 | 20 | SetLastError(ERROR_NOT_SUPPORTED); 21 | return INVALID_HANDLE_VALUE; 22 | } 23 | } // namespace mingw_thunk 24 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/kernel32/FindFirstVolumeW.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | namespace mingw_thunk 8 | { 9 | __DEFINE_THUNK(kernel32, 10 | 8, 11 | HANDLE, 12 | WINAPI, 13 | FindFirstVolumeW, 14 | _Out_ LPWSTR lpszVolumeName, 15 | _In_ DWORD cchBufferLength) 16 | { 17 | if (const auto pfn = try_get_FindFirstVolumeW()) 18 | return pfn(lpszVolumeName, cchBufferLength); 19 | 20 | if (cchBufferLength < 4) { 21 | SetLastError(ERROR_INVALID_PARAMETER); 22 | return INVALID_HANDLE_VALUE; 23 | } 24 | 25 | DWORD volumes = GetLogicalDrives(); 26 | if (volumes == 0) { 27 | return INVALID_HANDLE_VALUE; 28 | } 29 | 30 | DWORD drive = 0; 31 | for (; drive < 26; drive++) { 32 | if (volumes & (1 << drive)) { 33 | break; 34 | } 35 | } 36 | 37 | auto *data = internal::malloc( 38 | sizeof(internal::find_volume_data)); 39 | 40 | if (!data) { 41 | SetLastError(ERROR_NOT_ENOUGH_MEMORY); 42 | return INVALID_HANDLE_VALUE; 43 | } 44 | 45 | data->volumes = volumes; 46 | data->current = drive; 47 | 48 | lpszVolumeName[0] = 'A' + drive; 49 | lpszVolumeName[1] = ':'; 50 | lpszVolumeName[2] = '\\'; 51 | lpszVolumeName[3] = '\0'; 52 | 53 | return data; 54 | } 55 | } // namespace mingw_thunk 56 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/kernel32/FindNextVolumeW.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_THUNK(kernel32, 9 | 12, 10 | BOOL, 11 | WINAPI, 12 | FindNextVolumeW, 13 | _In_ HANDLE hFindVolume, 14 | _Out_ LPWSTR lpszVolumeName, 15 | _In_ DWORD cchBufferLength) 16 | { 17 | if (const auto pfn = try_get_FindNextVolumeW()) 18 | return pfn(hFindVolume, lpszVolumeName, cchBufferLength); 19 | 20 | if (cchBufferLength < 4) { 21 | SetLastError(ERROR_INVALID_PARAMETER); 22 | return FALSE; 23 | } 24 | 25 | auto *data = reinterpret_cast(hFindVolume); 26 | 27 | DWORD volumes = data->volumes; 28 | DWORD drive = data->current + 1; 29 | for (; drive < 26; drive++) { 30 | if (volumes & (1 << drive)) { 31 | break; 32 | } 33 | } 34 | 35 | if (drive >= 26) { 36 | SetLastError(ERROR_NO_MORE_FILES); 37 | return FALSE; 38 | } 39 | 40 | data->current = drive; 41 | 42 | lpszVolumeName[0] = 'A' + drive; 43 | lpszVolumeName[1] = ':'; 44 | lpszVolumeName[2] = '\\'; 45 | lpszVolumeName[3] = '\0'; 46 | 47 | return TRUE; 48 | } 49 | } // namespace mingw_thunk 50 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/kernel32/FindVolumeClose.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | namespace mingw_thunk 8 | { 9 | __DEFINE_THUNK( 10 | kernel32, 4, BOOL, WINAPI, FindVolumeClose, _In_ HANDLE hFindVolume) 11 | { 12 | if (const auto pfn = try_get_FindVolumeClose()) 13 | return pfn(hFindVolume); 14 | 15 | internal::free(hFindVolume); 16 | return TRUE; 17 | } 18 | } // namespace mingw_thunk 19 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/kernel32/GetCPInfoExA.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_THUNK(kernel32, 9 | 12, 10 | BOOL, 11 | WINAPI, 12 | GetCPInfoExA, 13 | _In_ UINT CodePage, 14 | _In_ DWORD dwFlags, 15 | _Out_ LPCPINFOEXA lpCPInfoEx) 16 | { 17 | if (const auto pfn = try_get_GetCPInfoExA()) 18 | return pfn(CodePage, dwFlags, lpCPInfoEx); 19 | 20 | // Never use CP_THREAD_ACP! It does not mean what you think it means. 21 | if (CodePage == CP_MACCP || CodePage == CP_THREAD_ACP) { 22 | SetLastError(ERROR_NOT_SUPPORTED); 23 | return FALSE; 24 | } 25 | 26 | if (CodePage == CP_ACP) 27 | CodePage = GetACP(); 28 | 29 | if (CodePage == CP_OEMCP) 30 | CodePage = GetOEMCP(); 31 | 32 | CPINFO info; 33 | if (!GetCPInfo(CodePage, &info)) 34 | return FALSE; 35 | 36 | internal::memcpy(lpCPInfoEx, &info, sizeof(CPINFO)); 37 | 38 | lpCPInfoEx->UnicodeDefaultChar = L'?'; 39 | lpCPInfoEx->CodePage = CodePage; 40 | 41 | if (CodePage == CP_UTF8) 42 | internal::strcpy(lpCPInfoEx->CodePageName, "UTF-8"); 43 | else { 44 | char *name = lpCPInfoEx->CodePageName; 45 | *name++ = 'C'; 46 | *name++ = 'P'; 47 | if (CodePage >= 10000) 48 | *name++ = '0' + CodePage / 10000; 49 | if (CodePage >= 1000) 50 | *name++ = '0' + CodePage / 1000 % 10; 51 | *name++ = '0' + CodePage / 100 % 10; 52 | *name++ = '0' + CodePage / 10 % 10; 53 | *name++ = '0' + CodePage % 10; 54 | *name++ = '\0'; 55 | } 56 | 57 | return TRUE; 58 | } 59 | } // namespace mingw_thunk 60 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/kernel32/GetFileSizeEx.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | __DEFINE_THUNK(kernel32, 8 | 8, 9 | BOOL, 10 | WINAPI, 11 | GetFileSizeEx, 12 | _In_ HANDLE hFile, 13 | _Out_ PLARGE_INTEGER lpFileSize) 14 | { 15 | if (const auto pfn = try_get_GetFileSizeEx()) 16 | return pfn(hFile, lpFileSize); 17 | 18 | DWORD low, high; 19 | low = GetFileSize(hFile, &high); 20 | 21 | if (low == INVALID_FILE_SIZE && GetLastError()) 22 | return FALSE; 23 | 24 | lpFileSize->LowPart = low; 25 | lpFileSize->HighPart = high; 26 | 27 | return TRUE; 28 | } 29 | } // namespace mingw_thunk 30 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/kernel32/GetLongPathNameW.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | namespace mingw_thunk 8 | { 9 | __DEFINE_THUNK(kernel32, 10 | 12, 11 | DWORD, 12 | WINAPI, 13 | GetLongPathNameW, 14 | _In_ LPCWSTR lpszShortPath, 15 | _Out_ LPWSTR lpszLongPath, 16 | _In_ DWORD cchBuffer) 17 | { 18 | if (const auto pfn = try_get_GetLongPathNameW()) { 19 | return pfn(lpszShortPath, lpszLongPath, cchBuffer); 20 | } 21 | 22 | // TODO: special handling Windows 9x 23 | 24 | size_t len = internal::wcslen(lpszShortPath); 25 | if (len >= cchBuffer) 26 | return len + 1; 27 | 28 | internal::memcpy(lpszLongPath, lpszShortPath, len * sizeof(wchar_t)); 29 | lpszLongPath[len] = 0; 30 | return len; 31 | } 32 | } // namespace mingw_thunk 33 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/kernel32/GetVolumePathNameW.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_THUNK(kernel32, 9 | 12, 10 | BOOL, 11 | WINAPI, 12 | GetVolumePathNameW, 13 | _In_ LPCWSTR lpszFileName, 14 | _Out_ LPWSTR lpszVolumePathName, 15 | _In_ DWORD cchBufferLength) 16 | { 17 | if (const auto pfn = try_get_GetVolumePathNameW()) 18 | return pfn(lpszFileName, lpszVolumePathName, cchBufferLength); 19 | 20 | if (cchBufferLength < 4) { 21 | SetLastError(ERROR_INSUFFICIENT_BUFFER); 22 | return FALSE; 23 | } 24 | 25 | if (!internal::isalpha(lpszFileName[0]) || lpszFileName[1] != L':' || 26 | lpszFileName[2] != L'\\') { 27 | wchar_t system_directory[MAX_PATH]; 28 | GetSystemDirectoryW(system_directory, MAX_PATH); 29 | lpszFileName = system_directory; 30 | } 31 | 32 | lpszVolumePathName[0] = lpszFileName[0]; 33 | lpszVolumePathName[1] = L':'; 34 | lpszVolumePathName[2] = L'\\'; 35 | lpszVolumePathName[3] = 0; 36 | 37 | return TRUE; 38 | } 39 | } // namespace mingw_thunk 40 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/kernel32/GlobalMemoryStatusEx.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | __DEFINE_THUNK(kernel32, 8 | 4, 9 | BOOL, 10 | WINAPI, 11 | GlobalMemoryStatusEx, 12 | _Inout_ LPMEMORYSTATUSEX lpBuffer) 13 | { 14 | if (const auto pfn = try_get_GlobalMemoryStatusEx()) 15 | return pfn(lpBuffer); 16 | 17 | MEMORYSTATUS ms = {sizeof(MEMORYSTATUS)}; 18 | GlobalMemoryStatus(&ms); 19 | 20 | lpBuffer->dwMemoryLoad = ms.dwMemoryLoad; 21 | lpBuffer->ullTotalPhys = ms.dwTotalPhys; 22 | lpBuffer->ullAvailPhys = ms.dwAvailPhys; 23 | lpBuffer->ullTotalPageFile = ms.dwTotalPageFile; 24 | lpBuffer->ullAvailPageFile = ms.dwAvailPageFile; 25 | lpBuffer->ullTotalVirtual = ms.dwTotalVirtual; 26 | lpBuffer->ullAvailVirtual = ms.dwAvailVirtual; 27 | lpBuffer->ullAvailExtendedVirtual = 0; 28 | return TRUE; 29 | } 30 | } // namespace mingw_thunk 31 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/kernel32/Module32First.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace mingw_thunk 8 | { 9 | __DEFINE_THUNK(kernel32, 10 | 8, 11 | BOOL, 12 | WINAPI, 13 | Module32First, 14 | _In_ HANDLE hSnapshot, 15 | _Inout_ LPMODULEENTRY32 lpme) 16 | { 17 | if (const auto pfn = try_get_Module32First()) 18 | return pfn(hSnapshot, lpme); 19 | 20 | SetLastError(ERROR_NOT_SUPPORTED); 21 | return FALSE; 22 | } 23 | } // namespace mingw_thunk 24 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/kernel32/Module32Next.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace mingw_thunk 8 | { 9 | __DEFINE_THUNK(kernel32, 10 | 8, 11 | BOOL, 12 | WINAPI, 13 | Module32Next, 14 | _In_ HANDLE hSnapshot, 15 | _Out_ LPMODULEENTRY32 lpme) 16 | { 17 | if (const auto pfn = try_get_Module32Next()) 18 | return pfn(hSnapshot, lpme); 19 | 20 | SetLastError(ERROR_NOT_SUPPORTED); 21 | return FALSE; 22 | } 23 | } // namespace mingw_thunk 24 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/kernel32/SetFilePointerEx.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | __DEFINE_THUNK(kernel32, 8 | 20, 9 | BOOL, 10 | WINAPI, 11 | SetFilePointerEx, 12 | _In_ HANDLE hFile, 13 | _In_ LARGE_INTEGER liDistanceToMove, 14 | _Out_opt_ PLARGE_INTEGER lpNewFilePointer, 15 | _In_ DWORD dwMoveMethod) 16 | { 17 | if (const auto pfn = try_get_SetFilePointerEx()) 18 | return pfn(hFile, liDistanceToMove, lpNewFilePointer, dwMoveMethod); 19 | 20 | LONG high = liDistanceToMove.HighPart; 21 | DWORD low = 22 | SetFilePointer(hFile, liDistanceToMove.LowPart, &high, dwMoveMethod); 23 | 24 | if (low == INVALID_SET_FILE_POINTER && GetLastError()) 25 | return FALSE; 26 | 27 | if (lpNewFilePointer) { 28 | lpNewFilePointer->LowPart = low; 29 | lpNewFilePointer->HighPart = high; 30 | } 31 | 32 | return TRUE; 33 | } 34 | } // namespace mingw_thunk 35 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_ctime64.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_CRT_THUNK(char *, _ctime64, const __time64_t *sourceTime) 9 | { 10 | if (const auto pfn = try_get__ctime64()) 11 | return pfn(sourceTime); 12 | 13 | struct tm *tm = _localtime64(sourceTime); 14 | if (!tm) 15 | return nullptr; 16 | return asctime(tm); 17 | }; 18 | } // namespace mingw_thunk 19 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_findfirst64.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | namespace mingw_thunk 10 | { 11 | __DEFINE_CRT_THUNK(intptr_t, 12 | _findfirst64, 13 | const char *filespec, 14 | struct __finddata64_t *fileinfo) 15 | { 16 | if (const auto pfn = try_get__findfirst64()) 17 | return pfn(filespec, fileinfo); 18 | 19 | WIN32_FIND_DATAA fd; 20 | HANDLE h = FindFirstFileA(filespec, &fd); 21 | if (h == INVALID_HANDLE_VALUE) { 22 | internal::dosmaperr(GetLastError()); 23 | return -1; 24 | } 25 | 26 | ULARGE_INTEGER size = { 27 | .LowPart = fd.nFileSizeLow, 28 | .HighPart = fd.nFileSizeHigh, 29 | }; 30 | 31 | fileinfo->attrib = fd.dwFileAttributes; 32 | fileinfo->time_create = internal::c_time64_from_filetime(fd.ftCreationTime); 33 | fileinfo->time_access = 34 | internal::c_time64_from_filetime(fd.ftLastAccessTime); 35 | fileinfo->time_write = internal::c_time64_from_filetime(fd.ftLastWriteTime); 36 | fileinfo->size = size.QuadPart; 37 | strncpy(fileinfo->name, fd.cFileName, MAX_PATH); 38 | 39 | return reinterpret_cast(h); 40 | } 41 | } // namespace mingw_thunk 42 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_findfirst64.test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | TEST_CASE("_findfirst64 and _findnext64") 8 | { 9 | const char *filename = "test-_findfirst64.txt"; 10 | 11 | SECTION("create test file") 12 | { 13 | FILE *fp = fopen(filename, "w"); 14 | REQUIRE(fp != nullptr); 15 | fclose(fp); 16 | } 17 | 18 | const char *pattern = "test-*.txt"; 19 | 20 | __finddata64_t data; 21 | bool found = false; 22 | 23 | CLEAR_TOUCH_FLAG(); 24 | intptr_t handle = _findfirst64(pattern, &data); 25 | REQUIRE_TOUCHED(); 26 | 27 | REQUIRE(handle != -1); 28 | 29 | do { 30 | if (strncmp(data.name, filename, MAX_PATH) == 0) 31 | found = true; 32 | } while ([&]() { 33 | CLEAR_TOUCH_FLAG(); 34 | int ret = _findnext64(handle, &data); 35 | REQUIRE_TOUCHED(); 36 | return ret == 0; 37 | }()); 38 | 39 | REQUIRE(errno == ENOENT); 40 | 41 | REQUIRE(found); 42 | } 43 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_findnext64.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | namespace mingw_thunk 10 | { 11 | __DEFINE_CRT_THUNK(int, 12 | _findnext64, 13 | intptr_t handle, 14 | struct __finddata64_t *fileinfo) 15 | { 16 | if (const auto pfn = try_get__findnext64()) 17 | return pfn(handle, fileinfo); 18 | 19 | HANDLE h = reinterpret_cast(handle); 20 | 21 | WIN32_FIND_DATAA fd; 22 | if (!FindNextFileA(h, &fd)) { 23 | internal::dosmaperr(GetLastError()); 24 | return -1; 25 | } 26 | 27 | ULARGE_INTEGER size = { 28 | .LowPart = fd.nFileSizeLow, 29 | .HighPart = fd.nFileSizeHigh, 30 | }; 31 | 32 | fileinfo->attrib = fd.dwFileAttributes; 33 | fileinfo->time_create = internal::c_time64_from_filetime(fd.ftCreationTime); 34 | fileinfo->time_access = 35 | internal::c_time64_from_filetime(fd.ftLastAccessTime); 36 | fileinfo->time_write = internal::c_time64_from_filetime(fd.ftLastWriteTime); 37 | fileinfo->size = size.QuadPart; 38 | strncpy(fileinfo->name, fd.cFileName, MAX_PATH); 39 | 40 | return 0; 41 | } 42 | } // namespace mingw_thunk 43 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_fstat64.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | namespace mingw_thunk 11 | { 12 | __DEFINE_CRT_THUNK(int, _fstat64, int fd, struct _stat64 *buffer) 13 | { 14 | if (const auto pfn = try_get__fstat64()) 15 | return pfn(fd, buffer); 16 | 17 | struct _stat32i64 buffer32; 18 | int ret = _fstat32i64(fd, &buffer32); 19 | if (ret != 0) 20 | return ret; 21 | 22 | buffer->st_dev = buffer32.st_dev; 23 | buffer->st_ino = buffer32.st_ino; 24 | buffer->st_mode = buffer32.st_mode; 25 | buffer->st_nlink = buffer32.st_nlink; 26 | buffer->st_uid = buffer32.st_uid; 27 | buffer->st_gid = buffer32.st_gid; 28 | buffer->st_rdev = buffer32.st_rdev; 29 | buffer->st_size = buffer32.st_size; 30 | 31 | HANDLE hFile = reinterpret_cast(_get_osfhandle(fd)); 32 | 33 | FILETIME atime, mtime, ctime; 34 | 35 | if (!GetFileTime(hFile, &ctime, &atime, &mtime)) { 36 | internal::dosmaperr(GetLastError()); 37 | return -1; 38 | } 39 | 40 | buffer->st_atime = internal::c_time64_from_filetime(atime); 41 | buffer->st_mtime = internal::c_time64_from_filetime(mtime); 42 | buffer->st_ctime = internal::c_time64_from_filetime(ctime); 43 | 44 | return 0; 45 | } 46 | } // namespace mingw_thunk 47 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_futime64.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | namespace mingw_thunk 11 | { 12 | __DEFINE_CRT_THUNK(int, _futime64, int fd, struct __utimbuf64 *filetime) 13 | { 14 | if (const auto pfn = try_get__futime64()) 15 | return pfn(fd, filetime); 16 | 17 | HANDLE hFile = reinterpret_cast(_get_osfhandle(fd)); 18 | 19 | FILETIME atime = internal::filetime_from_c_time64(filetime->actime); 20 | FILETIME mtime = internal::filetime_from_c_time64(filetime->modtime); 21 | 22 | if (!SetFileTime(hFile, nullptr, &atime, &mtime)) { 23 | internal::dosmaperr(GetLastError()); 24 | return -1; 25 | } 26 | 27 | return 0; 28 | }; 29 | } // namespace mingw_thunk 30 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_futime64.test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | TEST_CASE("_futime64 and _fstat64") 10 | { 11 | const wchar_t *filename = L"test-_futime64.txt"; 12 | 13 | int fd = _wopen(filename, _O_CREAT | _O_WRONLY, _S_IRWXU); 14 | 15 | REQUIRE(fd >= 0); 16 | 17 | struct __utimbuf64 times = {0x1'0000'0000, 0x1'0000'0000}; 18 | 19 | CLEAR_TOUCH_FLAG(); 20 | int ret = _futime64(fd, ×); 21 | REQUIRE_TOUCHED(); 22 | 23 | REQUIRE(ret == 0); 24 | 25 | struct __stat64 stats; 26 | 27 | CLEAR_TOUCH_FLAG(); 28 | ret = _fstat64(fd, &stats); 29 | REQUIRE_TOUCHED(); 30 | 31 | REQUIRE(ret == 0); 32 | REQUIRE(stats.st_mtime == times.modtime); 33 | 34 | // Skip: on Linux (Wine), accessing a file modified in the future will update 35 | // its atime unless the file system is mounted with 'noatime'. 36 | /* REQUIRE(stats.st_atime == times.actime); */ 37 | 38 | close(fd); 39 | } 40 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_gmtime64.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_CRT_THUNK(struct tm *, _gmtime64, const __time64_t *sourceTime) 9 | { 10 | if (const auto pfn = try_get__gmtime64()) 11 | return pfn(sourceTime); 12 | 13 | thread_local struct tm tm; 14 | internal::__secs_to_tm(*sourceTime, &tm); 15 | tm.tm_isdst = 0; 16 | return &tm; 17 | } 18 | } // namespace mingw_thunk 19 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_gmtime64.test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | TEST_CASE("_gmtime64") 6 | { 7 | for (__time64_t time64 = 0; time64 < 0x8000'0000; time64 += 0x1000'0000) { 8 | __time32_t time32 = time64; 9 | struct tm tm32 = *_gmtime32(&time32); 10 | 11 | CLEAR_TOUCH_FLAG(); 12 | struct tm tm64 = *_gmtime64(&time64); 13 | REQUIRE_TOUCHED(); 14 | 15 | REQUIRE(tm32.tm_year == tm64.tm_year); 16 | REQUIRE(tm32.tm_mon == tm64.tm_mon); 17 | REQUIRE(tm32.tm_mday == tm64.tm_mday); 18 | REQUIRE(tm32.tm_hour == tm64.tm_hour); 19 | REQUIRE(tm32.tm_min == tm64.tm_min); 20 | REQUIRE(tm32.tm_sec == tm64.tm_sec); 21 | REQUIRE(tm32.tm_wday == tm64.tm_wday); 22 | REQUIRE(tm32.tm_yday == tm64.tm_yday); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_localtime64.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_CRT_THUNK(struct tm *, _localtime64, const __time64_t *sourceTime) 9 | { 10 | if (const auto pfn = try_get__localtime64()) 11 | return pfn(sourceTime); 12 | 13 | thread_local struct tm tm; 14 | 15 | if (*sourceTime <= 0x7FFFFFFF) { 16 | __time32_t time32 = *sourceTime; 17 | struct tm *tm32 = _localtime32(&time32); 18 | if (tm32) { 19 | tm = *tm32; 20 | return &tm; 21 | } else { 22 | return nullptr; 23 | } 24 | } else { 25 | // the epoch is 2038-01-19 03:14:07 UTC. 26 | // Microsoft doesn't support time after 2038-01-18 23:59:59 UTC. 27 | // the time zone range is -12:00 to +14:00. 28 | // use 1 day before the epoch should be safe to estimate the offset. 29 | __time32_t safe_test_time = 0x7FFFFFFF - 24 * 60 * 60; 30 | 31 | // for msvcrt without _localtime64, there is no _mkgmtime either. 32 | struct tm test_tm = *_gmtime32(&safe_test_time); 33 | __time32_t pseudo_time = _mktime32(&test_tm); 34 | 35 | // take UTC+8 for example: 36 | // original time_t: 0 37 | // converted struct tm: 0:00 UTC 38 | // treat it as local time: 0:00 UTC+8 39 | // converted time_t: -8 * 60 * 60 40 | // offset: 8 * 60 * 60 41 | __time32_t offset = safe_test_time - pseudo_time; 42 | 43 | internal::__secs_to_tm(*sourceTime + offset, &tm); 44 | tm.tm_isdst = test_tm.tm_isdst; 45 | return &tm; 46 | } 47 | } 48 | } // namespace mingw_thunk 49 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_localtime64.test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | TEST_CASE("_localtime64") 6 | { 7 | __time32_t time32 = 0x7FFF'FFFF - 24 * 60 * 60; 8 | __time64_t time64 = __time64_t(0x7FFF'FFFF) + 24 * 60 * 60; 9 | struct tm tm32 = *_localtime32(&time32); 10 | 11 | CLEAR_TOUCH_FLAG(); 12 | struct tm tm64 = *_localtime64(&time64); 13 | REQUIRE_TOUCHED(); 14 | 15 | REQUIRE(tm32.tm_year == tm64.tm_year); 16 | REQUIRE(tm32.tm_mon == tm64.tm_mon); 17 | REQUIRE(tm32.tm_mday + 2 == tm64.tm_mday); 18 | REQUIRE(tm32.tm_hour == tm64.tm_hour); 19 | REQUIRE(tm32.tm_min == tm64.tm_min); 20 | REQUIRE(tm32.tm_sec == tm64.tm_sec); 21 | } 22 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_stat64.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | namespace mingw_thunk 10 | { 11 | __DEFINE_CRT_THUNK(int, _stat64, const char *path, struct __stat64 *buffer) 12 | { 13 | if (const auto pfn = try_get__stat64()) 14 | return pfn(path, buffer); 15 | 16 | struct _stat32i64 buffer32; 17 | int ret = _stat32i64(path, &buffer32); 18 | if (ret != 0) 19 | return ret; 20 | 21 | buffer->st_dev = buffer32.st_dev; 22 | buffer->st_ino = buffer32.st_ino; 23 | buffer->st_mode = buffer32.st_mode; 24 | buffer->st_nlink = buffer32.st_nlink; 25 | buffer->st_uid = buffer32.st_uid; 26 | buffer->st_gid = buffer32.st_gid; 27 | buffer->st_rdev = buffer32.st_rdev; 28 | buffer->st_size = buffer32.st_size; 29 | 30 | WIN32_FILE_ATTRIBUTE_DATA attr; 31 | if (!GetFileAttributesExA(path, GetFileExInfoStandard, &attr)) { 32 | internal::dosmaperr(GetLastError()); 33 | return -1; 34 | } 35 | 36 | buffer->st_atime = internal::c_time64_from_filetime(attr.ftLastAccessTime); 37 | buffer->st_mtime = internal::c_time64_from_filetime(attr.ftLastWriteTime); 38 | buffer->st_ctime = internal::c_time64_from_filetime(attr.ftCreationTime); 39 | 40 | return 0; 41 | } 42 | } // namespace mingw_thunk 43 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_time64.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace mingw_thunk 9 | { 10 | __DEFINE_CRT_THUNK(__time64_t, _time64, __time64_t *destTime) 11 | { 12 | if (const auto pfn = try_get__time64()) 13 | return pfn(destTime); 14 | 15 | FILETIME ft; 16 | GetSystemTimeAsFileTime(&ft); 17 | __time64_t ct = internal::c_time64_from_filetime(ft); 18 | if (destTime) 19 | *destTime = ct; 20 | return ct; 21 | }; 22 | } // namespace mingw_thunk 23 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_utime64.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_CRT_THUNK(int, 9 | _utime64, 10 | const char *filename, 11 | struct __utimbuf64 *times) 12 | { 13 | if (const auto pfn = try_get__utime64()) 14 | return pfn(filename, times); 15 | 16 | int fd = _open(filename, _O_BINARY | _O_WRONLY); 17 | if (fd < 0) 18 | return -1; 19 | 20 | int ret = _futime64(fd, times); 21 | _close(fd); 22 | return ret; 23 | } 24 | } // namespace mingw_thunk 25 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_utime64.test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | TEST_CASE("_utime64 and _stat64") 8 | { 9 | const char *filename = "test-_utime64.txt"; 10 | 11 | SECTION("create test file") 12 | { 13 | FILE *fp = fopen(filename, "w"); 14 | REQUIRE(fp != nullptr); 15 | fclose(fp); 16 | } 17 | 18 | struct __utimbuf64 times = {0x1'0000'0000, 0x1'0000'0000}; 19 | 20 | CLEAR_TOUCH_FLAG(); 21 | int ret = _utime64(filename, ×); 22 | REQUIRE_TOUCHED(); 23 | 24 | REQUIRE(ret == 0); 25 | 26 | struct __stat64 stats; 27 | 28 | CLEAR_TOUCH_FLAG(); 29 | ret = _stat64(filename, &stats); 30 | REQUIRE_TOUCHED(); 31 | 32 | REQUIRE(ret == 0); 33 | REQUIRE(stats.st_atime == times.actime); 34 | REQUIRE(stats.st_mtime == times.modtime); 35 | } 36 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_wfindfirst64.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | namespace mingw_thunk 10 | { 11 | __DEFINE_CRT_THUNK(intptr_t, 12 | _wfindfirst64, 13 | const wchar_t *filespec, 14 | struct _wfinddata64_t *fileinfo) 15 | { 16 | if (const auto pfn = try_get__wfindfirst64()) 17 | return pfn(filespec, fileinfo); 18 | 19 | WIN32_FIND_DATAW fd; 20 | HANDLE h = FindFirstFileW(filespec, &fd); 21 | if (h == INVALID_HANDLE_VALUE) { 22 | internal::dosmaperr(GetLastError()); 23 | return -1; 24 | } 25 | 26 | ULARGE_INTEGER size = { 27 | .LowPart = fd.nFileSizeLow, 28 | .HighPart = fd.nFileSizeHigh, 29 | }; 30 | 31 | fileinfo->attrib = fd.dwFileAttributes; 32 | fileinfo->time_create = internal::c_time64_from_filetime(fd.ftCreationTime); 33 | fileinfo->time_access = 34 | internal::c_time64_from_filetime(fd.ftLastAccessTime); 35 | fileinfo->time_write = internal::c_time64_from_filetime(fd.ftLastWriteTime); 36 | fileinfo->size = size.QuadPart; 37 | wcsncpy(fileinfo->name, fd.cFileName, MAX_PATH); 38 | 39 | return reinterpret_cast(h); 40 | } 41 | } // namespace mingw_thunk 42 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_wfindfirst64.test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | TEST_CASE("_wfindfirst64 and _wfindnext64") 8 | { 9 | const wchar_t *filename = L"test-_wfindfirst64.txt"; 10 | 11 | SECTION("create test file") 12 | { 13 | FILE *fp = _wfopen(filename, L"w"); 14 | REQUIRE(fp != nullptr); 15 | fclose(fp); 16 | } 17 | 18 | const wchar_t *pattern = L"test-*.txt"; 19 | 20 | _wfinddata64_t data; 21 | bool found = false; 22 | 23 | CLEAR_TOUCH_FLAG(); 24 | intptr_t handle = _wfindfirst64(pattern, &data); 25 | REQUIRE_TOUCHED(); 26 | 27 | REQUIRE(handle != -1); 28 | 29 | do { 30 | if (wcsncmp(data.name, filename, MAX_PATH) == 0) 31 | found = true; 32 | } while ([&]() { 33 | CLEAR_TOUCH_FLAG(); 34 | int ret = _wfindnext64(handle, &data); 35 | REQUIRE_TOUCHED(); 36 | return ret == 0; 37 | }()); 38 | 39 | REQUIRE(errno == ENOENT); 40 | 41 | REQUIRE(found); 42 | } 43 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_wfindnext64.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | namespace mingw_thunk 10 | { 11 | __DEFINE_CRT_THUNK(int, 12 | _wfindnext64, 13 | intptr_t handle, 14 | struct _wfinddata64_t *fileinfo) 15 | { 16 | if (const auto pfn = try_get__wfindnext64()) 17 | return pfn(handle, fileinfo); 18 | 19 | HANDLE h = reinterpret_cast(handle); 20 | 21 | WIN32_FIND_DATAW fd; 22 | if (!FindNextFileW(h, &fd)) { 23 | internal::dosmaperr(GetLastError()); 24 | return -1; 25 | } 26 | 27 | ULARGE_INTEGER size = { 28 | .LowPart = fd.nFileSizeLow, 29 | .HighPart = fd.nFileSizeHigh, 30 | }; 31 | 32 | fileinfo->attrib = fd.dwFileAttributes; 33 | fileinfo->time_create = internal::c_time64_from_filetime(fd.ftCreationTime); 34 | fileinfo->time_access = 35 | internal::c_time64_from_filetime(fd.ftLastAccessTime); 36 | fileinfo->time_write = internal::c_time64_from_filetime(fd.ftLastWriteTime); 37 | fileinfo->size = size.QuadPart; 38 | wcsncpy(fileinfo->name, fd.cFileName, MAX_PATH); 39 | 40 | return 0; 41 | } 42 | } // namespace mingw_thunk 43 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_wstat64.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | namespace mingw_thunk 10 | { 11 | __DEFINE_CRT_THUNK(int, 12 | _wstat64, 13 | const wchar_t *path, 14 | struct __stat64 *buffer) 15 | { 16 | if (const auto pfn = try_get__wstat64()) 17 | return pfn(path, buffer); 18 | 19 | struct _stat32i64 buffer32; 20 | int ret = _wstat32i64(path, &buffer32); 21 | if (ret != 0) 22 | return ret; 23 | 24 | buffer->st_dev = buffer32.st_dev; 25 | buffer->st_ino = buffer32.st_ino; 26 | buffer->st_mode = buffer32.st_mode; 27 | buffer->st_nlink = buffer32.st_nlink; 28 | buffer->st_uid = buffer32.st_uid; 29 | buffer->st_gid = buffer32.st_gid; 30 | buffer->st_rdev = buffer32.st_rdev; 31 | buffer->st_size = buffer32.st_size; 32 | 33 | WIN32_FILE_ATTRIBUTE_DATA attr; 34 | if (!GetFileAttributesExW(path, GetFileExInfoStandard, &attr)) { 35 | internal::dosmaperr(GetLastError()); 36 | return -1; 37 | } 38 | 39 | buffer->st_atime = internal::c_time64_from_filetime(attr.ftLastAccessTime); 40 | buffer->st_mtime = internal::c_time64_from_filetime(attr.ftLastWriteTime); 41 | buffer->st_ctime = internal::c_time64_from_filetime(attr.ftCreationTime); 42 | 43 | return 0; 44 | } 45 | } // namespace mingw_thunk 46 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_wutime64.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | namespace mingw_thunk 9 | { 10 | __DEFINE_CRT_THUNK(int, 11 | _wutime64, 12 | const wchar_t *filename, 13 | struct __utimbuf64 *times) 14 | { 15 | if (const auto pfn = try_get__wutime64()) 16 | return pfn(filename, times); 17 | 18 | int fd = _wopen(filename, _O_BINARY | _O_WRONLY); 19 | if (fd < 0) 20 | return -1; 21 | 22 | int ret = _futime64(fd, times); 23 | _close(fd); 24 | return ret; 25 | } 26 | } // namespace mingw_thunk 27 | -------------------------------------------------------------------------------- /support/thunk/src/5.0/msvcrt/_wutime64.test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | TEST_CASE("_wutime64 and _wstat64") 8 | { 9 | const wchar_t *filename = L"test-_wutime64.txt"; 10 | 11 | SECTION("create test file") 12 | { 13 | FILE *fp = _wfopen(filename, L"w"); 14 | REQUIRE(fp != nullptr); 15 | fclose(fp); 16 | } 17 | 18 | struct __utimbuf64 times = {0x1'0000'0000, 0x1'0000'0000}; 19 | 20 | CLEAR_TOUCH_FLAG(); 21 | int ret = _wutime64(filename, ×); 22 | REQUIRE_TOUCHED(); 23 | 24 | REQUIRE(ret == 0); 25 | 26 | struct __stat64 stats; 27 | 28 | CLEAR_TOUCH_FLAG(); 29 | ret = _wstat64(filename, &stats); 30 | REQUIRE_TOUCHED(); 31 | 32 | REQUIRE(ret == 0); 33 | REQUIRE(stats.st_atime == times.actime); 34 | REQUIRE(stats.st_mtime == times.modtime); 35 | } 36 | -------------------------------------------------------------------------------- /support/thunk/src/5.1/kernel32/AddVectoredExceptionHandler.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_THUNK(kernel32, 9 | 8, 10 | PVOID, 11 | WINAPI, 12 | AddVectoredExceptionHandler, 13 | ULONG First, 14 | PVECTORED_EXCEPTION_HANDLER Handler) 15 | { 16 | if (const auto pfn = try_get_AddVectoredExceptionHandler()) 17 | return pfn(First, Handler); 18 | 19 | SetLastError(ERROR_NOT_SUPPORTED); 20 | return NULL; 21 | } 22 | } // namespace mingw_thunk 23 | -------------------------------------------------------------------------------- /support/thunk/src/5.1/kernel32/GetConsoleProcessList.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_THUNK(kernel32, 9 | 8, 10 | DWORD, 11 | WINAPI, 12 | GetConsoleProcessList, 13 | _Out_ LPDWORD lpdwProcessList, 14 | _In_ DWORD dwProcessCount) 15 | { 16 | if (const auto pfn = try_get_GetConsoleProcessList()) 17 | return pfn(lpdwProcessList, dwProcessCount); 18 | 19 | SetLastError(ERROR_NOT_SUPPORTED); 20 | return 0; 21 | } 22 | } // namespace mingw_thunk 23 | -------------------------------------------------------------------------------- /support/thunk/src/5.1/kernel32/GetModuleHandleExW.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_THUNK(kernel32, 9 | 12, 10 | BOOL, 11 | WINAPI, 12 | GetModuleHandleExW, 13 | _In_ DWORD dwFlags, 14 | _In_opt_ LPCWSTR lpModuleName, 15 | _Out_ HMODULE *phModule) 16 | { 17 | if (const auto pfn = try_get_GetModuleHandleExW()) 18 | return pfn(dwFlags, lpModuleName, phModule); 19 | 20 | DWORD known_flags = GET_MODULE_HANDLE_EX_FLAG_PIN | 21 | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | 22 | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS; 23 | 24 | bool pin = dwFlags & GET_MODULE_HANDLE_EX_FLAG_PIN; 25 | bool unchanged_refcount = 26 | dwFlags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT; 27 | bool from_address = dwFlags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS; 28 | 29 | if ((dwFlags & ~known_flags) || pin || 30 | (unchanged_refcount && from_address)) { 31 | SetLastError(ERROR_NOT_SUPPORTED); 32 | return FALSE; 33 | } 34 | 35 | HMODULE h; 36 | if (from_address) { 37 | if (const auto pRtlPcToFileHeader = try_get_RtlPcToFileHeader()) { 38 | h = (HMODULE)pRtlPcToFileHeader((PVOID)lpModuleName, (PVOID *)&h); 39 | if (!h) 40 | SetLastError(ERROR_DLL_NOT_FOUND); 41 | } else { 42 | SetLastError(ERROR_NOT_SUPPORTED); 43 | return FALSE; 44 | } 45 | } else { 46 | if (unchanged_refcount) 47 | h = GetModuleHandleW(lpModuleName); 48 | else 49 | h = LoadLibraryW(lpModuleName); 50 | } 51 | if (h) { 52 | *phModule = h; 53 | return TRUE; 54 | } else { 55 | return FALSE; 56 | } 57 | } 58 | } // namespace mingw_thunk 59 | -------------------------------------------------------------------------------- /support/thunk/src/5.1/kernel32/GetNumaHighestNodeNumber.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | __DEFINE_THUNK(kernel32, 8 | 4, 9 | BOOL, 10 | WINAPI, 11 | GetNumaHighestNodeNumber, 12 | _Out_ PULONG HighestNodeNumber) 13 | { 14 | if (const auto pfn = try_get_GetNumaHighestNodeNumber()) 15 | return pfn(HighestNodeNumber); 16 | 17 | *HighestNodeNumber = 0; 18 | return TRUE; 19 | } 20 | } // namespace mingw_thunk 21 | -------------------------------------------------------------------------------- /support/thunk/src/5.1/kernel32/GetNumaNodeProcessorMask.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | __DEFINE_THUNK(kernel32, 8 | 8, 9 | BOOL, 10 | WINAPI, 11 | GetNumaNodeProcessorMask, 12 | _In_ UCHAR Node, 13 | _Out_ PULONGLONG ProcessorMask) 14 | { 15 | if (const auto pfn = try_get_GetNumaNodeProcessorMask()) 16 | return pfn(Node, ProcessorMask); 17 | 18 | if (Node == 0) { 19 | SYSTEM_INFO si; 20 | GetSystemInfo(&si); 21 | *ProcessorMask = si.dwActiveProcessorMask; 22 | } else { 23 | *ProcessorMask = 0; 24 | } 25 | return TRUE; 26 | } 27 | } // namespace mingw_thunk 28 | -------------------------------------------------------------------------------- /support/thunk/src/5.1/kernel32/GetSystemTimes.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | __DEFINE_THUNK(kernel32, 8 | 12, 9 | BOOL, 10 | WINAPI, 11 | GetSystemTimes, 12 | _Out_opt_ PFILETIME lpIdleTime, 13 | _Out_opt_ PFILETIME lpKernelTime, 14 | _Out_opt_ PFILETIME lpUserTime) 15 | { 16 | if (const auto pfn = try_get_GetSystemTimes()) 17 | return pfn(lpIdleTime, lpKernelTime, lpUserTime); 18 | 19 | SetLastError(ERROR_NOT_SUPPORTED); 20 | return FALSE; 21 | } 22 | } // namespace mingw_thunk 23 | -------------------------------------------------------------------------------- /support/thunk/src/5.1/kernel32/GetSystemWow64DirectoryA.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_THUNK(kernel32, 9 | 8, 10 | UINT, 11 | WINAPI, 12 | GetSystemWow64DirectoryA, 13 | _Out_ LPSTR lpBuffer, 14 | _In_ UINT uSize) 15 | { 16 | if (const auto pfn = try_get_GetSystemWow64DirectoryA()) 17 | return pfn(lpBuffer, uSize); 18 | 19 | SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 20 | return 0; 21 | } 22 | } // namespace mingw_thunk 23 | -------------------------------------------------------------------------------- /support/thunk/src/5.1/kernel32/GetVolumePathNamesForVolumeNameW.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | namespace mingw_thunk 8 | { 9 | __DEFINE_THUNK(kernel32, 10 | 16, 11 | BOOL, 12 | WINAPI, 13 | GetVolumePathNamesForVolumeNameW, 14 | _In_ LPCWSTR lpszVolumeName, 15 | 16 | _Out_ LPWCH lpszVolumePathNames, 17 | _In_ DWORD cchBufferLength, 18 | _Out_ PDWORD lpcchReturnLength) 19 | { 20 | if (const auto pfn = try_get_GetVolumePathNamesForVolumeNameW()) 21 | return pfn(lpszVolumeName, 22 | lpszVolumePathNames, 23 | cchBufferLength, 24 | lpcchReturnLength); 25 | 26 | SetLastError(ERROR_NOT_SUPPORTED); 27 | return FALSE; 28 | } 29 | } // namespace mingw_thunk 30 | -------------------------------------------------------------------------------- /support/thunk/src/5.1/kernel32/RemoveVectoredExceptionHandler.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_THUNK( 9 | kernel32, 4, ULONG, WINAPI, RemoveVectoredExceptionHandler, PVOID Handle) 10 | { 11 | if (const auto pfn = try_get_RemoveVectoredExceptionHandler()) 12 | return pfn(Handle); 13 | 14 | SetLastError(ERROR_NOT_SUPPORTED); 15 | return 0; 16 | } 17 | } // namespace mingw_thunk 18 | -------------------------------------------------------------------------------- /support/thunk/src/5.1/msvcrt/_aligned_free.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_CRT_THUNK(void, _aligned_free, void *memblock) 9 | { 10 | if (const auto pfn = try_get__aligned_free()) 11 | return pfn(memblock); 12 | 13 | if (memblock) { 14 | void *allocation = static_cast(memblock)[-1]; 15 | ::free(allocation); 16 | } 17 | } 18 | } // namespace mingw_thunk 19 | -------------------------------------------------------------------------------- /support/thunk/src/5.1/msvcrt/_aligned_malloc.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace mingw_thunk 9 | { 10 | __DEFINE_CRT_THUNK(void *, _aligned_malloc, size_t size, size_t alignment) 11 | { 12 | if (const auto pfn = try_get__aligned_malloc()) 13 | return pfn(size, alignment); 14 | 15 | bool is_power_of_2 = (alignment & (alignment - 1)) == 0; 16 | if (!is_power_of_2 || size == 0) { 17 | _set_errno(EINVAL); 18 | return nullptr; 19 | } 20 | 21 | void *allocation = ::malloc(size + alignment); 22 | if (!allocation) 23 | return nullptr; 24 | 25 | uintptr_t high_bits_mask = ~(alignment - 1); 26 | void *aligned = reinterpret_cast( 27 | (reinterpret_cast(allocation) + alignment) & high_bits_mask); 28 | 29 | // save the original allocation pointer exactly before the aligned pointer 30 | reinterpret_cast(aligned)[-1] = allocation; 31 | 32 | return aligned; 33 | } 34 | } // namespace mingw_thunk 35 | -------------------------------------------------------------------------------- /support/thunk/src/5.1/msvcrt/_aligned_malloc.test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | TEST_CASE("_aligned_malloc and _aligned_free") 6 | { 7 | size_t alignment = 64; 8 | for (size_t size = 1; size < (1 << 20); size <<= 1) { 9 | CLEAR_TOUCH_FLAG(); 10 | void *ptr = _aligned_malloc(size, alignment); 11 | REQUIRE_TOUCHED(); 12 | 13 | REQUIRE(ptr != nullptr); 14 | REQUIRE((reinterpret_cast(ptr) & (alignment - 1)) == 0); 15 | 16 | CLEAR_TOUCH_FLAG(); 17 | _aligned_free(ptr); 18 | REQUIRE_TOUCHED(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /support/thunk/src/5.1/ws2_32/freeaddrinfo.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_THUNK( 9 | kernel32, 4, VOID, WSAAPI, freeaddrinfo, _In_ PADDRINFOA pAddrInfo) 10 | { 11 | if (auto pfreeaddrinfo = try_get_freeaddrinfo()) 12 | return pfreeaddrinfo(pAddrInfo); 13 | 14 | while (pAddrInfo) { 15 | auto *next = pAddrInfo->ai_next; 16 | internal::free(pAddrInfo->ai_addr); 17 | internal::free(pAddrInfo); 18 | pAddrInfo = next; 19 | } 20 | } 21 | } // namespace mingw_thunk 22 | -------------------------------------------------------------------------------- /support/thunk/src/5.1/ws2_32/getaddrinfo.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace mingw_thunk 9 | { 10 | __DEFINE_THUNK(kernel32, 11 | 16, 12 | INT, 13 | WSAAPI, 14 | getaddrinfo, 15 | _In_opt_ PCSTR pNodeName, 16 | _In_opt_ PCSTR pServiceName, 17 | _In_opt_ const ADDRINFOA *pHints, 18 | _Out_ PADDRINFOA *ppResult) 19 | { 20 | if (auto pfreeaddrinfo = try_get_getaddrinfo()) 21 | return pfreeaddrinfo(pNodeName, pServiceName, pHints, ppResult); 22 | 23 | if (!pNodeName) 24 | return WSAHOST_NOT_FOUND; 25 | if (pHints && 26 | (pHints->ai_family != AF_UNSPEC && pHints->ai_family != AF_INET)) 27 | return WSAEAFNOSUPPORT; 28 | 29 | int flags = 0; 30 | if (pHints) 31 | flags = pHints->ai_flags; 32 | 33 | int socktype = SOCK_STREAM; 34 | if (pHints) 35 | socktype = pHints->ai_socktype; 36 | 37 | int protocol = IPPROTO_TCP; 38 | if (pHints) 39 | protocol = pHints->ai_protocol; 40 | else if (socktype == SOCK_DGRAM) 41 | protocol = IPPROTO_UDP; 42 | 43 | int port = 0; 44 | if (pServiceName) 45 | port = internal::atoi(pServiceName); 46 | 47 | struct hostent *host = gethostbyname(pNodeName); 48 | if (!host) 49 | return WSAGetLastError(); 50 | 51 | int wsa_error = 0; 52 | addrinfo *result = internal::addrinfo_from_hostent( 53 | host, flags, socktype, protocol, port, wsa_error); 54 | if (wsa_error) 55 | return wsa_error; 56 | *ppResult = result; 57 | return 0; 58 | } 59 | } // namespace mingw_thunk 60 | -------------------------------------------------------------------------------- /support/thunk/src/5.1/ws2_32/getaddrinfo.test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | TEST_CASE("getaddrinfo, getnameinfo and freeaddrinfo") 6 | { 7 | SECTION("initialize Winsock") 8 | { 9 | WSADATA wsaData; 10 | int ret = WSAStartup(MAKEWORD(2, 2), &wsaData); 11 | REQUIRE(ret == 0); 12 | } 13 | 14 | SECTION("getaddrinfo: numeric service") 15 | { 16 | struct addrinfo *res = nullptr; 17 | 18 | CLEAR_TOUCH_FLAG(); 19 | int ret = getaddrinfo("localhost", "8080", nullptr, &res); 20 | REQUIRE_TOUCHED(); 21 | 22 | REQUIRE(ret == 0); 23 | REQUIRE(res != nullptr); 24 | 25 | REQUIRE(res->ai_family == AF_INET); 26 | REQUIRE(res->ai_addrlen == sizeof(struct sockaddr_in)); 27 | 28 | auto *addr = reinterpret_cast(res->ai_addr); 29 | REQUIRE(addr->sin_family == AF_INET); 30 | REQUIRE(addr->sin_port == htons(8080)); 31 | REQUIRE(addr->sin_addr.s_addr == htonl(INADDR_LOOPBACK)); 32 | 33 | CLEAR_TOUCH_FLAG(); 34 | freeaddrinfo(res); 35 | REQUIRE_TOUCHED(); 36 | } 37 | 38 | SECTION("getaddrinfo: invalid node") 39 | { 40 | struct addrinfo *res = nullptr; 41 | 42 | CLEAR_TOUCH_FLAG(); 43 | int ret = 44 | getaddrinfo("invalid-node.invalid-domain", nullptr, nullptr, &res); 45 | REQUIRE_TOUCHED(); 46 | 47 | REQUIRE(ret == WSAHOST_NOT_FOUND); 48 | } 49 | 50 | SECTION("getnameinfo") 51 | { 52 | struct sockaddr_in addr; 53 | addr.sin_family = AF_INET; 54 | addr.sin_port = htons(8080); 55 | addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 56 | char host[NI_MAXHOST]; 57 | char service[NI_MAXSERV]; 58 | 59 | CLEAR_TOUCH_FLAG(); 60 | int ret = getnameinfo(reinterpret_cast(&addr), 61 | sizeof(addr), 62 | host, 63 | sizeof(host), 64 | service, 65 | sizeof(service), 66 | 0); 67 | REQUIRE_TOUCHED(); 68 | 69 | REQUIRE(ret == 0); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /support/thunk/src/5.2/advapi32/RegDeleteKeyExA.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | // YY-Thunks 1.1.6 8 | // Windows XP Professional x64 Edition, Windows Server 2003 with SP1 9 | __DEFINE_THUNK(advapi32, 10 | 16, 11 | LSTATUS, 12 | APIENTRY, 13 | RegDeleteKeyExA, 14 | _In_ HKEY hKey, 15 | _In_ LPCSTR lpSubKey, 16 | _In_ REGSAM samDesired, 17 | _Reserved_ DWORD Reserved) 18 | { 19 | if (auto const pRegDeleteKeyExA = try_get_RegDeleteKeyExA()) { 20 | return pRegDeleteKeyExA(hKey, lpSubKey, samDesired, Reserved); 21 | } 22 | 23 | return RegDeleteKeyA(hKey, lpSubKey); 24 | } 25 | } // namespace mingw_thunk 26 | -------------------------------------------------------------------------------- /support/thunk/src/5.2/advapi32/RegDeleteKeyExW.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | // YY-Thunks 1.1.6 8 | // Windows XP Professional x64 Edition, Windows Server 2003 with SP1 9 | __DEFINE_THUNK(advapi32, 10 | 16, 11 | LSTATUS, 12 | APIENTRY, 13 | RegDeleteKeyExW, 14 | _In_ HKEY hKey, 15 | _In_ LPCWSTR lpSubKey, 16 | _In_ REGSAM samDesired, 17 | _Reserved_ DWORD Reserved) 18 | { 19 | if (auto const pRegDeleteKeyExW = try_get_RegDeleteKeyExW()) { 20 | return pRegDeleteKeyExW(hKey, lpSubKey, samDesired, Reserved); 21 | } 22 | 23 | return RegDeleteKeyW(hKey, lpSubKey); 24 | } 25 | } // namespace mingw_thunk 26 | -------------------------------------------------------------------------------- /support/thunk/src/5.2/kernel32/FlsAlloc.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | __DEFINE_THUNK(kernel32, 8 | 4, 9 | DWORD, 10 | WINAPI, 11 | FlsAlloc, 12 | _In_opt_ PFLS_CALLBACK_FUNCTION lpCallback) 13 | { 14 | if (const auto pfn = try_get_FlsAlloc()) 15 | return pfn(lpCallback); 16 | 17 | // UCRT ignores the callback function, so do we. 18 | return TlsAlloc(); 19 | } 20 | } // namespace mingw_thunk 21 | -------------------------------------------------------------------------------- /support/thunk/src/5.2/kernel32/FlsFree.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | __DEFINE_THUNK(kernel32, 4, BOOL, WINAPI, FlsFree, _In_ DWORD dwFlsIndex) 8 | { 9 | if (const auto pfn = try_get_FlsFree()) 10 | return pfn(dwFlsIndex); 11 | 12 | return TlsFree(dwFlsIndex); 13 | } 14 | } // namespace mingw_thunk 15 | -------------------------------------------------------------------------------- /support/thunk/src/5.2/kernel32/FlsGetValue.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | __DEFINE_THUNK(kernel32, 4, PVOID, WINAPI, FlsGetValue, _In_ DWORD dwFlsIndex) 8 | { 9 | if (const auto pfn = try_get_FlsGetValue()) 10 | return pfn(dwFlsIndex); 11 | 12 | return TlsGetValue(dwFlsIndex); 13 | } 14 | } // namespace mingw_thunk 15 | -------------------------------------------------------------------------------- /support/thunk/src/5.2/kernel32/FlsSetValue.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | __DEFINE_THUNK(kernel32, 8 | 8, 9 | BOOL, 10 | WINAPI, 11 | FlsSetValue, 12 | _In_ DWORD dwFlsIndex, 13 | _In_opt_ PVOID lpFlsData) 14 | { 15 | if (const auto pfn = try_get_FlsSetValue()) 16 | return pfn(dwFlsIndex, lpFlsData); 17 | 18 | return TlsSetValue(dwFlsIndex, lpFlsData); 19 | } 20 | } // namespace mingw_thunk 21 | -------------------------------------------------------------------------------- /support/thunk/src/5.2/kernel32/GetCurrentProcessorNumber.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | namespace mingw_thunk 9 | { 10 | namespace internal 11 | { 12 | 13 | // clang-format off 14 | /* 15 | By executing the command: 16 | diff <(i686-w64-mingw32-g++ -dM -E -march=i486 - #define __GCC_ATOMIC_LLONG_LOCK_FREE 2 22 | 211a212 23 | > #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1 24 | 227,228c228,229 25 | < #define __i486 1 26 | < #define __i486__ 1 27 | --- 28 | > #define __i586 1 29 | > #define __i586__ 1 30 | 303a305,306 31 | > #define __pentium 1 32 | > #define __pentium__ 1 33 | 346c349,350 34 | < #define __tune_i486__ 1 35 | --- 36 | > #define __tune_i586__ 1 37 | > #define __tune_pentium__ 1 38 | 39 | The only way to detect target >= i586 (pentium) is to check for 40 | __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 41 | or 42 | __GCC_ATOMIC_LLONG_LOCK_FREE 43 | */ 44 | // clang-format on 45 | 46 | #if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) // i586 or later (see above) 47 | 48 | constexpr bool is_cpuid_implemented() 49 | { 50 | return true; 51 | } 52 | 53 | #else 54 | 55 | static bool is_cpuid_implemented() 56 | { 57 | static bool result = []() { 58 | constexpr uint32_t cpuid_bit = 1 << 21; 59 | uint32_t original = __builtin_ia32_readeflags_u32(); 60 | 61 | // try invert 62 | __builtin_ia32_writeeflags_u32(original ^ cpuid_bit); 63 | uint32_t updated = __builtin_ia32_readeflags_u32(); 64 | 65 | // is inverted? 66 | return bool((original ^ updated) & cpuid_bit); 67 | }(); 68 | 69 | return result; 70 | } 71 | 72 | #endif 73 | 74 | } // namespace internal 75 | 76 | __DEFINE_THUNK(kernel32, 0, DWORD, WINAPI, GetCurrentProcessorNumber) 77 | { 78 | if (const auto pfn = try_get_GetCurrentProcessorNumber()) 79 | return pfn(); 80 | 81 | if (!internal::is_cpuid_implemented()) 82 | return 0; 83 | 84 | // Windows < NT 5.2 is x86-32 only (stop reviving IA-64) and supports no 85 | // more than 32 logical processors (according to Task Manager Processor 86 | // Affinity dialog). No more checks required. 87 | uint32_t eax, ebx, ecx, edx; 88 | __cpuid(1, eax, ebx, ecx, edx); 89 | return ebx >> 24; 90 | } 91 | } // namespace mingw_thunk 92 | -------------------------------------------------------------------------------- /support/thunk/src/5.2/kernel32/GetLargePageMinimum.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | __DEFINE_THUNK(kernel32, 0, SIZE_T, WINAPI, GetLargePageMinimum) 8 | { 9 | if (const auto pfn = try_get_GetLargePageMinimum()) 10 | return pfn(); 11 | 12 | return 0; 13 | } 14 | } // namespace mingw_thunk 15 | -------------------------------------------------------------------------------- /support/thunk/src/5.2/kernel32/NeedCurrentDirectoryForExePathA.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_THUNK(kernel32, 9 | 4, 10 | BOOL, 11 | WINAPI, 12 | NeedCurrentDirectoryForExePathA, 13 | _In_ LPCSTR ExeName) 14 | { 15 | if (const auto pfn = try_get_NeedCurrentDirectoryForExePathA()) 16 | return pfn(ExeName); 17 | 18 | // WONTFIX: DBCS can contain '\' in second byte. 19 | if (internal::strchr(ExeName, '\\')) 20 | return TRUE; 21 | 22 | char value[2]; 23 | return !GetEnvironmentVariableA( 24 | "NoDefaultCurrentDirectoryInExePath", value, 2); 25 | } 26 | } // namespace mingw_thunk 27 | -------------------------------------------------------------------------------- /support/thunk/src/5.2/kernel32/NeedCurrentDirectoryForExePathW.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_THUNK(kernel32, 9 | 4, 10 | BOOL, 11 | WINAPI, 12 | NeedCurrentDirectoryForExePathW, 13 | _In_ LPCWSTR ExeName) 14 | { 15 | if (const auto pfn = try_get_NeedCurrentDirectoryForExePathW()) 16 | return pfn(ExeName); 17 | 18 | if (internal::wcschr(ExeName, L'\\')) 19 | return TRUE; 20 | 21 | char value[2]; 22 | return !GetEnvironmentVariableA( 23 | "NoDefaultCurrentDirectoryInExePath", value, 2); 24 | } 25 | } // namespace mingw_thunk 26 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/bcrypt/BCryptGenRandom.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace mingw_thunk 12 | { 13 | __DEFINE_THUNK(bcrypt, 14 | 16, 15 | NTSTATUS, 16 | WINAPI, 17 | BCryptGenRandom, 18 | _In_opt_ BCRYPT_ALG_HANDLE hAlgorithm, 19 | _Out_writes_bytes_(_cbBuffer) PUCHAR pbBuffer, 20 | _In_ ULONG cbBuffer, 21 | _In_ ULONG dwFlags) 22 | { 23 | if (const auto pfn = try_get_BCryptGenRandom()) 24 | return pfn(hAlgorithm, pbBuffer, cbBuffer, dwFlags); 25 | 26 | if (!pbBuffer) 27 | return STATUS_INVALID_PARAMETER; 28 | 29 | // Unaligned buffer is rare, here we simply ignore it. 30 | 31 | constexpr size_t block_size = sizeof(uint32_t); 32 | const size_t blocks = cbBuffer / block_size; 33 | const size_t remainder = cbBuffer % block_size; 34 | 35 | uint32_t *buffer = reinterpret_cast(pbBuffer); 36 | 37 | for (size_t i = 0; i < blocks; ++i) 38 | buffer[i] = internal::rand(); 39 | 40 | if (remainder) { 41 | uint32_t value = internal::rand(); 42 | internal::memcpy(buffer + blocks, &value, remainder); 43 | } 44 | 45 | return STATUS_SUCCESS; 46 | } 47 | } // namespace mingw_thunk 48 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/kernel32/CancelIoEx.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | // YY-Thunks 1.1.6 8 | // Windows Vista [desktop apps | UWP apps] 9 | // Windows Server 2008 [desktop apps | UWP apps] 10 | __DEFINE_THUNK(kernel32, 11 | 8, 12 | BOOL, 13 | WINAPI, 14 | CancelIoEx, 15 | _In_ HANDLE hFile, 16 | _In_opt_ LPOVERLAPPED lpOverlapped) 17 | { 18 | if (auto pCancelIoEx = try_get_CancelIoEx()) { 19 | return pCancelIoEx(hFile, lpOverlapped); 20 | } 21 | 22 | // downlevel逻辑会把该文件所有IO动作给取消掉!凑合用吧。 23 | return CancelIo(hFile); 24 | } 25 | } // namespace mingw_thunk 26 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/kernel32/CreateSymbolicLinkA.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | // YY-Thunks 1.1.6 8 | // Windows Vista [desktop apps only] 9 | // Windows Server 2008[desktop apps only] 10 | __DEFINE_THUNK(kernel32, 11 | 12, 12 | BOOLEAN, 13 | APIENTRY, 14 | CreateSymbolicLinkA, 15 | _In_ LPCSTR lpSymlinkFileName, 16 | _In_ LPCSTR lpTargetFileName, 17 | _In_ DWORD dwFlags) 18 | { 19 | if (const auto pCreateSymbolicLinkA = try_get_CreateSymbolicLinkA()) { 20 | return pCreateSymbolicLinkA(lpSymlinkFileName, lpTargetFileName, dwFlags); 21 | } 22 | 23 | SetLastError(ERROR_INVALID_FUNCTION); 24 | 25 | return FALSE; 26 | } 27 | } // namespace mingw_thunk 28 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/kernel32/CreateSymbolicLinkW.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | // YY-Thunks 1.1.6 8 | // Windows Vista [desktop apps only] 9 | // Windows Server 2008[desktop apps only] 10 | __DEFINE_THUNK(kernel32, 11 | 12, 12 | BOOLEAN, 13 | APIENTRY, 14 | CreateSymbolicLinkW, 15 | _In_ LPCWSTR lpSymlinkFileName, 16 | _In_ LPCWSTR lpTargetFileName, 17 | _In_ DWORD dwFlags) 18 | { 19 | if (const auto pCreateSymbolicLinkW = try_get_CreateSymbolicLinkW()) { 20 | return pCreateSymbolicLinkW(lpSymlinkFileName, lpTargetFileName, dwFlags); 21 | } 22 | 23 | SetLastError(ERROR_INVALID_FUNCTION); 24 | 25 | return FALSE; 26 | } 27 | } // namespace mingw_thunk 28 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/kernel32/CreateWaitableTimerExW.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | // YY-Thunks 1.1.6 8 | // Windows Vista [desktop apps | UWP apps] 9 | // Windows Server 2008 [desktop apps | UWP apps] 10 | __DEFINE_THUNK(kernel32, 11 | 16, 12 | HANDLE, 13 | WINAPI, 14 | CreateWaitableTimerExW, 15 | _In_opt_ LPSECURITY_ATTRIBUTES lpTimerAttributes, 16 | _In_opt_ LPCWSTR lpTimerName, 17 | _In_ DWORD dwFlags, 18 | _In_ DWORD dwDesiredAccess) 19 | { 20 | if (auto pCreateWaitableTimerExW = try_get_CreateWaitableTimerExW()) { 21 | return pCreateWaitableTimerExW( 22 | lpTimerAttributes, lpTimerName, dwFlags, dwDesiredAccess); 23 | } 24 | 25 | return CreateWaitableTimerW(lpTimerAttributes, 26 | dwFlags & CREATE_WAITABLE_TIMER_MANUAL_RESET, 27 | lpTimerName); 28 | } 29 | } // namespace mingw_thunk 30 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/kernel32/DeleteProcThreadAttributeList.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_THUNK(kernel32, 9 | 4, 10 | VOID, 11 | WINAPI, 12 | DeleteProcThreadAttributeList, 13 | _Inout_ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList) 14 | { 15 | if (const auto pfn = try_get_DeleteProcThreadAttributeList()) 16 | return pfn(lpAttributeList); 17 | } 18 | } // namespace mingw_thunk 19 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/kernel32/GetFinalPathNameByHandleW.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace mingw_thunk 9 | { 10 | __DEFINE_THUNK(kernel32, 11 | 16, 12 | DWORD, 13 | WINAPI, 14 | GetFinalPathNameByHandleW, 15 | _In_ HANDLE hFile, 16 | _Out_writes_(cchFilePath) LPWSTR lpszFilePath, 17 | _In_ DWORD cchFilePath, 18 | _In_ DWORD dwFlags) 19 | { 20 | if (const auto pfn = try_get_GetFinalPathNameByHandleW()) 21 | return pfn(hFile, lpszFilePath, cchFilePath, dwFlags); 22 | 23 | // This function is widely used to implement 'realpath'. 24 | // Simply fail, let the caller try fallback methods. 25 | SetLastError(ERROR_NOT_SUPPORTED); 26 | return 0; 27 | } 28 | } // namespace mingw_thunk 29 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/kernel32/GetTickCount64.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | __DEFINE_THUNK(kernel32, 0, ULONGLONG, WINAPI, GetTickCount64) 8 | { 9 | if (const auto pfn = try_get_GetTickCount64()) 10 | return pfn(); 11 | 12 | return GetTickCount(); 13 | } 14 | } // namespace mingw_thunk 15 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/kernel32/InitializeProcThreadAttributeList.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_THUNK(kernel32, 9 | 16, 10 | BOOL, 11 | WINAPI, 12 | InitializeProcThreadAttributeList, 13 | _Out_opt_ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, 14 | _In_ DWORD dwAttributeCount, 15 | DWORD dwFlags, 16 | _Inout_ PSIZE_T lpSize) 17 | { 18 | if (const auto pfn = try_get_InitializeProcThreadAttributeList()) 19 | return pfn(lpAttributeList, dwAttributeCount, dwFlags, lpSize); 20 | 21 | SetLastError(ERROR_NOT_SUPPORTED); 22 | return FALSE; 23 | } 24 | } // namespace mingw_thunk 25 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/kernel32/LCMapStringEx.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | // YY-Thunks 1.1.6 8 | // Minimum supported client Windows Vista [desktop apps | UWP apps] 9 | // Minimum supported server Windows Server 2008 [desktop apps | UWP apps] 10 | __DEFINE_THUNK(kernel32, 11 | 36, 12 | int, 13 | WINAPI, 14 | LCMapStringEx, 15 | _In_opt_ LPCWSTR lpLocaleName, 16 | _In_ DWORD dwMapFlags, 17 | _In_reads_(cchSrc) LPCWSTR lpSrcStr, 18 | _In_ int cchSrc, 19 | _Out_writes_opt_(cchDest) LPWSTR lpDestStr, 20 | _In_ int cchDest, 21 | _In_opt_ LPNLSVERSIONINFO lpVersionInformation, 22 | _In_opt_ LPVOID lpReserved, 23 | _In_opt_ LPARAM sortHandle) 24 | { 25 | if (const auto pLCMapStringEx = try_get_LCMapStringEx()) { 26 | return pLCMapStringEx(lpLocaleName, 27 | dwMapFlags, 28 | lpSrcStr, 29 | cchSrc, 30 | lpDestStr, 31 | cchDest, 32 | lpVersionInformation, 33 | lpReserved, 34 | sortHandle); 35 | } 36 | 37 | auto Locale = LocaleNameToLCID(lpLocaleName, 0); 38 | 39 | if (Locale == 0) { 40 | SetLastError(ERROR_INVALID_PARAMETER); 41 | return 0; 42 | } 43 | 44 | return LCMapStringW( 45 | Locale, dwMapFlags, lpSrcStr, cchSrc, lpDestStr, cchDest); 46 | } 47 | } // namespace mingw_thunk 48 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/kernel32/UpdateProcThreadAttribute.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | __DEFINE_THUNK(kernel32, 9 | 28, 10 | BOOL, 11 | WINAPI, 12 | UpdateProcThreadAttribute, 13 | _Inout_ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, 14 | _In_ DWORD dwFlags, 15 | _In_ DWORD_PTR Attribute, 16 | _In_ PVOID lpValue, 17 | _In_ SIZE_T cbSize, 18 | _Out_opt_ PVOID lpPreviousValue, 19 | _In_opt_ PSIZE_T lpReturnSize) 20 | { 21 | if (const auto pfn = try_get_UpdateProcThreadAttribute()) 22 | return pfn(lpAttributeList, 23 | dwFlags, 24 | Attribute, 25 | lpValue, 26 | cbSize, 27 | lpPreviousValue, 28 | lpReturnSize); 29 | 30 | SetLastError(ERROR_NOT_SUPPORTED); 31 | return FALSE; 32 | } 33 | } // namespace mingw_thunk 34 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/msvcrt/_wputenv_s.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace mingw_thunk 10 | { 11 | __DEFINE_CRT_THUNK(errno_t, 12 | _wputenv_s, 13 | const wchar_t *varname, 14 | const wchar_t *value_string) 15 | { 16 | if (const auto pfn = try_get__wputenv_s()) 17 | return pfn(varname, value_string); 18 | 19 | if (!varname || !value_string) { 20 | _set_errno(EINVAL); 21 | return EINVAL; 22 | } 23 | 24 | if (!SetEnvironmentVariableW(varname, value_string)) 25 | return internal::dosmaperr(); 26 | 27 | return 0; 28 | } 29 | } // namespace mingw_thunk 30 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/msvcrt/_wputenv_s.test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | TEST_CASE("_wputenv_s") 7 | { 8 | const auto &name = L"TEST_ENVIRONMENT"; 9 | const auto &value = L"TEST_VALUE"; 10 | 11 | SECTION("normal case") 12 | { 13 | CLEAR_TOUCH_FLAG(); 14 | errno_t err = _wputenv_s(name, value); 15 | REQUIRE_TOUCHED(); 16 | 17 | REQUIRE(err == 0); 18 | } 19 | 20 | SECTION("error: null name") 21 | { 22 | errno_t err = _wputenv_s(nullptr, value); 23 | 24 | REQUIRE(err == EINVAL); 25 | } 26 | 27 | SECTION("error: null value") 28 | { 29 | errno_t err = _wputenv_s(name, nullptr); 30 | 31 | REQUIRE(err == EINVAL); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/msvcrt/wcscat_s.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace mingw_thunk 9 | { 10 | __DEFINE_CRT_THUNK(errno_t, 11 | wcscat_s, 12 | wchar_t *strDestination, 13 | size_t numberOfElements, 14 | const wchar_t *strSource) 15 | { 16 | if (const auto pfn = try_get_wcscat_s()) 17 | return pfn(strDestination, numberOfElements, strSource); 18 | 19 | constexpr size_t rsize_max = SIZE_MAX >> 1; 20 | constexpr size_t max_len = rsize_max / sizeof(wchar_t); 21 | 22 | if (!strDestination || !numberOfElements || numberOfElements >= max_len) { 23 | _set_errno(EINVAL); 24 | return EINVAL; 25 | } 26 | 27 | if (!strSource) { 28 | *strDestination = 0; 29 | _set_errno(EINVAL); 30 | return EINVAL; 31 | } 32 | 33 | size_t dest_len = internal::wcsnlen(strDestination, numberOfElements); 34 | if (dest_len >= numberOfElements) { 35 | *strDestination = 0; 36 | _set_errno(EINVAL); 37 | return EINVAL; 38 | } 39 | 40 | int err = wcscpy_s( 41 | strDestination + dest_len, numberOfElements - dest_len, strSource); 42 | if (err) 43 | *strDestination = 0; 44 | return err; 45 | } 46 | } // namespace mingw_thunk 47 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/msvcrt/wcscat_s.test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | constexpr size_t rsize_max = SIZE_MAX >> 1; 9 | 10 | TEST_CASE("wcscat_s") 11 | { 12 | const wchar_t str1[] = L"hello"; 13 | constexpr size_t str1_len = std::size(str1) - 1; 14 | 15 | const wchar_t str2[] = L"world"; 16 | constexpr size_t str2_len = std::size(str2) - 1; 17 | 18 | const wchar_t *result = L"helloworld"; 19 | 20 | constexpr size_t N = 16; 21 | wchar_t dest[N]; 22 | 23 | auto fill_dest = [&]() { memcpy(dest, str1, sizeof(str1)); }; 24 | 25 | SECTION("normal case") 26 | { 27 | fill_dest(); 28 | 29 | CLEAR_TOUCH_FLAG(); 30 | errno_t err = wcscat_s(dest, N, str2); 31 | REQUIRE_TOUCHED(); 32 | 33 | REQUIRE(err == 0); 34 | REQUIRE(wcscmp(dest, result) == 0); 35 | } 36 | 37 | SECTION("boundary case") 38 | { 39 | fill_dest(); 40 | errno_t err = wcscat_s(dest, str1_len + str2_len, str2); 41 | REQUIRE(err == ERANGE); 42 | REQUIRE(wcscmp(dest, L"") == 0); 43 | 44 | fill_dest(); 45 | err = wcscat_s(dest, str1_len + str2_len + 1, str2); 46 | REQUIRE(err == 0); 47 | REQUIRE(wcscmp(dest, result) == 0); 48 | } 49 | 50 | SECTION("error: null src") 51 | { 52 | fill_dest(); 53 | errno_t err = wcscat_s(dest, N, nullptr); 54 | REQUIRE(err == EINVAL); 55 | REQUIRE(wcscmp(dest, L"") == 0); 56 | } 57 | 58 | SECTION("error: null dest") 59 | { 60 | errno_t err = wcscat_s(nullptr, N, str2); 61 | REQUIRE(err == EINVAL); 62 | } 63 | 64 | SECTION("error: dest size is 0") 65 | { 66 | dest[0] = 1; 67 | errno_t err = wcscat_s(dest, 0, str2); 68 | REQUIRE(err == EINVAL); 69 | // ISO C semantic (Microsoft say 0) 70 | REQUIRE(dest[0] == 1); 71 | } 72 | 73 | SECTION("error: dest size too large") 74 | { 75 | dest[0] = 1; 76 | // ISO C semantic (Microsoft say OK) 77 | errno_t err = wcscat_s(dest, rsize_max, str2); 78 | REQUIRE(err == EINVAL); 79 | REQUIRE(dest[0] == 1); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/msvcrt/wcscpy_s.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace mingw_thunk 10 | { 11 | __DEFINE_CRT_THUNK( 12 | errno_t, wcscpy_s, wchar_t *dest, rsize_t dest_size, const wchar_t *src) 13 | { 14 | if (const auto pfn = try_get_wcscpy_s()) 15 | return pfn(dest, dest_size, src); 16 | 17 | constexpr size_t rsize_max = SIZE_MAX >> 1; 18 | constexpr size_t max_len = rsize_max / sizeof(wchar_t); 19 | 20 | if (!dest || !dest_size || dest_size >= max_len) { 21 | _set_errno(EINVAL); 22 | return EINVAL; 23 | } 24 | 25 | if (!src) { 26 | *dest = 0; 27 | _set_errno(EINVAL); 28 | return EINVAL; 29 | } 30 | 31 | size_t len = internal::wcsnlen(src, dest_size); 32 | 33 | if (len >= dest_size) { 34 | *dest = 0; 35 | _set_errno(ERANGE); 36 | return ERANGE; 37 | } 38 | 39 | internal::memcpy(dest, src, len * sizeof(wchar_t)); 40 | dest[len] = 0; 41 | return 0; 42 | } 43 | } // namespace mingw_thunk 44 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/msvcrt/wcscpy_s.test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | constexpr size_t rsize_max = SIZE_MAX >> 1; 8 | 9 | TEST_CASE("wcscpy_s") 10 | { 11 | const wchar_t src[] = L"hello"; 12 | constexpr size_t src_len = std::size(src) - 1; 13 | 14 | constexpr size_t N = 16; 15 | wchar_t dest[N]; 16 | 17 | SECTION("normal case") 18 | { 19 | CLEAR_TOUCH_FLAG(); 20 | errno_t err = wcscpy_s(dest, N, src); 21 | REQUIRE_TOUCHED(); 22 | 23 | REQUIRE(err == 0); 24 | REQUIRE(wcscmp(dest, src) == 0); 25 | } 26 | 27 | SECTION("boundary case") 28 | { 29 | dest[0] = 1; 30 | errno_t err = wcscpy_s(dest, src_len, src); 31 | REQUIRE(err == ERANGE); 32 | REQUIRE(wcscmp(dest, L"") == 0); 33 | 34 | err = wcscpy_s(dest, src_len + 1, src); 35 | REQUIRE(err == 0); 36 | REQUIRE(wcscmp(dest, src) == 0); 37 | } 38 | 39 | SECTION("error: null src") 40 | { 41 | dest[0] = 1; 42 | errno_t err = wcscpy_s(dest, N, nullptr); 43 | REQUIRE(err == EINVAL); 44 | REQUIRE(wcscmp(dest, L"") == 0); 45 | } 46 | 47 | SECTION("error: null dest") 48 | { 49 | errno_t err = wcscpy_s(nullptr, N, src); 50 | REQUIRE(err == EINVAL); 51 | } 52 | 53 | SECTION("error: dest size is 0") 54 | { 55 | dest[0] = 1; 56 | errno_t err = wcscpy_s(dest, 0, src); 57 | REQUIRE(err == EINVAL); 58 | // ISO C semantic (Microsoft say dest[0] == 0) 59 | REQUIRE(dest[0] == 1); 60 | } 61 | 62 | SECTION("error: dest size too large") 63 | { 64 | dest[0] = 1; 65 | // ISO C semantic (Microsoft say OK) 66 | errno_t err = wcscpy_s(dest, rsize_max, src); 67 | REQUIRE(err == EINVAL); 68 | REQUIRE(dest[0] == 1); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/msvcrt/wcsncat_s.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace mingw_thunk 9 | { 10 | __DEFINE_CRT_THUNK(errno_t, 11 | wcsncat_s, 12 | wchar_t *strDest, 13 | size_t numberOfElements, 14 | const wchar_t *strSource, 15 | size_t count) 16 | { 17 | if (const auto pfn = try_get_wcsncat_s()) 18 | return pfn(strDest, numberOfElements, strSource, count); 19 | 20 | constexpr size_t rsize_max = SIZE_MAX >> 1; 21 | constexpr size_t max_len = rsize_max / sizeof(wchar_t); 22 | 23 | if (!strDest || !numberOfElements || numberOfElements >= max_len) { 24 | _set_errno(EINVAL); 25 | return EINVAL; 26 | } 27 | 28 | if (!strSource || !count || count >= max_len || 29 | // overlap 30 | (strDest <= strSource && strDest + numberOfElements > strSource) || 31 | (strSource <= strDest && strSource + count > strDest)) { 32 | *strDest = 0; 33 | _set_errno(EINVAL); 34 | return EINVAL; 35 | } 36 | 37 | size_t dest_len = internal::wcsnlen(strDest, numberOfElements); 38 | if (dest_len >= numberOfElements) { 39 | *strDest = 0; 40 | _set_errno(EINVAL); 41 | return EINVAL; 42 | } 43 | 44 | int err = wcsncpy_s( 45 | strDest + dest_len, numberOfElements - dest_len, strSource, count); 46 | if (err) 47 | *strDest = 0; 48 | return err; 49 | } 50 | } // namespace mingw_thunk 51 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/msvcrt/wcsncpy_s.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace mingw_thunk 10 | { 11 | __DEFINE_CRT_THUNK(errno_t, 12 | wcsncpy_s, 13 | wchar_t *strDest, 14 | size_t numberOfElements, 15 | const wchar_t *strSource, 16 | size_t count) 17 | { 18 | if (const auto pfn = try_get_wcsncpy_s()) 19 | return pfn(strDest, numberOfElements, strSource, count); 20 | 21 | constexpr size_t rsize_max = SIZE_MAX >> 1; 22 | constexpr size_t max_len = rsize_max / sizeof(wchar_t); 23 | 24 | if (!strDest || !numberOfElements || numberOfElements >= rsize_max) { 25 | _set_errno(EINVAL); 26 | return EINVAL; 27 | } 28 | 29 | if (!strSource || !count || count >= rsize_max || 30 | // overlap 31 | (strDest <= strSource && strDest + numberOfElements > strSource) || 32 | (strSource <= strDest && strSource + count > strDest)) { 33 | *strDest = 0; 34 | _set_errno(EINVAL); 35 | return EINVAL; 36 | } 37 | 38 | size_t len = internal::wcsnlen(strSource, count); 39 | 40 | if (len >= numberOfElements) { 41 | *strDest = 0; 42 | _set_errno(ERANGE); 43 | return ERANGE; 44 | } 45 | 46 | internal::memcpy(strDest, strSource, len * sizeof(wchar_t)); 47 | strDest[len] = 0; 48 | return 0; 49 | } 50 | } // namespace mingw_thunk 51 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/msvcrt/wcsncpy_s.test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | constexpr size_t rsize_max = SIZE_MAX >> 1; 8 | 9 | TEST_CASE("wcsncpy_s") 10 | { 11 | const wchar_t src[] = L"hello"; 12 | constexpr size_t src_len = std::size(src) - 1; 13 | 14 | constexpr size_t N = 16; 15 | wchar_t dest[N]; 16 | 17 | SECTION("normal case") 18 | { 19 | CLEAR_TOUCH_FLAG(); 20 | errno_t err = wcsncpy_s(dest, N, src, src_len); 21 | REQUIRE_TOUCHED(); 22 | 23 | REQUIRE(err == 0); 24 | REQUIRE(wcscmp(dest, src) == 0); 25 | } 26 | 27 | SECTION("boundary case") 28 | { 29 | dest[0] = 1; 30 | errno_t err = wcsncpy_s(dest, src_len, src, src_len); 31 | REQUIRE(err == ERANGE); 32 | REQUIRE(wcscmp(dest, L"") == 0); 33 | 34 | err = wcsncpy_s(dest, src_len + 1, src, src_len); 35 | REQUIRE(err == 0); 36 | REQUIRE(wcscmp(dest, src) == 0); 37 | 38 | err = wcsncpy_s(dest, src_len + 1, src, src_len + 1); 39 | REQUIRE(err == 0); 40 | REQUIRE(wcscmp(dest, src) == 0); 41 | } 42 | 43 | SECTION("error: null src") 44 | { 45 | dest[0] = 1; 46 | errno_t err = wcsncpy_s(dest, N, nullptr, src_len); 47 | REQUIRE(err == EINVAL); 48 | REQUIRE(wcscmp(dest, L"") == 0); 49 | } 50 | 51 | SECTION("error: null dest") 52 | { 53 | errno_t err = wcsncpy_s(nullptr, N, src, src_len); 54 | REQUIRE(err == EINVAL); 55 | } 56 | 57 | SECTION("error: dest size is 0") 58 | { 59 | dest[0] = 1; 60 | errno_t err = wcsncpy_s(dest, 0, src, src_len); 61 | REQUIRE(err == EINVAL); 62 | REQUIRE(dest[0] == 1); 63 | } 64 | 65 | SECTION("error: dest size too large") 66 | { 67 | dest[0] = 1; 68 | // ISO C semantic (Microsoft say OK) 69 | errno_t err = wcsncpy_s(dest, rsize_max, src, src_len); 70 | REQUIRE(err == EINVAL); 71 | REQUIRE(dest[0] == 1); 72 | } 73 | 74 | SECTION("error: src count is 0") 75 | { 76 | dest[0] = 1; 77 | // IOS C semantic (Microsoft say OK) 78 | errno_t err = wcsncpy_s(dest, N, src, 0); 79 | REQUIRE(err == EINVAL); 80 | REQUIRE(wcscmp(dest, L"") == 0); 81 | } 82 | 83 | SECTION("error: src count too large") 84 | { 85 | dest[0] = 1; 86 | // ISO C semantic (Microsoft say OK) 87 | errno_t err = wcsncpy_s(dest, N, src, rsize_max); 88 | REQUIRE(err == EINVAL); 89 | REQUIRE(wcscmp(dest, L"") == 0); 90 | } 91 | 92 | SECTION("error: overlap") 93 | { 94 | dest[0] = 1; 95 | // ISO C semantic (Microsoft say undefined) 96 | errno_t err = wcsncpy_s(dest, N, dest, src_len); 97 | REQUIRE(err == EINVAL); 98 | REQUIRE(wcscmp(dest, L"") == 0); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /support/thunk/src/6.0/msvcrt/wcstok_s.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | // mingw-w64 13 9 | __DEFINE_CRT_THUNK( 10 | wchar_t *, wcstok_s, wchar_t *s, const wchar_t *sep, wchar_t **p) 11 | { 12 | if (const auto pfn = try_get_wcstok_s()) 13 | return pfn(s, sep, p); 14 | 15 | if (!p || !sep) { 16 | errno = EINVAL; 17 | return NULL; 18 | } /* added for wcstok_s */ 19 | if (!s && !(s = *p)) { 20 | errno = EINVAL; 21 | return NULL; 22 | } 23 | s += wcsspn(s, sep); 24 | if (!*s) 25 | return *p = NULL; 26 | *p = s + wcscspn(s, sep); 27 | if (**p) 28 | *(*p)++ = 0; 29 | else 30 | *p = 0; 31 | return s; 32 | } 33 | } // namespace mingw_thunk 34 | -------------------------------------------------------------------------------- /support/thunk/src/6.1/kernel32/GetActiveProcessorCount.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | // YY-Thunks 1.1.6 9 | // Minimum supported client Windows 7 [desktop apps only] 10 | // Minimum supported server Windows Server 2008 R2 [desktop apps only] 11 | __DEFINE_THUNK(kernel32, 12 | 4, 13 | DWORD, 14 | WINAPI, 15 | GetActiveProcessorCount, 16 | _In_ WORD GroupNumber) 17 | { 18 | if (auto pGetActiveProcessorCount = try_get_GetActiveProcessorCount()) { 19 | return pGetActiveProcessorCount(GroupNumber); 20 | } 21 | 22 | return Downlevel::GetProcessorCount(GroupNumber); 23 | } 24 | } // namespace mingw_thunk 25 | -------------------------------------------------------------------------------- /support/thunk/src/6.1/kernel32/GetActiveProcessorGroupCount.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | // YY-Thunks 1.1.6 8 | // Minimum supported client Windows 7 [desktop apps only] 9 | // Minimum supported server Windows Server 2008 R2 [desktop apps only] 10 | __DEFINE_THUNK(kernel32, 0, WORD, WINAPI, GetActiveProcessorGroupCount, VOID) 11 | { 12 | if (auto pGetActiveProcessorGroupCount = 13 | try_get_GetActiveProcessorGroupCount()) { 14 | return pGetActiveProcessorGroupCount(); 15 | } 16 | 17 | // 我们统一假定只有一组,事实也如此。 18 | return 1; 19 | } 20 | } // namespace mingw_thunk 21 | -------------------------------------------------------------------------------- /support/thunk/src/6.1/kernel32/GetMaximumProcessorCount.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | // YY-Thunks 1.1.6 9 | // Minimum supported client Windows 7 [desktop apps only] 10 | // Minimum supported server Windows Server 2008 R2 [desktop apps only] 11 | __DEFINE_THUNK(kernel32, 12 | 4, 13 | DWORD, 14 | WINAPI, 15 | GetMaximumProcessorCount, 16 | _In_ WORD GroupNumber) 17 | { 18 | if (auto pGetMaximumProcessorCount = try_get_GetMaximumProcessorCount()) { 19 | return pGetMaximumProcessorCount(GroupNumber); 20 | } 21 | 22 | return Downlevel::GetProcessorCount(GroupNumber); 23 | } 24 | } // namespace mingw_thunk 25 | -------------------------------------------------------------------------------- /support/thunk/src/6.1/kernel32/GetMaximumProcessorGroupCount.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | // YY-Thunks 1.1.6 8 | // Minimum supported client Windows 7 [desktop apps only] 9 | // Minimum supported server Windows Server 2008 R2 [desktop apps only] 10 | __DEFINE_THUNK(kernel32, 0, WORD, WINAPI, GetMaximumProcessorGroupCount, VOID) 11 | { 12 | if (auto pGetMaximumProcessorGroupCount = 13 | try_get_GetMaximumProcessorGroupCount()) { 14 | return pGetMaximumProcessorGroupCount(); 15 | } 16 | 17 | // 我们统一假定只有一组,事实也如此。 18 | return 1; 19 | } 20 | } // namespace mingw_thunk 21 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathAllocCanonicalize.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | // YY-Thunks 1.1.6 9 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 10 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 11 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 12 | 12, 13 | HRESULT, 14 | WINAPI, 15 | PathAllocCanonicalize, 16 | _In_ PCWSTR pszPathIn, 17 | _In_ ULONG dwFlags, 18 | _Outptr_ PWSTR *ppszPathOut) 19 | { 20 | if (const auto pPathAllocCanonicalize = try_get_PathAllocCanonicalize()) { 21 | return pPathAllocCanonicalize(pszPathIn, dwFlags, ppszPathOut); 22 | } 23 | 24 | // 参数检查 25 | if (ppszPathOut == nullptr) 26 | return E_INVALIDARG; 27 | 28 | *ppszPathOut = nullptr; 29 | 30 | auto cchBufferSize = pszPathIn ? wcslen(pszPathIn) : 0; 31 | 32 | if (cchBufferSize >= PATHCCH_MAX_CCH) 33 | return __HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE); 34 | 35 | if (cchBufferSize) { 36 | ++cchBufferSize; 37 | } else { 38 | // "\\\0" 39 | cchBufferSize = 2; 40 | } 41 | 42 | if (cchBufferSize > MAX_PATH && (dwFlags & PATHCCH_ALLOW_LONG_PATHS)) { 43 | //"\\\\?\\UNC\0" 44 | cchBufferSize += 6; 45 | } 46 | 47 | // 保证边界依然在 最大值内 48 | const unsigned cchMaxPath = 49 | (dwFlags & PATHCCH_ALLOW_LONG_PATHS) ? PATHCCH_MAX_CCH : MAX_PATH; 50 | if (cchBufferSize > cchMaxPath) 51 | cchBufferSize = cchMaxPath; 52 | 53 | auto pBuffer = 54 | (wchar_t *)LocalAlloc(LMEM_ZEROINIT, sizeof(wchar_t) * cchBufferSize); 55 | 56 | if (pBuffer == nullptr) 57 | return E_OUTOFMEMORY; 58 | 59 | auto hr = PathCchCanonicalizeEx(pBuffer, cchBufferSize, pszPathIn, dwFlags); 60 | 61 | if (FAILED(hr)) { 62 | LocalFree(pBuffer); 63 | return hr; 64 | } 65 | 66 | *ppszPathOut = pBuffer; 67 | 68 | return hr; 69 | } 70 | } // namespace mingw_thunk 71 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathAllocCombine.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | // YY-Thunks 1.1.6 9 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 10 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 11 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 12 | 16, 13 | HRESULT, 14 | WINAPI, 15 | PathAllocCombine, 16 | _In_opt_ PCWSTR pszPathIn, 17 | _In_opt_ PCWSTR pszMore, 18 | _In_ ULONG dwFlags, 19 | _Outptr_ PWSTR *ppszPathOut) 20 | { 21 | if (const auto pPathAllocCombine = try_get_PathAllocCombine()) { 22 | return pPathAllocCombine(pszPathIn, pszMore, dwFlags, ppszPathOut); 23 | } 24 | 25 | // 参数检查 26 | if (ppszPathOut == nullptr) 27 | return E_INVALIDARG; 28 | 29 | *ppszPathOut = nullptr; 30 | 31 | // 不能同时为 null 32 | if (pszPathIn == nullptr && pszMore == nullptr) 33 | return E_INVALIDARG; 34 | 35 | size_t cchPathIn = pszPathIn ? wcslen(pszPathIn) : 0; 36 | 37 | if (cchPathIn >= PATHCCH_MAX_CCH) 38 | return __HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE); 39 | 40 | if (cchPathIn) 41 | ++cchPathIn; 42 | 43 | size_t cchMore = pszMore ? wcslen(pszMore) : 0; 44 | 45 | if (cchMore >= PATHCCH_MAX_CCH) 46 | return __HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE); 47 | 48 | if (cchMore) 49 | ++cchMore; 50 | 51 | auto cchBufferSize = cchPathIn + cchMore; 52 | 53 | if (cchBufferSize == 0) { 54 | //"\\\0" 55 | cchBufferSize = 2; 56 | } else if (cchBufferSize > MAX_PATH && 57 | (dwFlags & PATHCCH_ALLOW_LONG_PATHS)) { 58 | //"\\\\?\\UNC\0" 59 | cchBufferSize += 6; 60 | } 61 | 62 | // 保证边界依然在 最大值内 63 | const unsigned cchMaxPath = 64 | (dwFlags & PATHCCH_ALLOW_LONG_PATHS) ? PATHCCH_MAX_CCH : MAX_PATH; 65 | if (cchBufferSize > cchMaxPath) 66 | cchBufferSize = cchMaxPath; 67 | 68 | auto pBuffer = 69 | (wchar_t *)LocalAlloc(LMEM_ZEROINIT, sizeof(wchar_t) * cchBufferSize); 70 | 71 | if (pBuffer == nullptr) 72 | return E_OUTOFMEMORY; 73 | 74 | auto hr = 75 | PathCchCombineEx(pBuffer, cchBufferSize, pszPathIn, pszMore, dwFlags); 76 | 77 | if (FAILED(hr)) { 78 | LocalFree(pBuffer); 79 | return hr; 80 | } 81 | 82 | *ppszPathOut = pBuffer; 83 | 84 | return hr; 85 | } 86 | } // namespace mingw_thunk 87 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathCchAddBackslash.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | // YY-Thunk 1.1.6 9 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 10 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 11 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 12 | 8, 13 | HRESULT, 14 | WINAPI, 15 | PathCchAddBackslash, 16 | _Inout_updates_(cchPath) PWSTR pszPath, 17 | _In_ size_t cchPath) 18 | { 19 | return PathCchAddBackslashEx(pszPath, cchPath, nullptr, nullptr); 20 | } 21 | } // namespace mingw_thunk 22 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathCchAddBackslashEx.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | namespace mingw_thunk 8 | { 9 | // YY-Thunk 1.1.6 10 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 11 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 12 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 13 | 16, 14 | HRESULT, 15 | WINAPI, 16 | PathCchAddBackslashEx, 17 | _Inout_updates_(cchPath) PWSTR pszPath, 18 | _In_ size_t cchPath, 19 | _Outptr_opt_result_buffer_(*pcchRemaining) PWSTR *ppszEnd, 20 | _Out_opt_ size_t *pcchRemaining) 21 | { 22 | if (ppszEnd) 23 | *ppszEnd = nullptr; 24 | 25 | if (pcchRemaining) 26 | *pcchRemaining = 0; 27 | 28 | auto nLength = internal::wcslen(pszPath); 29 | 30 | HRESULT hr; 31 | 32 | do { 33 | if (nLength >= cchPath) { 34 | hr = __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); 35 | break; 36 | } 37 | 38 | if (nLength && pszPath[nLength - 1] != L'\\') { 39 | // 末尾不是 '\\' 所以我们添加 一个 '\\' 微软原版这里用了 40 | // StringCchCopyExW,但是我觉得这没有必要。 41 | 42 | ++nLength; 43 | if (nLength >= cchPath) { 44 | hr = __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); 45 | break; 46 | } 47 | 48 | pszPath[nLength - 1] = L'\\'; 49 | pszPath[nLength] = L'\0'; 50 | 51 | hr = S_OK; 52 | } else { 53 | hr = S_FALSE; 54 | } 55 | 56 | if (ppszEnd) 57 | *ppszEnd = pszPath + nLength; 58 | 59 | if (pcchRemaining) 60 | *pcchRemaining = cchPath - nLength; 61 | 62 | } while (false); 63 | 64 | return hr; 65 | } 66 | } // namespace mingw_thunk 67 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathCchAddExtension.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace mingw_thunk 9 | { 10 | // YY-Thunks 1.1.6 11 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 12 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 13 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 14 | 12, 15 | HRESULT, 16 | WINAPI, 17 | PathCchAddExtension, 18 | _Inout_updates_(cchPath) PWSTR pszPath, 19 | _In_ size_t cchPath, 20 | _In_ PCWSTR pszExt) 21 | { 22 | if (pszPath == nullptr || cchPath == 0 || cchPath > PATHCCH_MAX_CCH || 23 | internal::IsValidExtensionWorker(pszExt) == false) { 24 | // loc_1009895F 25 | return E_INVALIDARG; 26 | } 27 | 28 | // 检测Unicode Path,如果不是,那么最多允许 260 29 | const auto bExtendedLengthDosDevicePath = 30 | internal::IsExtendedLengthDosDevicePath(pszPath); 31 | if (!bExtendedLengthDosDevicePath) { 32 | cchPath = internal::min(MAX_PATH, cchPath); 33 | } 34 | 35 | PWSTR pszPathExt; 36 | 37 | auto hr = PathCchFindExtension(pszPath, cchPath, (LPCWSTR *)&pszPathExt); 38 | 39 | if (FAILED(hr)) { 40 | return hr; 41 | } 42 | 43 | if (*pszPathExt != L'\0') { 44 | // 已经存在后缀,所以我们什么也不做。 45 | return S_FALSE; 46 | } 47 | 48 | if (*pszExt == L'.') 49 | ++pszExt; 50 | 51 | // 后缀是 "" 52 | if (*pszExt == L'\0') { 53 | return S_OK; 54 | } 55 | 56 | do { 57 | const auto szPathBufferEnd = pszPath + cchPath; 58 | auto szDest = pszPathExt; 59 | 60 | if (szDest >= szPathBufferEnd) 61 | break; 62 | 63 | *szDest = L'.'; 64 | ++szDest; 65 | 66 | for (; szDest < szPathBufferEnd; ++szDest, ++pszExt) { 67 | if ((*szDest = *pszExt) == L'\0') { 68 | return S_OK; 69 | } 70 | } 71 | 72 | } while (false); 73 | 74 | *pszPathExt = L'\0'; 75 | 76 | if (bExtendedLengthDosDevicePath) { 77 | if (cchPath != PATHCCH_MAX_CCH) { 78 | return __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); 79 | } 80 | } else { 81 | if (cchPath != MAX_PATH) { 82 | return __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); 83 | } 84 | } 85 | 86 | return __HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE); 87 | } 88 | } // namespace mingw_thunk 89 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathCchAppend.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | // YY-Thunks 1.1.6 9 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 10 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 11 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 12 | 12, 13 | HRESULT, 14 | WINAPI, 15 | PathCchAppend, 16 | _Inout_updates_(cchPath) PWSTR pszPath, 17 | _In_ size_t cchPath, 18 | _In_opt_ PCWSTR pszMore) 19 | { 20 | return PathCchAppendEx(pszPath, cchPath, pszMore, 0); 21 | } 22 | } // namespace mingw_thunk 23 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathCchAppendEx.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | namespace mingw_thunk 8 | { 9 | // YY-Thunks 1.1.6 10 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 11 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 12 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 13 | 16, 14 | HRESULT, 15 | WINAPI, 16 | PathCchAppendEx, 17 | _Inout_updates_(cchPath) PWSTR pszPath, 18 | _In_ size_t cchPath, 19 | _In_opt_ PCWSTR pszMore, 20 | _In_ ULONG dwFlags) 21 | { 22 | if (pszMore && PathIsUNCEx(pszMore, nullptr) == false && 23 | internal::IsExtendedLengthDosDevicePath(pszMore) == false) { 24 | // 跳过开头的所有 '\\' 25 | for (; *pszMore == L'\\'; ++pszMore) 26 | ; 27 | } 28 | 29 | return PathCchCombineEx(pszPath, cchPath, pszPath, pszMore, dwFlags); 30 | } 31 | } // namespace mingw_thunk 32 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathCchCanonicalize.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | // YY-Thunks 1.1.6 9 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 10 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 11 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 12 | 12, 13 | HRESULT, 14 | WINAPI, 15 | PathCchCanonicalize, 16 | _Out_writes_(cchPathOut) PWSTR pszPathOut, 17 | _In_ size_t cchPathOut, 18 | _In_ PCWSTR pszPathIn) 19 | { 20 | return PathCchCanonicalizeEx(pszPathOut, cchPathOut, pszPathIn, 0); 21 | } 22 | } // namespace mingw_thunk 23 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathCchCombine.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | // YY-Thunks 1.1.6 8 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 9 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 10 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 11 | 16, 12 | HRESULT, 13 | WINAPI, 14 | PathCchCombine, 15 | _Out_writes_(cchPathOut) PWSTR pszPathOut, 16 | _In_ size_t cchPathOut, 17 | _In_opt_ PCWSTR pszPathIn, 18 | _In_opt_ PCWSTR pszMore) 19 | { 20 | return PathCchCombineEx(pszPathOut, cchPathOut, pszPathIn, pszMore, 0); 21 | } 22 | } // namespace mingw_thunk 23 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathCchFindExtension.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | // YY-Thunks 1.1.6 9 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 10 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 11 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 12 | 12, 13 | HRESULT, 14 | WINAPI, 15 | PathCchFindExtension, 16 | _In_reads_(_Inexpressible_(cchPath)) PCWSTR pszPath, 17 | _In_ size_t cchPath, 18 | _Outptr_ PCWSTR *ppszExt) 19 | { 20 | if (ppszExt == nullptr) 21 | return E_INVALIDARG; 22 | 23 | *ppszExt = nullptr; 24 | 25 | if (pszPath == nullptr || cchPath == 0 || cchPath > PATHCCH_MAX_CCH) { 26 | return E_INVALIDARG; 27 | } 28 | 29 | const auto szPathBufferEnd = pszPath + cchPath; 30 | PCWSTR pszExt = nullptr; 31 | 32 | for (; *pszPath; ++pszPath) { 33 | if (pszPath >= szPathBufferEnd) 34 | return E_INVALIDARG; 35 | 36 | switch (*pszPath) { 37 | case L'\\': 38 | case L' ': 39 | pszExt = nullptr; 40 | break; 41 | case L'.': 42 | pszExt = pszPath; 43 | break; 44 | default: 45 | break; 46 | } 47 | } 48 | 49 | *ppszExt = pszExt ? pszExt : pszPath; 50 | 51 | return S_OK; 52 | } 53 | } // namespace mingw_thunk 54 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathCchIsRoot.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | // YY-Thunk 1.1.6 9 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 10 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 11 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 12 | 4, 13 | BOOL, 14 | WINAPI, 15 | PathCchIsRoot, 16 | _In_opt_ PCWSTR pszPath) 17 | { 18 | // NULL or "" 19 | if (pszPath == nullptr || pszPath[0] == L'\0') 20 | return FALSE; 21 | 22 | // "C:\\" 形式 23 | if (((L'A' <= pszPath[0] && pszPath[0] <= L'Z') || 24 | (L'a' <= pszPath[0] && pszPath[0] <= L'z')) // iswalpha(pszPath[0]) 25 | && pszPath[1] == L':' && pszPath[2] == L'\\' && pszPath[3] == L'\0') { 26 | return TRUE; 27 | } 28 | 29 | // "\\" 形式 30 | if (pszPath[0] == L'\\' && pszPath[1] == L'\0') { 31 | return TRUE; 32 | } 33 | 34 | /* 35 | * "\\\path1\\path2" 36 | * "\\\\path1" 37 | * "\\\\?\\UNC\\path1\\path2" 38 | * "\\\\?\\UNC\\path1" 39 | */ 40 | PCWSTR pszServer; 41 | if (PathIsUNCEx(pszPath, &pszServer)) { 42 | DWORD nSeparatorsCount = 0; 43 | 44 | for (; *pszServer; ++pszServer) { 45 | if (*pszServer == L'\\') { 46 | ++nSeparatorsCount; 47 | 48 | if (nSeparatorsCount > 1 || pszServer[1] == L'\0') 49 | return FALSE; 50 | } 51 | } 52 | 53 | return TRUE; 54 | } 55 | 56 | /* 57 | * "\\\\?\\C:\\" 58 | * "\\\\?\\Volume{guid}\\" 59 | */ 60 | 61 | if (pszPath[0] == L'\\' && pszPath[1] == L'\\' && pszPath[2] == L'?' && 62 | pszPath[3] == L'\\') { 63 | // "\\\\?\\C:\\" 64 | if (((L'A' <= pszPath[4] && pszPath[4] <= L'Z') || 65 | (L'a' <= pszPath[4] && pszPath[4] <= L'z')) // iswalpha(pszPath[4]) 66 | && pszPath[5] == L':' && pszPath[6] == L'\\' && pszPath[7] == L'\0') { 67 | return TRUE; 68 | } 69 | 70 | // "\\\\?\\Volume{guid}\\" 71 | if (internal::PathIsVolumeGUIDWorker(pszPath) && pszPath[48] == L'\\' && 72 | pszPath[49] == L'\0') { 73 | return TRUE; 74 | } 75 | } 76 | 77 | return FALSE; 78 | } 79 | } // namespace mingw_thunk 80 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathCchRemoveBackslash.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | // YY-Thunk 1.1.6 8 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 9 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 10 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 11 | 8, 12 | HRESULT, 13 | WINAPI, 14 | PathCchRemoveBackslash, 15 | _Inout_updates_(cchPath) PWSTR pszPath, 16 | _In_ size_t cchPath) 17 | { 18 | return PathCchRemoveBackslashEx(pszPath, cchPath, nullptr, nullptr); 19 | } 20 | } // namespace mingw_thunk 21 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathCchRemoveBackslashEx.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | namespace mingw_thunk 8 | { 9 | // YY-Thunk 1.1.6 10 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 11 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 12 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 13 | 16, 14 | HRESULT, 15 | WINAPI, 16 | PathCchRemoveBackslashEx, 17 | _Inout_updates_(_Inexpressible_(cchPath)) PWSTR pszPath, 18 | _In_ size_t cchPath, 19 | _Outptr_opt_result_buffer_(*pcchRemaining) PWSTR *ppszEnd, 20 | _Out_opt_ size_t *pcchRemaining) 21 | { 22 | if (ppszEnd) 23 | *ppszEnd = nullptr; 24 | 25 | if (pcchRemaining) 26 | *pcchRemaining = 0; 27 | 28 | auto nLength = internal::wcslen(pszPath); 29 | 30 | HRESULT hr = S_FALSE; 31 | 32 | do { 33 | if (nLength >= cchPath) { 34 | hr = E_INVALIDARG; 35 | break; 36 | } 37 | 38 | if (nLength && pszPath[nLength - 1] == L'\\') { 39 | --nLength; 40 | 41 | if (!PathCchIsRoot(pszPath)) { 42 | pszPath[nLength] = L'\0'; 43 | hr = S_OK; 44 | } 45 | } 46 | 47 | if (ppszEnd) 48 | *ppszEnd = pszPath + nLength; 49 | 50 | if (pcchRemaining) 51 | *pcchRemaining = cchPath - nLength; 52 | 53 | } while (false); 54 | 55 | return hr; 56 | } 57 | } // namespace mingw_thunk 58 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathCchRemoveExtension.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace mingw_thunk 9 | { 10 | // YY-Thunks 1.1.6 11 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 12 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 13 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 14 | 8, 15 | HRESULT, 16 | WINAPI, 17 | PathCchRemoveExtension, 18 | _Inout_updates_(_Inexpressible_(cchPath)) PWSTR pszPath, 19 | _In_ size_t cchPath) 20 | { 21 | if (pszPath == nullptr || cchPath == 0 || cchPath > PATHCCH_MAX_CCH) 22 | return E_INVALIDARG; 23 | 24 | const auto bExtendedLengthDosDevicePath = 25 | internal::IsExtendedLengthDosDevicePath(pszPath); 26 | if (!bExtendedLengthDosDevicePath) { 27 | cchPath = internal::min(MAX_PATH, cchPath); 28 | } 29 | 30 | PWSTR pszPathExt; 31 | 32 | auto hr = PathCchFindExtension(pszPath, cchPath, (LPCWSTR *)&pszPathExt); 33 | 34 | if (FAILED(hr)) { 35 | return hr; 36 | } 37 | 38 | if (*pszPathExt) { 39 | *pszPathExt = L'\0'; 40 | return S_OK; 41 | } else { 42 | return S_FALSE; 43 | } 44 | } 45 | } // namespace mingw_thunk 46 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathCchRemoveFileSpec.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | // YY-Thunks 1.1.6 9 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 10 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 11 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 12 | 8, 13 | HRESULT, 14 | WINAPI, 15 | PathCchRemoveFileSpec, 16 | _Inout_updates_(_Inexpressible_(cchPath)) PWSTR pszPath, 17 | _In_ size_t cchPath) 18 | { 19 | if (pszPath == nullptr || cchPath == 0 || cchPath > PATHCCH_MAX_CCH) 20 | return E_INVALIDARG; 21 | 22 | PWSTR pszRootEnd; 23 | 24 | if (FAILED(PathCchSkipRoot(pszPath, (PCWSTR *)&pszRootEnd))) { 25 | pszRootEnd = pszPath; 26 | } 27 | 28 | const auto pszPathBufferEnd = pszPath + cchPath; 29 | 30 | if (pszRootEnd >= pszPathBufferEnd) 31 | return E_INVALIDARG; 32 | 33 | // 搜索最后一个 ‘\\’ 34 | 35 | LPWSTR szLast = pszRootEnd; 36 | 37 | for (; *pszRootEnd; ++pszRootEnd) { 38 | if (pszRootEnd >= pszPathBufferEnd) 39 | return E_INVALIDARG; 40 | 41 | if (*pszRootEnd == L'\\') 42 | szLast = pszRootEnd; 43 | } 44 | 45 | if (*szLast) { 46 | *szLast = L'\0'; 47 | PathCchRemoveBackslash(pszPath, cchPath); 48 | 49 | return S_OK; 50 | } else { 51 | return PathCchRemoveBackslash(pszPath, cchPath); 52 | } 53 | } 54 | } // namespace mingw_thunk 55 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathCchRenameExtension.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace mingw_thunk 9 | { 10 | // YY-Thunks 1.1.6 11 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 12 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 13 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 14 | 12, 15 | HRESULT, 16 | WINAPI, 17 | PathCchRenameExtension, 18 | _Inout_updates_(cchPath) PWSTR pszPath, 19 | _In_ size_t cchPath, 20 | _In_ PCWSTR pszExt) 21 | { 22 | if (pszPath == nullptr || cchPath == 0 || cchPath > PATHCCH_MAX_CCH || 23 | internal::IsValidExtensionWorker(pszExt) == false) 24 | return E_INVALIDARG; 25 | 26 | // 检测Unicode Path,如果不是,那么最多允许 260 27 | const auto bExtendedLengthDosDevicePath = 28 | internal::IsExtendedLengthDosDevicePath(pszPath); 29 | if (!bExtendedLengthDosDevicePath) { 30 | cchPath = internal::min(MAX_PATH, cchPath); 31 | } 32 | 33 | PWSTR pszPathExt; 34 | 35 | auto hr = PathCchFindExtension(pszPath, cchPath, (LPCWSTR *)&pszPathExt); 36 | 37 | if (FAILED(hr)) { 38 | return hr; 39 | } 40 | 41 | if (*pszExt == L'.') 42 | ++pszExt; 43 | 44 | // 如果调用者提供的 后缀为空,那么删除现有的,然后立即返回 S_OK 45 | if (*pszExt == L'\0') { 46 | *pszPathExt = L'\0'; 47 | return S_OK; 48 | } 49 | 50 | // 故意不用微软的方法,微软的方法在缓存区不足时会破坏原始值。 51 | // 覆盖现有文件后缀 52 | const auto szPathBufferEnd = pszPath + cchPath; 53 | const auto cchExt = wcslen(pszExt); 54 | 55 | // . ext < szPathBufferEnd 56 | if (pszPathExt + 1 + cchExt + 1 <= szPathBufferEnd) { 57 | *pszPathExt = L'.'; 58 | ++pszPathExt; 59 | 60 | memcpy(pszPathExt, pszExt, (cchExt + 1) * sizeof(pszExt[0])); 61 | 62 | return S_OK; 63 | } 64 | 65 | if (bExtendedLengthDosDevicePath) { 66 | if (cchPath != PATHCCH_MAX_CCH) { 67 | return __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); 68 | } 69 | } else { 70 | if (cchPath != MAX_PATH) { 71 | return __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); 72 | } 73 | } 74 | 75 | return __HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE); 76 | } 77 | } // namespace mingw_thunk 78 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathCchSkipRoot.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | namespace mingw_thunk 8 | { 9 | // YY-Thunks 1.1.6 10 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 11 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 12 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 13 | 8, 14 | HRESULT, 15 | WINAPI, 16 | PathCchSkipRoot, 17 | _In_ PCWSTR pszPath, 18 | _Outptr_ PCWSTR *ppszRootEnd) 19 | { 20 | if (pszPath == nullptr || *pszPath == L'\0' || ppszRootEnd == nullptr) 21 | return E_INVALIDARG; 22 | 23 | *ppszRootEnd = nullptr; 24 | 25 | PCWSTR szRootEnd; 26 | if (PathIsUNCEx(pszPath, &szRootEnd)) { 27 | // 如果是UNC路径,则尝试跳过 2个 '\\' 28 | DWORD nSeparate = 0; 29 | 30 | for (; *szRootEnd && nSeparate < 2; ++szRootEnd) { 31 | if (*szRootEnd == L'\\') { 32 | ++nSeparate; 33 | } 34 | } 35 | } else if (pszPath[0] == L'\\' && pszPath[1] != L'\\') { 36 | // "\\XXXXXX" 一个相对路径 37 | szRootEnd = pszPath + 1; 38 | } else { 39 | if (internal::PathIsVolumeGUIDWorker(pszPath)) { 40 | szRootEnd = pszPath + 48; 41 | } else if (pszPath[0] == L'\\' && pszPath[1] == L'\\' && 42 | pszPath[2] == L'?' && pszPath[3] == L'\\' && 43 | ((L'A' <= pszPath[4] && pszPath[4] <= L'Z') || 44 | (L'a' <= pszPath[4] && 45 | pszPath[4] <= L'z')) // iswalpha(pszPath[4]) 46 | && pszPath[5] == L':') { 47 | // "\\\\?\\C:\\" 48 | szRootEnd = pszPath + 6; 49 | } else if (((L'A' <= pszPath[0] && pszPath[0] <= L'Z') || 50 | (L'a' <= pszPath[0] && 51 | pszPath[0] <= L'z')) // iswalpha(pszPath[0]) 52 | && pszPath[1] == L':') { 53 | // "C:\\" 54 | szRootEnd = pszPath + 2; 55 | } else { 56 | return E_INVALIDARG; 57 | } 58 | 59 | if (*szRootEnd == L'\\') 60 | ++szRootEnd; 61 | } 62 | 63 | *ppszRootEnd = szRootEnd; 64 | 65 | return S_OK; 66 | } 67 | } // namespace mingw_thunk 68 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathCchStripPrefix.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace mingw_thunk 9 | { 10 | // YY-Thunks 1.1.6 11 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 12 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 13 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 14 | 8, 15 | HRESULT, 16 | WINAPI, 17 | PathCchStripPrefix, 18 | _Inout_updates_(cchPath) PWSTR pszPath, 19 | _In_ size_t cchPath) 20 | { 21 | if (pszPath == nullptr || cchPath == 0 || cchPath > PATHCCH_MAX_CCH) 22 | return E_INVALIDARG; 23 | 24 | if (!internal::IsExtendedLengthDosDevicePath(pszPath)) 25 | return S_FALSE; 26 | 27 | if (cchPath < 4) 28 | return E_INVALIDARG; 29 | 30 | if ((pszPath[4] == L'U' || pszPath[4] == L'u') && 31 | (pszPath[5] == L'N' || pszPath[5] == L'n') && 32 | (pszPath[6] == L'C' || pszPath[6] == L'c') && pszPath[7] == L'\\') { 33 | if (cchPath < 8) 34 | return E_INVALIDARG; 35 | 36 | return internal::StringCchCopyW(pszPath + 2, cchPath - 2, pszPath + 8); 37 | } else if ((L'A' <= pszPath[4] && pszPath[4] <= L'Z' || 38 | L'a' <= pszPath[4] && pszPath[4] <= L'z') && 39 | pszPath[5] == L':') { 40 | return internal::StringCchCopyW(pszPath, cchPath, pszPath + 4); 41 | } else { 42 | return S_FALSE; 43 | } 44 | } 45 | } // namespace mingw_thunk 46 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathCchStripToRoot.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | // YY-Thunks 1.1.6 9 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 10 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 11 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 12 | 8, 13 | HRESULT, 14 | WINAPI, 15 | PathCchStripToRoot, 16 | _Inout_updates_(_Inexpressible_(cchPath)) PWSTR pszPath, 17 | _In_ size_t cchPath) 18 | { 19 | if (pszPath == nullptr || cchPath == 0 || cchPath > PATHCCH_MAX_CCH) 20 | return E_INVALIDARG; 21 | 22 | PWSTR szRootEnd; 23 | auto hr = PathCchSkipRoot(pszPath, (PCWSTR *)&szRootEnd); 24 | 25 | do { 26 | if (FAILED(hr)) 27 | break; 28 | 29 | if (szRootEnd >= pszPath + cchPath) { 30 | hr = E_INVALIDARG; 31 | break; 32 | } 33 | 34 | if (*szRootEnd) { 35 | *szRootEnd = L'\0'; 36 | PathCchRemoveBackslash(pszPath, cchPath); 37 | hr = S_OK; 38 | } else { 39 | hr = PathCchRemoveBackslash(pszPath, cchPath); 40 | if (FAILED(hr)) 41 | break; 42 | } 43 | 44 | return hr; 45 | 46 | } while (false); 47 | 48 | *pszPath = L'\0'; 49 | 50 | return hr; 51 | } 52 | } // namespace mingw_thunk 53 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/api-ms-win-core-path-l1-1-0/PathIsUNCEx.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace mingw_thunk 7 | { 8 | // YY-Thunks 1.1.6 9 | // Minimum supported client Windows 8 [desktop apps | UWP apps] 10 | // Minimum supported server Windows Server 2012 [desktop apps | UWP apps] 11 | __DEFINE_THUNK(api_ms_win_core_path_l1_1_0, 12 | 8, 13 | _Success_(return) BOOL, 14 | WINAPI, 15 | PathIsUNCEx, 16 | _In_ PCWSTR pszPath, 17 | _Outptr_opt_ PCWSTR *ppszServer) 18 | { 19 | if (ppszServer) 20 | *ppszServer = nullptr; 21 | 22 | if (pszPath[0] == L'\\' && pszPath[1] == L'\\') { 23 | if (pszPath[2] == L'?') { 24 | if (pszPath[3] == L'\\' && (pszPath[4] == L'U' || pszPath[4] == L'u') && 25 | (pszPath[5] == L'N' || pszPath[5] == L'n') && 26 | (pszPath[6] == L'C' || pszPath[6] == L'c') && pszPath[7] == L'\\') { 27 | pszPath += 8; 28 | } else { 29 | return FALSE; 30 | } 31 | } else { 32 | // PathIsVolumeGUIDWorker 判断是多余的,因为 "\\\\?\\Volume{GUID}" 33 | // 这样的形式走不到这个分支 34 | 35 | pszPath += 2; 36 | } 37 | 38 | if (ppszServer) 39 | *ppszServer = pszPath; 40 | 41 | return TRUE; 42 | } 43 | 44 | return FALSE; 45 | } 46 | } // namespace mingw_thunk 47 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/kernel32/AddDllDirectory.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | __DEFINE_THUNK(kernel32, 8 | 4, 9 | DLL_DIRECTORY_COOKIE, 10 | WINAPI, 11 | AddDllDirectory, 12 | _In_ PCWSTR NewDirectory) 13 | { 14 | if (auto pfn = try_get_AddDllDirectory()) 15 | return pfn(NewDirectory); 16 | 17 | SetLastError(ERROR_NOT_SUPPORTED); 18 | return nullptr; 19 | } 20 | } // namespace mingw_thunk 21 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/kernel32/CopyFile2.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace mingw_thunk 9 | { 10 | __DEFINE_THUNK(kernel32, 11 | 12, 12 | HRESULT, 13 | WINAPI, 14 | CopyFile2, 15 | _In_ PCWSTR pwszExistingFileName, 16 | _In_ PCWSTR pwszNewFileName, 17 | _In_opt_ COPYFILE2_EXTENDED_PARAMETERS *pExtendedParameters) 18 | { 19 | if (const auto pfn = try_get_CopyFile2()) 20 | return pfn(pwszExistingFileName, pwszNewFileName, pExtendedParameters); 21 | 22 | DWORD copy_flags = 0; 23 | if (pExtendedParameters) { 24 | if (pExtendedParameters->dwCopyFlags & COPY_FILE_FAIL_IF_EXISTS) 25 | copy_flags |= COPY_FILE_FAIL_IF_EXISTS; 26 | if (pExtendedParameters->dwCopyFlags & COPY_FILE_RESTARTABLE) 27 | copy_flags |= COPY_FILE_RESTARTABLE; 28 | if (pExtendedParameters->dwCopyFlags & COPY_FILE_OPEN_SOURCE_FOR_WRITE) 29 | copy_flags |= COPY_FILE_OPEN_SOURCE_FOR_WRITE; 30 | if (pExtendedParameters->dwCopyFlags & 31 | COPY_FILE_ALLOW_DECRYPTED_DESTINATION) 32 | copy_flags |= COPY_FILE_ALLOW_DECRYPTED_DESTINATION; 33 | if (internal::os_geq(6, 0)) { 34 | if (pExtendedParameters->dwCopyFlags & COPY_FILE_COPY_SYMLINK) 35 | copy_flags |= COPY_FILE_COPY_SYMLINK; 36 | if (pExtendedParameters->dwCopyFlags & COPY_FILE_NO_BUFFERING) 37 | copy_flags |= COPY_FILE_NO_BUFFERING; 38 | } 39 | } 40 | 41 | if (CopyFileExW(pwszExistingFileName, 42 | pwszNewFileName, 43 | nullptr, 44 | nullptr, 45 | pExtendedParameters ? pExtendedParameters->pfCancel 46 | : nullptr, 47 | copy_flags)) 48 | return S_OK; 49 | else 50 | return HRESULT_FROM_WIN32(GetLastError()); 51 | } 52 | } // namespace mingw_thunk 53 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/kernel32/CopyFile2.test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | TEST_CASE("CopyFile2") 9 | { 10 | const wchar_t *source = L"test-CopyFile2.txt"; 11 | 12 | SECTION("create test file") 13 | { 14 | FILE *fp = _wfopen(source, L"w"); 15 | fclose(fp); 16 | } 17 | 18 | const wchar_t *dest = L"test-CopyFile2-copy.txt"; 19 | 20 | COPYFILE2_EXTENDED_PARAMETERS params{sizeof(params)}; 21 | 22 | CLEAR_TOUCH_FLAG(); 23 | HRESULT hr = CopyFile2(source, dest, ¶ms); 24 | REQUIRE_TOUCHED(); 25 | 26 | REQUIRE(SUCCEEDED(hr)); 27 | } 28 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/kernel32/GetSystemTimePreciseAsFileTime.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | // YY-Thunks 1.1.6 8 | __DEFINE_THUNK(kernel32, 9 | 4, 10 | VOID, 11 | WINAPI, 12 | GetSystemTimePreciseAsFileTime, 13 | _Out_ LPFILETIME lpSystemTimeAsFileTime) 14 | { 15 | if (auto const pGetSystemTimePreciseAsFileTime = 16 | try_get_GetSystemTimePreciseAsFileTime()) { 17 | return pGetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime); 18 | } 19 | 20 | return GetSystemTimeAsFileTime(lpSystemTimeAsFileTime); 21 | } 22 | } // namespace mingw_thunk 23 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/kernel32/GetSystemTimePreciseAsFileTime.test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | TEST_CASE("GetSystemTimePreciseAsFileTime") 6 | { 7 | FILETIME ft1; 8 | CLEAR_TOUCH_FLAG(); 9 | GetSystemTimePreciseAsFileTime(&ft1); 10 | REQUIRE_TOUCHED(); 11 | 12 | FILETIME ft2; 13 | GetSystemTimeAsFileTime(&ft2); 14 | 15 | ULARGE_INTEGER ul1{ 16 | .LowPart = ft1.dwLowDateTime, 17 | .HighPart = ft1.dwHighDateTime, 18 | }; 19 | ULARGE_INTEGER ul2{ 20 | .LowPart = ft2.dwLowDateTime, 21 | .HighPart = ft2.dwHighDateTime, 22 | }; 23 | 24 | // difference < 1 ms (100 ns * 10'000) 25 | REQUIRE(int64_t(ul1.QuadPart) - int64_t(ul2.QuadPart) < 10'000); 26 | REQUIRE(int64_t(ul2.QuadPart) - int64_t(ul1.QuadPart) < 10'000); 27 | } 28 | -------------------------------------------------------------------------------- /support/thunk/src/6.2/kernel32/RemoveDllDirectory.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace mingw_thunk 6 | { 7 | __DEFINE_THUNK(kernel32, 8 | 4, 9 | BOOL, 10 | WINAPI, 11 | RemoveDllDirectory, 12 | _In_ DLL_DIRECTORY_COOKIE Cookie) 13 | { 14 | if (auto pfn = try_get_RemoveDllDirectory()) 15 | return pfn(Cookie); 16 | 17 | // This should not be called because `AddDllDirectory` always fails. 18 | SetLastError(ERROR_NOT_SUPPORTED); 19 | return 0; 20 | } 21 | } // namespace mingw_thunk 22 | -------------------------------------------------------------------------------- /support/thunk/xmake.lua: -------------------------------------------------------------------------------- 1 | set_plat('mingw') 2 | add_rules('mode.release') 3 | set_languages('c11', 'cxx17') 4 | 5 | add_requires("catch2") 6 | 7 | target('thunk') 8 | set_kind('static') 9 | add_cxxflags( 10 | '-nostdinc++', 11 | '-fno-exceptions', 12 | '-fno-threadsafe-statics') 13 | add_includedirs('include') 14 | add_defines( 15 | '__USE_MINGW_ANSI_STDIO=0', 16 | '_WIN32_WINNT=0x0f00') 17 | set_exceptions('none') 18 | if is_arch('i386') then 19 | add_files( 20 | 'src/5.0/**.cc|**.test.cc', 21 | 'src/5.1/**.cc|**.test.cc', 22 | 'src/5.2/**.cc|**.test.cc') 23 | end 24 | if is_arch('i386') or is_arch('x86_64') then 25 | add_files('src/6.0/**.cc|**.test.cc') 26 | add_files('src/6.1/**.cc|**.test.cc') 27 | add_files('src/6.2/**.cc|**.test.cc') 28 | end 29 | 30 | target('test') 31 | add_packages('catch2') 32 | add_includedirs('include') 33 | add_defines( 34 | 'ENABLE_TEST_OVERRIDE', 35 | '__USE_MINGW_ANSI_STDIO=0', 36 | '_WIN32_WINNT=0x0f00') 37 | set_exceptions('none') 38 | if is_arch('i386') then 39 | add_files( 40 | 'src/5.0/**.cc', 41 | 'src/5.1/**.cc', 42 | 'src/5.2/**.cc') 43 | end 44 | if is_arch('i386') or is_arch('x86_64') then 45 | add_files('src/6.0/**.cc') 46 | add_files('src/6.1/**.cc') 47 | add_files('src/6.2/**.cc') 48 | end 49 | add_ldflags('-static') 50 | add_links('ws2_32') 51 | add_tests('default') 52 | -------------------------------------------------------------------------------- /support/utf8/utf8-init.c: -------------------------------------------------------------------------------- 1 | unsigned __stdcall GetACP(); 2 | unsigned __stdcall GetConsoleCP(); 3 | unsigned __stdcall GetConsoleOutputCP(); 4 | int __stdcall SetConsoleCP(unsigned); 5 | int __stdcall SetConsoleOutputCP(unsigned); 6 | 7 | unsigned __mingw_lite_crt_saved_console_input_code_page; 8 | unsigned __mingw_lite_crt_saved_console_output_code_page; 9 | 10 | void __attribute__((constructor)) 11 | __mingw_lite_crt_set_console_code_page() 12 | { 13 | __mingw_lite_crt_saved_console_input_code_page = GetConsoleCP(); 14 | __mingw_lite_crt_saved_console_output_code_page = GetConsoleOutputCP(); 15 | unsigned acp = GetACP(); 16 | SetConsoleCP(acp); 17 | SetConsoleOutputCP(acp); 18 | } 19 | 20 | void __attribute__((destructor)) 21 | __mingw_lite_crt_restore_console_code_page() 22 | { 23 | SetConsoleCP(__mingw_lite_crt_saved_console_input_code_page); 24 | SetConsoleOutputCP(__mingw_lite_crt_saved_console_output_code_page); 25 | } 26 | -------------------------------------------------------------------------------- /support/utf8/utf8-manifest.rc: -------------------------------------------------------------------------------- 1 | 1 24 MOVEABLE PURE DISCARDABLE 2 | BEGIN 3 | "" 4 | "" 5 | "" 6 | "" 7 | "" 8 | "UTF-8" 9 | "" 10 | "" 11 | "" 12 | END 13 | --------------------------------------------------------------------------------