mirror of
				https://github.com/davidgiven/fluxengine.git
				synced 2025-10-24 11:11:02 -07:00 
			
		
		
		
	Compare commits
	
		
			244 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | eee6f95b15 | ||
|  | 7a3d10451d | ||
|  | e4f1a5a06f | ||
|  | 500fcde21b | ||
|  | eb363a4b2a | ||
|  | 8a78e609b0 | ||
|  | 15c67b8cc1 | ||
|  | 00e9c5a07f | ||
|  | 7643457374 | ||
|  | 78d5584e21 | ||
|  | 1d1143a893 | ||
|  | 91093e1304 | ||
|  | 1175a06f3d | ||
|  | 6e5abd1189 | ||
|  | 34f97384e7 | ||
|  | 653a6a0189 | ||
|  | f0b1b61eac | ||
|  | c0fd121bdf | ||
|  | b805b86ddb | ||
|  | 654e7e750c | ||
|  | 7501fcfe8b | ||
|  | fdb7837e03 | ||
|  | 1c57cea483 | ||
|  | 0c8e8d4d69 | ||
|  | 8876aae2cc | ||
|  | 3e053b32e2 | ||
|  | 0611728537 | ||
|  | a84cf83ce5 | ||
|  | c064aa7862 | ||
|  | 195f7126cc | ||
|  | 50d466c9c1 | ||
|  | 5763574634 | ||
|  | 2da568b3e8 | ||
|  | 2732d9aec8 | ||
|  | 15d34aff15 | ||
|  | af3e257c78 | ||
|  | c2248c7e4a | ||
|  | a7967b6dc3 | ||
|  | c1f47921e6 | ||
|  | cda93d516b | ||
|  | 8f9c12b26c | ||
|  | cdb4e9ed21 | ||
|  | 1a612c3db5 | ||
|  | 72ab957134 | ||
|  | 621523db62 | ||
|  | cdf9cc387c | ||
|  | b84ecd289d | ||
|  | d4cb8f414a | ||
|  | 8180c1f79e | ||
|  | b23b21a7bf | ||
|  | b30eff294d | ||
|  | cacb397198 | ||
|  | 0f8c7d6969 | ||
|  | 7b35232cad | ||
|  | 43624796db | ||
|  | bc17c624d3 | ||
|  | 61476ea0cc | ||
|  | f0663030e1 | ||
|  | 989a11931b | ||
|  | 94372a7f09 | ||
|  | 5c2702c6ab | ||
|  | 586c09f5c3 | ||
|  | 7a94123f0d | ||
|  | 4cad34a8a4 | ||
|  | c0ef3215df | ||
|  | 08982aae7a | ||
|  | 6366ac6639 | ||
|  | 3807d22a78 | ||
|  | 3adbfd7ef5 | ||
|  | 7e40dfa5da | ||
|  | 62ddca2bb4 | ||
|  | 1a59e5065d | ||
|  | 52c0c409e9 | ||
|  | e74b16d28b | ||
|  | c2369bcc31 | ||
|  | 2636352a49 | ||
|  | 222a88f097 | ||
|  | dbc691726d | ||
|  | 9ff3aedf18 | ||
|  | 8303a1fbca | ||
|  | 0f584ee343 | ||
|  | aafad0a628 | ||
|  | 9d03951da9 | ||
|  | b15d6cb8e5 | ||
|  | f9c1816e6f | ||
|  | d960b020ea | ||
|  | 72e9d57b15 | ||
|  | 968b90dbab | ||
|  | 2bccdcc93b | ||
|  | ce2a5eb6d9 | ||
|  | 353e4f6210 | ||
|  | c115de9d40 | ||
|  | df83b558bf | ||
|  | 7c2b5f116d | ||
|  | 30fe75f9bf | ||
|  | 401e7a9edb | ||
|  | fd4ddc56f2 | ||
|  | 83d907bf71 | ||
|  | 327bc76c6e | ||
|  | fdd39fb2d8 | ||
|  | bfcfa8eb19 | ||
|  | 7095c03e28 | ||
|  | 45e796f15f | ||
|  | 3d1dcd6874 | ||
|  | 0033d0759f | ||
|  | 53f7dfe6c9 | ||
|  | 75446de29b | ||
|  | 1d119d6921 | ||
|  | 7462bd995f | ||
|  | 0dd99efad3 | ||
|  | 1234e81463 | ||
|  | ea13d66e6b | ||
|  | a7cb7eb995 | ||
|  | 29f5feb34d | ||
|  | 5dc60db7b6 | ||
|  | fb9f7fe445 | ||
|  | a548471652 | ||
|  | 3e47d66644 | ||
|  | 3bfa45a80c | ||
|  | 2d717af4db | ||
|  | 533b217c8f | ||
|  | ff1fb761f2 | ||
|  | 95d49add2c | ||
|  | 8b75609b70 | ||
|  | b8929dd589 | ||
|  | 2fd29f8786 | ||
|  | 38408820ca | ||
|  | 43e6840e78 | ||
|  | 15908c52bd | ||
|  | c90b0e7dc2 | ||
|  | d2ff9806bd | ||
|  | 1e6993c12d | ||
|  | 1122344016 | ||
|  | 0dbce00fe4 | ||
|  | 5af0b68e06 | ||
|  | 6038a11671 | ||
|  | dcb92db519 | ||
|  | dcaeabacc6 | ||
|  | a2a5c7eff0 | ||
|  | e1cf927bf3 | ||
|  | 8fd98d674a | ||
|  | fd884027c0 | ||
|  | 26bd467f79 | ||
|  | c7f22c0dab | ||
|  | 92d44f6ae3 | ||
|  | 9143f477b2 | ||
|  | 1a519bf837 | ||
|  | ca6b90f8c1 | ||
|  | 44fc532d63 | ||
|  | 6a6cd025c0 | ||
|  | d769f90704 | ||
|  | 9d8e3b21ba | ||
|  | dabdfec3e7 | ||
|  | 6a00653d1e | ||
|  | 8fb786094f | ||
|  | 87e978c817 | ||
|  | 4a31046c9c | ||
|  | db420b3495 | ||
|  | c81dc166bc | ||
|  | 07aa416975 | ||
|  | 627820cddc | ||
|  | a24fe420c4 | ||
|  | 986be921f4 | ||
|  | f5f223f622 | ||
|  | bbdfa0d651 | ||
|  | e6bb0cb463 | ||
|  | 9e61670116 | ||
|  | 3876c07164 | ||
|  | ed315eade9 | ||
|  | 7456fd0c90 | ||
|  | 44160e66ac | ||
|  | 9bd969a57b | ||
|  | 0b585078d8 | ||
|  | 0d495ed934 | ||
|  | 95b703b1ea | ||
|  | 688061397b | ||
|  | 1f00176455 | ||
|  | 90da6b1e72 | ||
|  | 4deb45dc3f | ||
|  | eeec5d106a | ||
|  | 4e42d1d197 | ||
|  | 495d08c447 | ||
|  | 1b859015ae | ||
|  | 3db2109e01 | ||
|  | 294ac87503 | ||
|  | c297adb0c7 | ||
|  | 446b965794 | ||
|  | 96d4df296d | ||
|  | a149aac0e9 | ||
|  | aacc7be9f3 | ||
|  | 7409955701 | ||
|  | c623d95a80 | ||
|  | 1927cc7fe1 | ||
|  | 4eca254daf | ||
|  | c7d4fee3f6 | ||
|  | a6f798ae5b | ||
|  | c9ae836e52 | ||
|  | e3ffa63f7f | ||
|  | 4ffc2cc1dc | ||
|  | 7f9ba14687 | ||
|  | a24933e272 | ||
|  | 20bdacbecf | ||
|  | ab9d6cf5ed | ||
|  | 1f5903a9a0 | ||
|  | bb073b6bb3 | ||
|  | 516241f8f5 | ||
|  | 977b6831a0 | ||
|  | c61effb54f | ||
|  | 346d989944 | ||
|  | 60a73c8d1e | ||
|  | e52db4a837 | ||
|  | 4e317643bc | ||
|  | 5f520bf375 | ||
|  | 2efe521b3a | ||
|  | 5c21103646 | ||
|  | 9444696f37 | ||
|  | 082fe4e787 | ||
|  | 5e13cf23f9 | ||
|  | 8f98a1f557 | ||
|  | 5b21e8798b | ||
|  | b9ef5b7db8 | ||
|  | 9867f8c302 | ||
|  | 315889faf6 | ||
|  | 798e8fee89 | ||
|  | e1c49db329 | ||
|  | dae9537472 | ||
|  | 1330d56cdd | ||
|  | 6ce3ce20d0 | ||
|  | 362c5ee9b0 | ||
|  | 0f34ce0278 | ||
|  | 0c27c7c4c8 | ||
|  | 37595bf73c | ||
|  | 952aea46ba | ||
|  | 6a6536cf27 | ||
|  | 696368c92a | ||
|  | e3edc9327e | ||
|  | 8d2e6a664d | ||
|  | 9db6efe7a2 | ||
|  | ba1f8b8ed8 | ||
|  | 10605b3908 | ||
|  | e31e547322 | ||
|  | 9484a1b870 | ||
|  | 0a5a814a88 | ||
|  | 08ce455d1d | 
							
								
								
									
										68
									
								
								.github/workflows/ccpp.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										68
									
								
								.github/workflows/ccpp.yml
									
									
									
									
										vendored
									
									
								
							| @@ -19,9 +19,10 @@ jobs: | ||||
|         repository: 'davidgiven/fluxengine-testdata' | ||||
|         path: 'fluxengine-testdata' | ||||
|     - name: apt | ||||
|       run: sudo apt update && sudo apt install libudev-dev libsqlite3-dev protobuf-compiler libwxgtk3.0-gtk3-dev libfmt-dev | ||||
|       run: | | ||||
|         sudo apt install libudev-dev libsqlite3-dev protobuf-compiler libwxgtk3.0-gtk3-dev libfmt-dev libprotobuf-dev wx-common | ||||
|     - name: make | ||||
|       run: CXXFLAGS="-Wp,-D_GLIBCXX_ASSERTIONS" make -j2 -C fluxengine | ||||
|       run: CXXFLAGS="-Wp,-D_GLIBCXX_ASSERTIONS" make -j`nproc` -C fluxengine | ||||
|  | ||||
|   build-macos-current: | ||||
|     runs-on: macos-latest | ||||
| @@ -37,60 +38,57 @@ jobs: | ||||
|     - name: brew | ||||
|       run: brew install sqlite pkg-config libusb protobuf wxwidgets fmt make coreutils dylibbundler libjpeg | ||||
|     - name: make | ||||
|       run: gmake -j2 -C fluxengine | ||||
|       run: gmake -j`nproc` -C fluxengine | ||||
|  | ||||
|     - name: Upload build artifacts | ||||
|       uses: actions/upload-artifact@v2 | ||||
|       with: | ||||
|         name: ${{ github.event.repository.name }}.${{ github.sha }} | ||||
|         path: fluxengine.FluxEngine.pkg | ||||
|         path: fluxengine/FluxEngine.pkg | ||||
|  | ||||
|   build-windows: | ||||
|     runs-on: windows-latest | ||||
|     defaults: | ||||
|       run: | ||||
|         shell: msys2 {0} | ||||
|  | ||||
|     steps: | ||||
|     - uses: msys2/setup-msys2@v2 | ||||
|       with: | ||||
|         update: true | ||||
|         msystem: MINGW32 | ||||
|         install: >- | ||||
|           diffutils | ||||
|           make | ||||
|           mingw-w64-i686-fmt | ||||
|           mingw-w64-i686-gcc | ||||
|           mingw-w64-i686-libusb | ||||
|           mingw-w64-i686-pkg-config | ||||
|           mingw-w64-i686-protobuf | ||||
|           mingw-w64-i686-sqlite3 | ||||
|           mingw-w64-i686-wxWidgets | ||||
|           mingw-w64-i686-zlib | ||||
|           mingw-w64-i686-nsis | ||||
|           zip | ||||
|           vim | ||||
|     - uses: actions/checkout@v2 | ||||
|     - name: setup WSL | ||||
|       run: | | ||||
|         curl -L https://github.com/WhitewaterFoundry/Fedora-Remix-for-WSL/releases/download/39.0.1/Fedora-Remix-for-WSL-SL_39.0.1.0_x64_arm64.msixbundle -o fedora.msixbundle | ||||
|         unzip fedora.msixbundle Fedora-Remix-for-WSL-SL_39.0.1.0_x64.msix | ||||
|         unzip Fedora-Remix-for-WSL-SL_39.0.1.0_x64.msix install.tar.gz | ||||
|         wsl --update | ||||
|         wsl --import fedora fedora install.tar.gz | ||||
|         wsl --set-default fedora | ||||
|         wsl sh -c 'dnf -y install https://github.com/rpmsphere/noarch/raw/master/r/rpmsphere-release-38-1.noarch.rpm' | ||||
|         wsl sh -c 'dnf -y install --setop=install_weak_deps=False gcc gcc-c++ protobuf-c-compiler protobuf-devel fmt-devel systemd-devel sqlite-devel wxGTK-devel mingw32-gcc mingw32-gcc-c++ mingw32-zlib-static mingw32-protobuf-static mingw32-sqlite-static mingw32-wxWidgets3-static mingw32-libpng-static mingw32-libjpeg-static mingw32-libtiff-static mingw32-nsis png2ico' | ||||
|  | ||||
|     - name: fix line endings | ||||
|       run: | | ||||
|         git config --global core.autocrlf false | ||||
|         git config --global core.eol lf | ||||
|          | ||||
|     - uses: actions/checkout@v4 | ||||
|       with: | ||||
|         repository: 'davidgiven/fluxengine' | ||||
|         path: 'fluxengine' | ||||
|     - uses: actions/checkout@v2 | ||||
|  | ||||
|     - uses: actions/checkout@v4 | ||||
|       with: | ||||
|         repository: 'davidgiven/fluxengine-testdata' | ||||
|         path: 'fluxengine-testdata' | ||||
|     - name: build | ||||
|       run: make -j2 -C fluxengine | ||||
|  | ||||
|     - name: run | ||||
|       run: | | ||||
|         wsl sh -c 'make -C fluxengine BUILDTYPE=windows -j$(nproc)' | ||||
|  | ||||
|     - name: nsis | ||||
|       run: | | ||||
|         cd fluxengine | ||||
|         strip fluxengine.exe -o fluxengine-stripped.exe | ||||
|         strip fluxengine-gui.exe -o fluxengine-gui-stripped.exe | ||||
|         makensis -v2 -nocd -dOUTFILE=fluxengine-installer.exe extras/windows-installer.nsi | ||||
|         wsl sh -c 'cd fluxengine && strip fluxengine.exe -o fluxengine-stripped.exe' | ||||
|         wsl sh -c 'cd fluxengine && strip fluxengine-gui.exe -o fluxengine-gui-stripped.exe' | ||||
|         wsl sh -c 'cd fluxengine && makensis -v2 -nocd -dOUTFILE=fluxengine-installer.exe extras/windows-installer.nsi' | ||||
|  | ||||
|     - name: zip | ||||
|       run: | | ||||
|         cd fluxengine | ||||
|         zip -9 fluxengine-windows.zip fluxengine.exe fluxengine-gui.exe upgrade-flux-file.exe brother120tool.exe brother240tool.exe FluxEngine.cydsn/CortexM3/ARM_GCC_541/Release/FluxEngine.hex fluxengine-installer.exe | ||||
|         wsl sh -c 'cd fluxengine && zip -9 fluxengine-windows.zip fluxengine.exe fluxengine-gui.exe upgrade-flux-file.exe brother120tool.exe brother240tool.exe FluxEngine.cydsn/CortexM3/ARM_GCC_541/Release/FluxEngine.hex fluxengine-installer.exe' | ||||
|  | ||||
|     - name: Upload build artifacts | ||||
|       uses: actions/upload-artifact@v2 | ||||
|   | ||||
							
								
								
									
										68
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										68
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,7 +1,7 @@ | ||||
| name: Autorelease | ||||
|  | ||||
| concurrency:  | ||||
|   group: environment-${{ github.head_ref }} | ||||
|   group: environment-release-${{ github.head_ref }} | ||||
|   cancel-in-progress: true | ||||
|  | ||||
| on: | ||||
| @@ -12,43 +12,42 @@ on: | ||||
| jobs: | ||||
|   dev-release: | ||||
|     runs-on: windows-latest | ||||
|     defaults: | ||||
|       run: | ||||
|         shell: msys2 {0} | ||||
|     steps: | ||||
|     - uses: msys2/setup-msys2@v2 | ||||
|       with: | ||||
|         update: true | ||||
|         msystem: MINGW32 | ||||
|         install: >- | ||||
|           diffutils | ||||
|           make | ||||
|           mingw-w64-i686-fmt | ||||
|           mingw-w64-i686-gcc | ||||
|           mingw-w64-i686-libusb | ||||
|           mingw-w64-i686-pkg-config | ||||
|           mingw-w64-i686-protobuf | ||||
|           mingw-w64-i686-sqlite3 | ||||
|           mingw-w64-i686-wxWidgets | ||||
|           mingw-w64-i686-zlib | ||||
|           mingw-w64-i686-nsis | ||||
|           zip | ||||
|           vim | ||||
|     - uses: actions/checkout@v3 | ||||
|  | ||||
|     - name: build | ||||
|     steps: | ||||
|     - name: setup WSL | ||||
|       run: | | ||||
|         make -j2 | ||||
|         curl -L https://github.com/WhitewaterFoundry/Fedora-Remix-for-WSL/releases/download/39.0.1/Fedora-Remix-for-WSL-SL_39.0.1.0_x64_arm64.msixbundle -o fedora.msixbundle | ||||
|         unzip fedora.msixbundle Fedora-Remix-for-WSL-SL_39.0.1.0_x64.msix | ||||
|         unzip Fedora-Remix-for-WSL-SL_39.0.1.0_x64.msix install.tar.gz | ||||
|         wsl --update | ||||
|         wsl --import fedora fedora install.tar.gz | ||||
|         wsl --set-default fedora | ||||
|         wsl sh -c 'dnf -y install https://github.com/rpmsphere/noarch/raw/master/r/rpmsphere-release-38-1.noarch.rpm' | ||||
|         wsl sh -c 'dnf -y install --setop=install_weak_deps=False gcc gcc-c++ protobuf-c-compiler protobuf-devel fmt-devel systemd-devel sqlite-devel wxGTK-devel mingw32-gcc mingw32-gcc-c++ mingw32-zlib-static mingw32-protobuf-static mingw32-sqlite-static mingw32-wxWidgets3-static mingw32-libpng-static mingw32-libjpeg-static mingw32-libtiff-static mingw32-nsis png2ico' | ||||
|  | ||||
|     - name: fix line endings | ||||
|       run: | | ||||
|         git config --global core.autocrlf false | ||||
|         git config --global core.eol lf | ||||
|          | ||||
|     - uses: actions/checkout@v4 | ||||
|       with: | ||||
|         repository: 'davidgiven/fluxengine' | ||||
|         path: 'fluxengine' | ||||
|  | ||||
|     - name: run | ||||
|       run: | | ||||
|         wsl sh -c 'cd fluxengine && make BUILDTYPE=windows -j$(nproc)' | ||||
|  | ||||
|     - name: nsis | ||||
|       run: | | ||||
|         strip fluxengine.exe -o fluxengine-stripped.exe | ||||
|         strip fluxengine-gui.exe -o fluxengine-gui-stripped.exe | ||||
|         makensis -v2 -nocd -dOUTFILE=fluxengine-installer.exe extras/windows-installer.nsi | ||||
|         wsl sh -c 'cd fluxengine && strip fluxengine.exe -o fluxengine-stripped.exe' | ||||
|         wsl sh -c 'cd fluxengine && strip fluxengine-gui.exe -o fluxengine-gui-stripped.exe' | ||||
|         wsl sh -c 'cd fluxengine && makensis -v2 -nocd -dOUTFILE=fluxengine-installer.exe extras/windows-installer.nsi' | ||||
|  | ||||
|     - name: zip | ||||
|       run: | | ||||
|         zip -9 fluxengine.zip fluxengine.exe fluxengine-gui.exe upgrade-flux-file.exe brother120tool.exe brother240tool.exe FluxEngine.cydsn/CortexM3/ARM_GCC_541/Release/FluxEngine.hex | ||||
|         wsl sh -c 'cd fluxengine && zip -9 fluxengine-windows.zip fluxengine.exe fluxengine-gui.exe upgrade-flux-file.exe brother120tool.exe brother240tool.exe FluxEngine.cydsn/CortexM3/ARM_GCC_541/Release/FluxEngine.hex fluxengine-installer.exe' | ||||
|  | ||||
|     - name: date | ||||
|       run: | | ||||
| @@ -59,6 +58,7 @@ jobs: | ||||
|       with: | ||||
|         tag-name: dev | ||||
|         force-branch: false | ||||
|         git-directory: 'fluxengine' | ||||
|       env: | ||||
|         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||
|  | ||||
| @@ -77,8 +77,8 @@ jobs: | ||||
|       with: | ||||
|         name: Development build ${{ env.RELEASE_DATE }} | ||||
|         files: | | ||||
|           fluxengine.zip | ||||
|           fluxengine-installer.exe | ||||
|           fluxengine/fluxengine.zip | ||||
|           fluxengine/fluxengine-installer.exe | ||||
|         tag_name: dev | ||||
|       env: | ||||
|         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||
| @@ -87,10 +87,12 @@ jobs: | ||||
|     runs-on: macos-latest | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
|  | ||||
|     - name: brew | ||||
|       run: brew install sqlite pkg-config libusb protobuf wxwidgets fmt make coreutils dylibbundler libjpeg | ||||
|  | ||||
|     - name: make | ||||
|       run: gmake | ||||
|       run: gmake -j`nproc` | ||||
|  | ||||
|     - name: tag | ||||
|       uses: EndBug/latest-tag@latest | ||||
|   | ||||
							
								
								
									
										345
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										345
									
								
								Makefile
									
									
									
									
									
								
							| @@ -1,299 +1,96 @@ | ||||
| #Special Windows settings. | ||||
| export BUILDTYPE | ||||
| BUILDTYPE ?= host | ||||
|  | ||||
| ifeq ($(OS), Windows_NT) | ||||
| 	MINGWBIN = /mingw32/bin | ||||
| 	CCPREFIX = $(MINGWBIN)/ | ||||
| 	LUA = $(MINGWBIN)/lua | ||||
| 	PKG_CONFIG = $(MINGWBIN)/pkg-config | ||||
| 	WX_CONFIG = /usr/bin/sh $(MINGWBIN)/wx-config --static=yes | ||||
| 	PROTOC = $(MINGWBIN)/protoc | ||||
| 	PLATFORM = WINDOWS | ||||
| 	LDFLAGS += \ | ||||
| 		-static | ||||
| ifeq ($(BUILDTYPE),windows) | ||||
| 	MINGW = i686-w64-mingw32- | ||||
| 	CC = $(MINGW)gcc | ||||
| 	CXX = $(MINGW)g++ -std=c++17 | ||||
| 	CFLAGS += -g -O3 | ||||
| 	CXXFLAGS += \ | ||||
| 		-std=c++17 \ | ||||
| 		-fext-numeric-literals \ | ||||
| 		-Wno-deprecated-enum-float-conversion \ | ||||
| 		-Wno-deprecated-enum-enum-conversion | ||||
|  | ||||
| #Required to get the gcc run - time libraries on the path. | ||||
| 	export PATH := $(PATH):$(MINGWBIN) | ||||
| 	EXT ?= .exe | ||||
| 	LDFLAGS += -static | ||||
| 	AR = $(MINGW)ar | ||||
| 	PKG_CONFIG = $(MINGW)pkg-config -static | ||||
| 	WINDRES = $(MINGW)windres | ||||
| 	WX_CONFIG = /usr/i686-w64-mingw32/sys-root/mingw/bin/wx-config-3.0 --static=yes | ||||
| 	EXT = .exe | ||||
| else | ||||
| 	CC = gcc | ||||
| 	CXX = g++ -std=c++17 | ||||
| 	CFLAGS = -g -O3 | ||||
| 	LDFLAGS = | ||||
| 	AR = ar | ||||
| 	PKG_CONFIG = pkg-config | ||||
| endif | ||||
|  | ||||
| #Special OSX settings. | ||||
| HOSTCC = gcc | ||||
| HOSTCXX = g++ -std=c++17 | ||||
| HOSTCFLAGS = -g -O3 | ||||
| HOSTLDFLAGS = | ||||
|  | ||||
| ifeq ($(shell uname),Darwin) | ||||
| 	PLATFORM = OSX | ||||
| 	LDFLAGS += \ | ||||
| 		-framework IOKit \ | ||||
| 		-framework Foundation | ||||
| endif | ||||
|  | ||||
| #Check the Make version. | ||||
|  | ||||
|  | ||||
| ifeq ($(findstring 4.,$(MAKE_VERSION)),) | ||||
| $(error You need GNU Make 4.x for this (if you're on OSX, use gmake).) | ||||
| endif | ||||
|  | ||||
| #Normal settings. | ||||
|  | ||||
| OBJDIR ?= .obj | ||||
| CCPREFIX ?= | ||||
| LUA ?= lua | ||||
| CC ?= $(CCPREFIX)gcc | ||||
| CXX ?= $(CCPREFIX)g++ | ||||
| AR ?= $(CCPREFIX)ar | ||||
| PKG_CONFIG ?= pkg-config | ||||
| WX_CONFIG ?= wx-config | ||||
| PROTOC ?= protoc | ||||
| CFLAGS ?= -g -O3 | ||||
| CXXFLAGS += -std=c++17 | ||||
| LDFLAGS ?= | ||||
| PLATFORM ?= UNIX | ||||
| TESTS ?= yes | ||||
| EXT ?= | ||||
| REALOBJ = .obj | ||||
| OBJ = $(REALOBJ)/$(BUILDTYPE) | ||||
| DESTDIR ?= | ||||
| PREFIX ?= /usr/local | ||||
| BINDIR ?= $(PREFIX)/bin | ||||
|  | ||||
| CFLAGS += \ | ||||
| 	-Iarch \ | ||||
| 	-Ilib \ | ||||
| 	-I. \ | ||||
| 	-I$(OBJDIR)/arch \ | ||||
| 	-I$(OBJDIR)/lib \ | ||||
| 	-I$(OBJDIR) \ | ||||
| 	-Wno-deprecated-declarations \ | ||||
| # Special Windows settings. | ||||
|  | ||||
| LDFLAGS += \ | ||||
| 	-lz \ | ||||
| 	-lfmt | ||||
| ifeq ($(OS), Windows_NT) | ||||
| 	EXT ?= .exe | ||||
| 	MINGWBIN = /mingw32/bin | ||||
| 	CCPREFIX = $(MINGWBIN)/ | ||||
| 	PKG_CONFIG = $(MINGWBIN)/pkg-config | ||||
| 	WX_CONFIG = /usr/bin/sh $(MINGWBIN)/wx-config --static=yes | ||||
| 	PROTOC = $(MINGWBIN)/protoc | ||||
| 	WINDRES = windres | ||||
| 	LDFLAGS += \ | ||||
| 		-static | ||||
| 	CXXFLAGS += \ | ||||
| 		-fext-numeric-literals \ | ||||
| 		-Wno-deprecated-enum-float-conversion \ | ||||
| 		-Wno-deprecated-enum-enum-conversion | ||||
|  | ||||
| .SUFFIXES: | ||||
| .DELETE_ON_ERROR: | ||||
|  | ||||
| define nl | ||||
|  | ||||
| endef | ||||
|  | ||||
| empty := | ||||
| space := $(empty) $(empty) | ||||
|  | ||||
| use-library = $(eval $(use-library-impl)) | ||||
| define use-library-impl | ||||
| $1: $(call $3_LIB) | ||||
| $1: private LDFLAGS += $(call $3_LDFLAGS) | ||||
| $2: private CFLAGS += $(call $3_CFLAGS) | ||||
| endef | ||||
|  | ||||
| use-pkgconfig = $(eval $(use-pkgconfig-impl)) | ||||
| define use-pkgconfig-impl | ||||
| ifneq ($(strip $(shell $(PKG_CONFIG) $3; echo $$?)),0) | ||||
| $$(error Missing required pkg-config dependency: $3) | ||||
| 	# Required to get the gcc run - time libraries on the path. | ||||
| 	export PATH := $(PATH):$(MINGWBIN) | ||||
| endif | ||||
|  | ||||
| $(1): private LDFLAGS += $(shell $(PKG_CONFIG) --libs $(3)) | ||||
| $(2): private CFLAGS += $(shell $(PKG_CONFIG) --cflags $(3)) | ||||
| endef | ||||
|  | ||||
| .PHONY: all binaries tests clean install install-bin | ||||
| all: binaries tests docs | ||||
|  | ||||
| PROTOS = \ | ||||
| 	arch/aeslanier/aeslanier.proto \ | ||||
| 	arch/agat/agat.proto \ | ||||
| 	arch/amiga/amiga.proto \ | ||||
| 	arch/apple2/apple2.proto \ | ||||
| 	arch/brother/brother.proto \ | ||||
| 	arch/c64/c64.proto \ | ||||
| 	arch/f85/f85.proto \ | ||||
| 	arch/fb100/fb100.proto \ | ||||
| 	arch/ibm/ibm.proto \ | ||||
| 	arch/macintosh/macintosh.proto \ | ||||
| 	arch/micropolis/micropolis.proto \ | ||||
| 	arch/mx/mx.proto \ | ||||
| 	arch/northstar/northstar.proto \ | ||||
| 	arch/rolandd20/rolandd20.proto \ | ||||
| 	arch/smaky6/smaky6.proto \ | ||||
| 	arch/tids990/tids990.proto \ | ||||
| 	arch/victor9k/victor9k.proto \ | ||||
| 	arch/zilogmcz/zilogmcz.proto \ | ||||
| 	lib/common.proto \ | ||||
| 	lib/config.proto \ | ||||
| 	lib/decoders/decoders.proto \ | ||||
| 	lib/drive.proto \ | ||||
| 	lib/encoders/encoders.proto \ | ||||
| 	lib/fl2.proto \ | ||||
| 	lib/fluxsink/fluxsink.proto \ | ||||
| 	lib/fluxsource/fluxsource.proto \ | ||||
| 	lib/imagereader/imagereader.proto \ | ||||
| 	lib/imagewriter/imagewriter.proto \ | ||||
| 	lib/layout.proto \ | ||||
| 	lib/usb/usb.proto \ | ||||
| 	lib/vfs/vfs.proto \ | ||||
| 	tests/testproto.proto \ | ||||
|  | ||||
| PROTO_HDRS = $(patsubst %.proto, $(OBJDIR)/%.pb.h, $(PROTOS)) | ||||
| PROTO_SRCS = $(patsubst %.proto, $(OBJDIR)/%.pb.cc, $(PROTOS)) | ||||
| PROTO_OBJS = $(patsubst %.cc, %.o, $(PROTO_SRCS)) | ||||
| PROTO_CFLAGS = $(shell $(PKG_CONFIG) --cflags protobuf) | ||||
| $(PROTO_SRCS): | $(PROTO_HDRS) | ||||
| $(PROTO_OBJS): CFLAGS += $(PROTO_CFLAGS) | ||||
| PROTO_LIB = $(OBJDIR)/libproto.a | ||||
| $(PROTO_LIB): $(PROTO_OBJS) | ||||
| PROTO_LDFLAGS = $(shell $(PKG_CONFIG) --libs protobuf) -pthread | ||||
| .PRECIOUS: $(PROTO_HDRS) $(PROTO_SRCS) | ||||
|  | ||||
| include dep/agg/build.mk | ||||
| include dep/libusbp/build.mk | ||||
| include dep/stb/build.mk | ||||
| include dep/emu/build.mk | ||||
| include dep/fatfs/build.mk | ||||
| include dep/adflib/build.mk | ||||
| include dep/hfsutils/build.mk | ||||
| include scripts/build.mk | ||||
|  | ||||
| include lib/build.mk | ||||
| include arch/build.mk | ||||
| include src/build.mk | ||||
| include src/gui/build.mk | ||||
| include tools/build.mk | ||||
| include tests/build.mk | ||||
|  | ||||
| do-encodedecodetest = $(eval $(do-encodedecodetest-impl)) | ||||
| define do-encodedecodetest-impl | ||||
|  | ||||
| tests: $(OBJDIR)/$1$$(subst $$(space),_,$3).flux.encodedecode | ||||
| $(OBJDIR)/$1$$(subst $$(space),_,$3).flux.encodedecode: scripts/encodedecodetest.sh $(FLUXENGINE_BIN) $2 | ||||
| 	@mkdir -p $(dir $$@) | ||||
| 	@echo ENCODEDECODETEST $1 flux $(FLUXENGINE_BIN) $2 $3 | ||||
| 	@scripts/encodedecodetest.sh $1 flux $(FLUXENGINE_BIN) $2 $3 > $$@ | ||||
|  | ||||
| tests: $(OBJDIR)/$1$$(subst $$(space),_,$3).scp.encodedecode | ||||
| $(OBJDIR)/$1$$(subst $$(space),_,$3).scp.encodedecode: scripts/encodedecodetest.sh $(FLUXENGINE_BIN) $2 | ||||
| 	@mkdir -p $(dir $$@) | ||||
| 	@echo ENCODEDECODETEST $1 scp $(FLUXENGINE_BIN) $2 $3 | ||||
| 	@scripts/encodedecodetest.sh $1 scp $(FLUXENGINE_BIN) $2 $3 > $$@ | ||||
|  | ||||
| endef | ||||
|  | ||||
| $(call do-encodedecodetest,agat,,--drive.tpi=96) | ||||
| $(call do-encodedecodetest,amiga,,--drive.tpi=135) | ||||
| $(call do-encodedecodetest,apple2,,--140 --drive.tpi=96) | ||||
| $(call do-encodedecodetest,atarist,,--360 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,atarist,,--370 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,atarist,,--400 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,atarist,,--410 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,atarist,,--720 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,atarist,,--740 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,atarist,,--800 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,atarist,,--820 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,bk) | ||||
| $(call do-encodedecodetest,brother,,--120 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,brother,,--240 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,commodore,scripts/commodore1541_test.textpb,--171 --drive.tpi=96) | ||||
| $(call do-encodedecodetest,commodore,scripts/commodore1541_test.textpb,--192 --drive.tpi=96) | ||||
| $(call do-encodedecodetest,commodore,,--800 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,commodore,,--1620 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,hplif,,--264 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,hplif,,--616 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,hplif,,--770 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,ibm,,--1200 --drive.tpi=96) | ||||
| $(call do-encodedecodetest,ibm,,--1232 --drive.tpi=96) | ||||
| $(call do-encodedecodetest,ibm,,--1440 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,ibm,,--1680 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,ibm,,--180 --drive.tpi=96) | ||||
| $(call do-encodedecodetest,ibm,,--160 --drive.tpi=96) | ||||
| $(call do-encodedecodetest,ibm,,--320 --drive.tpi=96) | ||||
| $(call do-encodedecodetest,ibm,,--360 --drive.tpi=96) | ||||
| $(call do-encodedecodetest,ibm,,--720_96 --drive.tpi=96) | ||||
| $(call do-encodedecodetest,ibm,,--720_135 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,mac,scripts/mac400_test.textpb,--400 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,mac,scripts/mac800_test.textpb,--800 --drive.tpi=135) | ||||
| $(call do-encodedecodetest,n88basic,,--drive.tpi=96) | ||||
| $(call do-encodedecodetest,rx50,,--drive.tpi=96) | ||||
| $(call do-encodedecodetest,tids990,,--drive.tpi=48) | ||||
| $(call do-encodedecodetest,victor9k,,--612 --drive.tpi=96) | ||||
| $(call do-encodedecodetest,victor9k,,--1224 --drive.tpi=96) | ||||
|  | ||||
| do-corpustest = $(eval $(do-corpustest-impl)) | ||||
| define do-corpustest-impl | ||||
|  | ||||
| tests: $(OBJDIR)/corpustest/$2 | ||||
| $(OBJDIR)/corpustest/$2: $(FLUXENGINE_BIN) \ | ||||
| 		../fluxengine-testdata/data/$1 ../fluxengine-testdata/data/$2 | ||||
| 	@mkdir -p $(OBJDIR)/corpustest | ||||
| 	@echo CORPUSTEST $1 $2 $3 | ||||
| 	@$(FLUXENGINE_BIN) read $3 -s ../fluxengine-testdata/data/$1 -o $$@ > $$@.log | ||||
| 	@cmp $$@ ../fluxengine-testdata/data/$2 | ||||
|  | ||||
| endef | ||||
|  | ||||
| ifneq ($(wildcard ../fluxengine-testdata/data),) | ||||
|  | ||||
| $(call do-corpustest,amiga.flux,amiga.adf,amiga --drive.tpi=135) | ||||
| $(call do-corpustest,atarist360.flux,atarist360.st,atarist --360 --drive.tpi=135) | ||||
| $(call do-corpustest,atarist720.flux,atarist720.st,atarist --720 --drive.tpi=135) | ||||
| $(call do-corpustest,brother120.flux,brother120.img,brother --120 --drive.tpi=135) | ||||
| $(call do-corpustest,cmd-fd2000.flux,cmd-fd2000.img,commodore --1620 --drive.tpi=135) | ||||
| $(call do-corpustest,ibm1232.flux,ibm1232.img,ibm --1232 --drive.tpi=96) | ||||
| $(call do-corpustest,ibm1440.flux,ibm1440.img,ibm --1440 --drive.tpi=135) | ||||
| $(call do-corpustest,mac800.flux,mac800.dsk,mac --800 --drive.tpi=135) | ||||
| $(call do-corpustest,micropolis315.flux,micropolis315.img,micropolis --315 --drive.tpi=100) | ||||
| $(call do-corpustest,northstar87-synthetic.flux,northstar87-synthetic.nsi,northstar --87 --drive.tpi=48) | ||||
| $(call do-corpustest,northstar175-synthetic.flux,northstar175-synthetic.nsi,northstar --175 --drive.tpi=48) | ||||
| $(call do-corpustest,northstar350-synthetic.flux,northstar350-synthetic.nsi,northstar --350 --drive.tpi=48) | ||||
| $(call do-corpustest,victor9k_ss.flux,victor9k_ss.img,victor9k --612 --drive.tpi=96) | ||||
| $(call do-corpustest,victor9k_ds.flux,victor9k_ds.img,victor9k --1224 --drive.tpi=96) | ||||
| # Special OSX settings. | ||||
|  | ||||
| ifeq ($(shell uname),Darwin) | ||||
| 	LDFLAGS += \ | ||||
| 		-framework IOKit \ | ||||
| 		-framework Foundation  | ||||
| endif | ||||
|  | ||||
| $(OBJDIR)/%.a: | ||||
| 	@mkdir -p $(dir $@) | ||||
| 	@echo AR $@ | ||||
| 	@$(AR) rc $@ $^ | ||||
| .PHONY: all | ||||
| all: +all README.md | ||||
|  | ||||
| %.exe: | ||||
| 	@mkdir -p $(dir $@) | ||||
| 	@echo LINK $@ | ||||
| 	@$(CXX) -o $@ $(filter %.o,$^) $(filter %.a,$^) $(LDFLAGS) $(filter %.a,$^) $(LDFLAGS) | ||||
| .PHONY: binaries tests | ||||
| binaries: all | ||||
| tests: all | ||||
| 	 | ||||
| README.md: $(OBJ)/scripts/+mkdocindex/+mkdocindex$(EXT) | ||||
| 	@echo MKDOC $@ | ||||
| 	@csplit -s -f$(OBJ)/README. README.md '/<!-- FORMATSSTART -->/' '%<!-- FORMATSEND -->%' | ||||
| 	@(cat $(OBJ)/README.00 && $< && cat $(OBJ)/README.01) > README.md | ||||
|  | ||||
| $(OBJDIR)/%.o: %.cpp | ||||
| 	@mkdir -p $(dir $@) | ||||
| 	@echo CXX $< | ||||
| 	@$(CXX) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(@:.o=.d) -c -o $@ $< | ||||
| .PHONY: tests | ||||
|  | ||||
| $(OBJDIR)/%.o: %.cc | ||||
| 	@mkdir -p $(dir $@) | ||||
| 	@echo CXX $< | ||||
| 	@$(CXX) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(@:.o=.d) -c -o $@ $< | ||||
| .PHONY: install install-bin | ||||
| install:: all install-bin | ||||
|  | ||||
| $(OBJDIR)/%.o: $(OBJDIR)/%.cc | ||||
| 	@mkdir -p $(dir $@) | ||||
| 	@echo CXX $< | ||||
| 	@$(CXX) $(CFLAGS) $(CXXFLAGS) -MMD -MP -MF $(@:.o=.d) -c -o $@ $< | ||||
| clean:: | ||||
| 	$(hide) rm -rf $(REALOBJ) | ||||
|  | ||||
| $(OBJDIR)/%.o: %.c | ||||
| 	@mkdir -p $(dir $@) | ||||
| 	@echo CC $< | ||||
| 	@$(CC) $(CFLAGS) $(CFLAGS) -MMD -MP -MF $(@:.o=.d) -c -o $@ $< | ||||
| install-bin: | ||||
| 	@echo "INSTALL" | ||||
| 	$(hide) install -D -v "$(OBJ)/src+fluxengine/src+fluxengine" "$(DESTDIR)$(BINDIR)/fluxengine" | ||||
| 	$(hide) install -D -v "$(OBJ)/src/gui+gui/gui+gui" "$(DESTDIR)$(BINDIR)/fluxengine-gui" | ||||
| 	$(hide) install -D -v "$(OBJ)/tools+brother120tool/tools+brother120tool" "$(DESTDIR)$(BINDIR)/brother120tool" | ||||
| 	$(hide) install -D -v "$(OBJ)/tools+brother240tool/tools+brother240tool" "$(DESTDIR)$(BINDIR)/brother240tool" | ||||
| 	$(hide) install -D -v "$(OBJ)/tools+upgrade-flux-file/tools+upgrade-flux-file" "$(DESTDIR)$(BINDIR)/upgrade-flux-file" | ||||
|  | ||||
| $(OBJDIR)/%.pb.h: %.proto | ||||
| 	@mkdir -p $(dir $@) | ||||
| 	@echo PROTOC $@ | ||||
| 	@$(PROTOC) -I. --cpp_out=$(OBJDIR) $< | ||||
|  | ||||
| clean: | ||||
| 	rm -rf $(OBJDIR) | ||||
|  | ||||
| install: install-bin # install-man install-docs ... | ||||
|  | ||||
| install-bin: fluxengine$(EXT) fluxengine-gui$(EXT) brother120tool$(EXT) brother240tool$(EXT) upgrade-flux-file$(EXT) | ||||
| 	install -d "$(DESTDIR)$(BINDIR)" | ||||
| 	for target in $^; do \ | ||||
| 		install $$target "$(DESTDIR)$(BINDIR)/$$target"; \ | ||||
| 	done | ||||
|  | ||||
| -include $(OBJS:%.o=%.d) | ||||
| include build/ab.mk | ||||
|   | ||||
| @@ -128,17 +128,19 @@ choices because they can store multiple types of file system. | ||||
| | [`icl30`](doc/disk-icl30.md) | ICL Model 30: CP/M; 263kB 35-track DSSD | 🦖 |  | CPMFS  | | ||||
| | [`mac`](doc/disk-mac.md) | Macintosh: 400kB/800kB 3.5" GCR | 🦄 | 🦄 | MACHFS  | | ||||
| | [`micropolis`](doc/disk-micropolis.md) | Micropolis: 100tpi MetaFloppy disks | 🦄 | 🦄 |  | | ||||
| | [`ms2000`](doc/disk-ms2000.md) | : MS2000 Microdisk Development System |  |  | MICRODOS  | | ||||
| | [`mx`](doc/disk-mx.md) | DVK MX: Soviet-era PDP-11 clone | 🦖 |  |  | | ||||
| | [`n88basic`](doc/disk-n88basic.md) | N88-BASIC: PC8800/PC98 5.25" 77-track 26-sector DSHD | 🦄 | 🦄 |  | | ||||
| | [`northstar`](doc/disk-northstar.md) | Northstar: 5.25" hard sectored | 🦄 | 🦄 |  | | ||||
| | [`psos`](doc/disk-psos.md) | pSOS: 800kB DSDD with PHILE | 🦄 | 🦄 | PHILE  | | ||||
| | [`rolandd20`](doc/disk-rolandd20.md) | Roland D20: 3.5" electronic synthesiser disks | 🦖 |  |  | | ||||
| | [`rolandd20`](doc/disk-rolandd20.md) | Roland D20: 3.5" electronic synthesiser disks | 🦄 | 🦖 | ROLAND  | | ||||
| | [`rx50`](doc/disk-rx50.md) | Digital RX50: 400kB 5.25" 80-track 10-sector SSDD | 🦖 | 🦖 |  | | ||||
| | [`smaky6`](doc/disk-smaky6.md) | Smaky 6: 308kB 5.25" 77-track 16-sector SSDD, hard sectored | 🦖 |  | SMAKY6  | | ||||
| | [`tartu`](doc/disk-tartu.md) | Tartu: The Palivere and variations | 🦄 |  | CPMFS  | | ||||
| | [`tids990`](doc/disk-tids990.md) | Texas Instruments DS990: 1126kB 8" DSSD | 🦖 | 🦖 |  | | ||||
| | [`tiki`](doc/disk-tiki.md) | Tiki 100: CP/M |  |  | CPMFS  | | ||||
| | [`victor9k`](doc/disk-victor9k.md) | Victor 9000 / Sirius One: 1224kB 5.25" DSDD GCR | 🦖 | 🦖 |  | | ||||
| | [`zilogmcz`](doc/disk-zilogmcz.md) | Zilog MCZ: 320kB 8" 77-track SSSD hard-sectored | 🦖 |  |  | | ||||
| | [`zilogmcz`](doc/disk-zilogmcz.md) | Zilog MCZ: 320kB 8" 77-track SSSD hard-sectored | 🦖 |  | ZDOS  | | ||||
| {: .datatable } | ||||
|  | ||||
| <!-- FORMATSEND --> | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "aeslanier.h" | ||||
| #include "crc.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "sector.h" | ||||
| #include "bytes.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "lib/sector.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include <string.h> | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "agat.h" | ||||
| #include "bytes.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "fmt/format.h" | ||||
|  | ||||
| uint8_t agatChecksum(const Bytes& bytes) | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "agat.h" | ||||
| #include "crc.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "sector.h" | ||||
| #include "bytes.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "lib/sector.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include <string.h> | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "amiga.h" | ||||
| #include "bytes.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "fmt/format.h" | ||||
|  | ||||
| uint32_t amigaChecksum(const Bytes& bytes) | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| #ifndef AMIGA_H | ||||
| #define AMIGA_H | ||||
|  | ||||
| #include "encoders/encoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
|  | ||||
| #define AMIGA_SECTOR_RECORD 0xaaaa44894489LL | ||||
|  | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "protocol.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "amiga.h" | ||||
| #include "bytes.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include "lib/decoders/decoders.pb.h" | ||||
| #include <string.h> | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "amiga.h" | ||||
| #include "crc.h" | ||||
| #include "readerwriter.h" | ||||
| #include "image.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/readerwriter.h" | ||||
| #include "lib/image.h" | ||||
| #include "arch/amiga/amiga.pb.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
|  | ||||
|   | ||||
| @@ -2,8 +2,8 @@ | ||||
| #define APPLE2_H | ||||
|  | ||||
| #include <memory.h> | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
|  | ||||
| #define APPLE2_SECTOR_RECORD 0xd5aa96 | ||||
| #define APPLE2_DATA_RECORD 0xd5aaad | ||||
|   | ||||
| @@ -1,13 +1,13 @@ | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "protocol.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "apple2.h" | ||||
| #include "arch/apple2/apple2.pb.h" | ||||
| #include "lib/decoders/decoders.pb.h" | ||||
| #include "bytes.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include <string.h> | ||||
| #include <algorithm> | ||||
|   | ||||
| @@ -1,14 +1,14 @@ | ||||
| #include "globals.h" | ||||
| #include "lib/globals.h" | ||||
| #include "arch/apple2/apple2.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "sector.h" | ||||
| #include "readerwriter.h" | ||||
| #include "image.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "lib/readerwriter.h" | ||||
| #include "lib/image.h" | ||||
| #include "fmt/format.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
| #include <ctype.h> | ||||
| #include "bytes.h" | ||||
| #include "lib/bytes.h" | ||||
|  | ||||
| static int encode_data_gcr(uint8_t data) | ||||
| { | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "brother.h" | ||||
| #include "sector.h" | ||||
| #include "bytes.h" | ||||
| #include "crc.h" | ||||
| #include "lib/sector.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "lib/crc.h" | ||||
| #include <ctype.h> | ||||
|  | ||||
| const FluxPattern SECTOR_RECORD_PATTERN(32, BROTHER_SECTOR_RECORD); | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "brother.h" | ||||
| #include "crc.h" | ||||
| #include "readerwriter.h" | ||||
| #include "image.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/readerwriter.h" | ||||
| #include "lib/image.h" | ||||
| #include "arch/brother/brother.pb.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
|  | ||||
|   | ||||
| @@ -1,43 +0,0 @@ | ||||
| LIBARCH_SRCS = \ | ||||
| 	arch/aeslanier/decoder.cc \ | ||||
| 	arch/agat/agat.cc \ | ||||
| 	arch/agat/decoder.cc \ | ||||
| 	arch/agat/encoder.cc \ | ||||
| 	arch/amiga/amiga.cc \ | ||||
| 	arch/amiga/decoder.cc \ | ||||
| 	arch/amiga/encoder.cc \ | ||||
| 	arch/apple2/decoder.cc \ | ||||
| 	arch/apple2/encoder.cc \ | ||||
| 	arch/brother/decoder.cc \ | ||||
| 	arch/brother/encoder.cc \ | ||||
| 	arch/c64/c64.cc \ | ||||
| 	arch/c64/decoder.cc \ | ||||
| 	arch/c64/encoder.cc \ | ||||
| 	arch/f85/decoder.cc \ | ||||
| 	arch/fb100/decoder.cc \ | ||||
| 	arch/ibm/decoder.cc \ | ||||
| 	arch/ibm/encoder.cc \ | ||||
| 	arch/macintosh/decoder.cc \ | ||||
| 	arch/macintosh/encoder.cc \ | ||||
| 	arch/micropolis/decoder.cc \ | ||||
| 	arch/micropolis/encoder.cc \ | ||||
| 	arch/mx/decoder.cc \ | ||||
| 	arch/northstar/decoder.cc \ | ||||
| 	arch/northstar/encoder.cc \ | ||||
| 	arch/rolandd20/decoder.cc \ | ||||
| 	arch/smaky6/decoder.cc \ | ||||
| 	arch/tids990/decoder.cc \ | ||||
| 	arch/tids990/encoder.cc \ | ||||
| 	arch/victor9k/decoder.cc \ | ||||
| 	arch/victor9k/encoder.cc \ | ||||
| 	arch/zilogmcz/decoder.cc \ | ||||
|  | ||||
| LIBARCH_OBJS = $(patsubst %.cc, $(OBJDIR)/%.o, $(LIBARCH_SRCS)) | ||||
| OBJS += $(LIBARCH_OBJS) | ||||
| $(LIBARCH_SRCS): | $(PROTO_HDRS) | ||||
| $(LIBARCH_SRCS): CFLAGS += $(PROTO_CFLAGS) | ||||
| LIBARCH_LIB = $(OBJDIR)/libarch.a | ||||
| LIBARCH_LDFLAGS = | ||||
| $(LIBARCH_LIB): $(LIBARCH_OBJS) | ||||
|  | ||||
| $(call use-pkgconfig, $(LIBARCH_LIB), $(LIBARCH_OBJS), fmt) | ||||
							
								
								
									
										27
									
								
								arch/build.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								arch/build.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| from build.c import cxxlibrary | ||||
| from build.protobuf import proto, protocc | ||||
|  | ||||
| proto( | ||||
|     name="arch_proto", | ||||
|     srcs=[ | ||||
|         "./aeslanier/aeslanier.proto", | ||||
|         "./agat/agat.proto", | ||||
|         "./amiga/amiga.proto", | ||||
|         "./apple2/apple2.proto", | ||||
|         "./brother/brother.proto", | ||||
|         "./c64/c64.proto", | ||||
|         "./f85/f85.proto", | ||||
|         "./fb100/fb100.proto", | ||||
|         "./ibm/ibm.proto", | ||||
|         "./macintosh/macintosh.proto", | ||||
|         "./micropolis/micropolis.proto", | ||||
|         "./mx/mx.proto", | ||||
|         "./northstar/northstar.proto", | ||||
|         "./rolandd20/rolandd20.proto", | ||||
|         "./smaky6/smaky6.proto", | ||||
|         "./tartu/tartu.proto", | ||||
|         "./tids990/tids990.proto", | ||||
|         "./victor9k/victor9k.proto", | ||||
|         "./zilogmcz/zilogmcz.proto", | ||||
|     ], | ||||
| ) | ||||
| @@ -1,4 +1,4 @@ | ||||
| #include "globals.h" | ||||
| #include "lib/globals.h" | ||||
| #include "c64.h" | ||||
|  | ||||
| /* | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| #ifndef C64_H | ||||
| #define C64_H | ||||
|  | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
|  | ||||
| #define C64_SECTOR_RECORD 0xffd49 | ||||
| #define C64_DATA_RECORD 0xffd57 | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "protocol.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "c64.h" | ||||
| #include "crc.h" | ||||
| #include "bytes.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include <string.h> | ||||
| #include <algorithm> | ||||
|   | ||||
| @@ -1,17 +1,17 @@ | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "c64.h" | ||||
| #include "crc.h" | ||||
| #include "sector.h" | ||||
| #include "readerwriter.h" | ||||
| #include "image.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/sector.h" | ||||
| #include "lib/readerwriter.h" | ||||
| #include "lib/image.h" | ||||
| #include "fmt/format.h" | ||||
| #include "arch/c64/c64.pb.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
| #include "lib/layout.h" | ||||
| #include <ctype.h> | ||||
| #include "bytes.h" | ||||
| #include "lib/bytes.h" | ||||
|  | ||||
| static bool lastBit; | ||||
|  | ||||
| @@ -51,26 +51,6 @@ static void write_bits( | ||||
|     } | ||||
| } | ||||
|  | ||||
| void bindump(std::ostream& stream, std::vector<bool>& buffer) | ||||
| { | ||||
|     size_t pos = 0; | ||||
|  | ||||
|     while ((pos < buffer.size()) and (pos < 520)) | ||||
|     { | ||||
|         stream << fmt::format("{:5d} : ", pos); | ||||
|         for (int i = 0; i < 40; i++) | ||||
|         { | ||||
|             if ((pos + i) < buffer.size()) | ||||
|                 stream << fmt::format("{:01b}", (buffer[pos + i])); | ||||
|             else | ||||
|                 stream << "-- "; | ||||
|             if ((((pos + i + 1) % 8) == 0) and i != 0) | ||||
|                 stream << "  "; | ||||
|         } | ||||
|         stream << std::endl; | ||||
|         pos += 40; | ||||
|     } | ||||
| } | ||||
| static std::vector<bool> encode_data(uint8_t input) | ||||
| { | ||||
|     /* | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "protocol.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "f85.h" | ||||
| #include "crc.h" | ||||
| #include "bytes.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include <string.h> | ||||
| #include <algorithm> | ||||
|   | ||||
| @@ -1,13 +1,13 @@ | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "protocol.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "fb100.h" | ||||
| #include "crc.h" | ||||
| #include "bytes.h" | ||||
| #include "decoders/rawbits.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "lib/decoders/rawbits.h" | ||||
| #include "fmt/format.h" | ||||
| #include <string.h> | ||||
| #include <algorithm> | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "ibm.h" | ||||
| #include "crc.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "sector.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "lib/sector.h" | ||||
| #include "arch/ibm/ibm.pb.h" | ||||
| #include "proto.h" | ||||
| #include "lib/proto.h" | ||||
| #include "lib/layout.h" | ||||
| #include <string.h> | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "ibm.h" | ||||
| #include "crc.h" | ||||
| #include "readerwriter.h" | ||||
| #include "image.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/readerwriter.h" | ||||
| #include "lib/image.h" | ||||
| #include "arch/ibm/ibm.pb.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
| #include "fmt/format.h" | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "protocol.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "macintosh.h" | ||||
| #include "bytes.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include <string.h> | ||||
| #include <algorithm> | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "macintosh.h" | ||||
| #include "crc.h" | ||||
| #include "readerwriter.h" | ||||
| #include "image.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/readerwriter.h" | ||||
| #include "lib/image.h" | ||||
| #include "fmt/format.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
| #include "lib/layout.h" | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "micropolis.h" | ||||
| #include "bytes.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include "lib/decoders/decoders.pb.h" | ||||
|  | ||||
| @@ -59,6 +59,76 @@ uint8_t mzosChecksum(const Bytes& bytes) | ||||
|     return checksum; | ||||
| } | ||||
|  | ||||
| static uint8_t b(uint32_t field, uint8_t pos) | ||||
| { | ||||
|     return (field >> pos) & 1; | ||||
| } | ||||
|  | ||||
| static uint8_t eccNextBit(uint32_t ecc, uint8_t data_bit) | ||||
| { | ||||
|     // This is 0x81932080 which is 0x0104C981 with reversed bits | ||||
|     return b(ecc, 7) ^ b(ecc, 13) ^ b(ecc, 16) ^ b(ecc, 17) ^ b(ecc, 20) ^ | ||||
|            b(ecc, 23) ^ b(ecc, 24) ^ b(ecc, 31) ^ data_bit; | ||||
| } | ||||
|  | ||||
| uint32_t vectorGraphicEcc(const Bytes& bytes) | ||||
| { | ||||
|     uint32_t e = 0; | ||||
|     Bytes payloadBytes = bytes.slice(0, bytes.size() - 4); | ||||
|     ByteReader payload(payloadBytes); | ||||
|     while (!payload.eof()) | ||||
|     { | ||||
|         uint8_t byte = payload.read_8(); | ||||
|         for (int i = 0; i < 8; i++) | ||||
|         { | ||||
|             e = (e << 1) | eccNextBit(e, byte >> 7); | ||||
|             byte <<= 1; | ||||
|         } | ||||
|     } | ||||
|     Bytes trailerBytes = bytes.slice(bytes.size() - 4); | ||||
|     ByteReader trailer(trailerBytes); | ||||
|     uint32_t res = e; | ||||
|     while (!trailer.eof()) | ||||
|     { | ||||
|         uint8_t byte = trailer.read_8(); | ||||
|         for (int i = 0; i < 8; i++) | ||||
|         { | ||||
|             res = (res << 1) | eccNextBit(e, byte >> 7); | ||||
|             e <<= 1; | ||||
|             byte <<= 1; | ||||
|         } | ||||
|     } | ||||
|     return res; | ||||
| } | ||||
|  | ||||
| /* Fixes bytes when possible, returning true if changed. */ | ||||
| static bool vectorGraphicEccFix(Bytes& bytes, uint32_t syndrome) | ||||
| { | ||||
|     uint32_t ecc = syndrome; | ||||
|     int pos = (MICROPOLIS_ENCODED_SECTOR_SIZE - 5) * 8 + 7; | ||||
|     bool aligned = false; | ||||
|     while ((ecc & 0xff000000) == 0) | ||||
|     { | ||||
|         pos += 8; | ||||
|         ecc <<= 8; | ||||
|     } | ||||
|     for (; pos >= 0; pos--) | ||||
|     { | ||||
|         bool bit = ecc & 1; | ||||
|         ecc >>= 1; | ||||
|         if (bit) | ||||
|             ecc ^= 0x808264c0; | ||||
|         if ((ecc & 0xff07ffff) == 0) | ||||
|             aligned = true; | ||||
|         if (aligned && pos % 8 == 0) | ||||
|             break; | ||||
|     } | ||||
|     if (pos < 0) | ||||
|         return false; | ||||
|     bytes[pos / 8] ^= ecc >> 16; | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| class MicropolisDecoder : public Decoder | ||||
| { | ||||
| public: | ||||
| @@ -85,9 +155,10 @@ public: | ||||
|         /* Discard a possible partial sector at the end of the track. | ||||
|          * This partial sector could be mistaken for a conflicted sector, if | ||||
|          * whatever data read happens to match the checksum of 0, which is | ||||
|          * rare, but has been observed on some disks. | ||||
|          * rare, but has been observed on some disks. There's 570uS of slack in | ||||
|          * each sector, after accounting for preamble, data, and postamble. | ||||
|          */ | ||||
|         if (now > (getFluxmapDuration() - 12.5e6)) | ||||
|         if (now > (getFluxmapDuration() - 12.0e6)) | ||||
|         { | ||||
|             seekToIndexMark(); | ||||
|             return 0; | ||||
| @@ -114,9 +185,10 @@ public: | ||||
|         _sector->headerStartTime = tell().ns(); | ||||
|  | ||||
|         /* seekToPattern() can skip past the index hole, if this happens | ||||
|          * too close to the end of the Fluxmap, discard the sector. | ||||
|          * too close to the end of the Fluxmap, discard the sector. The | ||||
|          * preamble was expected to be 640uS long. | ||||
|          */ | ||||
|         if (_sector->headerStartTime > (getFluxmapDuration() - 12.5e6)) | ||||
|         if (_sector->headerStartTime > (getFluxmapDuration() - 11.3e6)) | ||||
|         { | ||||
|             return 0; | ||||
|         } | ||||
| @@ -130,6 +202,19 @@ public: | ||||
|         auto rawbits = readRawBits(MICROPOLIS_ENCODED_SECTOR_SIZE * 16); | ||||
|         auto bytes = | ||||
|             decodeFmMfm(rawbits).slice(0, MICROPOLIS_ENCODED_SECTOR_SIZE); | ||||
|  | ||||
|         bool eccPresent = bytes[274] == 0xaa; | ||||
|         uint32_t ecc = 0; | ||||
|         if (_config.ecc_type() == MicropolisDecoderProto::VECTOR && eccPresent) | ||||
|         { | ||||
|             ecc = vectorGraphicEcc(bytes.slice(0, 274)); | ||||
|             if (ecc != 0) | ||||
|             { | ||||
|                 vectorGraphicEccFix(bytes, ecc); | ||||
|                 ecc = vectorGraphicEcc(bytes.slice(0, 274)); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         ByteReader br(bytes); | ||||
|  | ||||
|         int syncByte = br.read_8(); /* sync */ | ||||
| @@ -191,8 +276,10 @@ public: | ||||
|             _sector->data = bytes; | ||||
|         else | ||||
|             error("Sector output size may only be 256 or 275"); | ||||
|         _sector->status = | ||||
|             (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
|         if (wantChecksum == gotChecksum && (!eccPresent || ecc == 0)) | ||||
|             _sector->status = Sector::OK; | ||||
|         else | ||||
|             _sector->status = Sector::BAD_CHECKSUM; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|   | ||||
| @@ -1,14 +1,15 @@ | ||||
| #include "globals.h" | ||||
| #include "lib/globals.h" | ||||
| #include "micropolis.h" | ||||
| #include "sector.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "image.h" | ||||
| #include "lib/sector.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "lib/image.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
|  | ||||
| static void write_sector(std::vector<bool>& bits, | ||||
|     unsigned& cursor, | ||||
|     const std::shared_ptr<const Sector>& sector) | ||||
|     const std::shared_ptr<const Sector>& sector, | ||||
|     MicropolisEncoderProto::EccType eccType) | ||||
| { | ||||
|     if ((sector->data.size() != 256) && | ||||
|         (sector->data.size() != MICROPOLIS_ENCODED_SECTOR_SIZE)) | ||||
| @@ -45,8 +46,16 @@ static void write_sector(std::vector<bool>& bits, | ||||
|             writer.write_8(0); /* Padding */ | ||||
|         writer += sector->data; | ||||
|         writer.write_8(micropolisChecksum(sectorData.slice(1))); | ||||
|         for (int i = 0; i < 5; i++) | ||||
|             writer.write_8(0); /* 4 byte ECC and ECC not present flag */ | ||||
|  | ||||
|         uint8_t eccPresent = 0; | ||||
|         uint32_t ecc = 0; | ||||
|         if (eccType == MicropolisEncoderProto::VECTOR) | ||||
|         { | ||||
|             eccPresent = 0xaa; | ||||
|             ecc = vectorGraphicEcc(sectorData + Bytes(4)); | ||||
|         } | ||||
|         writer.write_be32(ecc); | ||||
|         writer.write_8(eccPresent); | ||||
|     } | ||||
|     for (uint8_t b : sectorData) | ||||
|         fullSector->push_back(b); | ||||
| @@ -86,18 +95,34 @@ public: | ||||
|             (_config.rotational_period_ms() * 1e3) / _config.clock_period_us(); | ||||
|  | ||||
|         std::vector<bool> bits(bitsPerRevolution); | ||||
|         std::vector<unsigned> indexes; | ||||
|         unsigned prev_cursor = 0; | ||||
|         unsigned cursor = 0; | ||||
|  | ||||
|         for (const auto& sectorData : sectors) | ||||
|             write_sector(bits, cursor, sectorData); | ||||
|         { | ||||
|             indexes.push_back(cursor); | ||||
|             prev_cursor = cursor; | ||||
|             write_sector(bits, cursor, sectorData, _config.ecc_type()); | ||||
|         } | ||||
|         indexes.push_back(prev_cursor + (cursor - prev_cursor) / 2); | ||||
|         indexes.push_back(cursor); | ||||
|  | ||||
|         if (cursor != bits.size()) | ||||
|             error("track data mismatched length"); | ||||
|  | ||||
|         std::unique_ptr<Fluxmap> fluxmap(new Fluxmap); | ||||
|         fluxmap->appendBits(bits, | ||||
|         nanoseconds_t clockPeriod = | ||||
|             calculatePhysicalClockPeriod(_config.clock_period_us() * 1e3, | ||||
|                 _config.rotational_period_ms() * 1e6)); | ||||
|                 _config.rotational_period_ms() * 1e6); | ||||
|         auto pos = bits.begin(); | ||||
|         for (int i = 1; i < indexes.size(); i++) | ||||
|         { | ||||
|             auto end = bits.begin() + indexes[i]; | ||||
|             fluxmap->appendBits(std::vector<bool>(pos, end), clockPeriod); | ||||
|             fluxmap->appendIndex(); | ||||
|             pos = end; | ||||
|         } | ||||
|         return fluxmap; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -17,5 +17,6 @@ extern std::unique_ptr<Encoder> createMicropolisEncoder( | ||||
|     const EncoderProto& config); | ||||
|  | ||||
| extern uint8_t micropolisChecksum(const Bytes& bytes); | ||||
| extern uint32_t vectorGraphicEcc(const Bytes& bytes); | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -8,17 +8,30 @@ message MicropolisDecoderProto { | ||||
| 		MICROPOLIS = 1; | ||||
| 		MZOS = 2; | ||||
| 	} | ||||
| 	enum EccType { | ||||
| 		NONE = 0; | ||||
| 		VECTOR = 1; | ||||
| 	} | ||||
|  | ||||
| 	optional int32 sector_output_size = 1 [default = 256, | ||||
| 		(help) = "How much of the raw sector should be saved. Must be 256 or 275"]; | ||||
| 	optional ChecksumType checksum_type = 2 [default = AUTO, | ||||
| 		(help) = "Checksum type to use: AUTO, MICROPOLIS, MZOS"]; | ||||
| 	optional EccType ecc_type = 3 [default = NONE, | ||||
| 		(help) = "ECC type to use: NONE, VECTOR"]; | ||||
| } | ||||
|  | ||||
| message MicropolisEncoderProto { | ||||
|     enum EccType { | ||||
|         NONE = 0; | ||||
|         VECTOR = 1; | ||||
|     } | ||||
|  | ||||
|     optional double clock_period_us = 1 | ||||
|         [ default = 2.0, (help) = "clock rate on the real device" ]; | ||||
|     optional double rotational_period_ms = 2 | ||||
|         [ default = 200.0, (help) = "rotational period on the real device" ]; | ||||
|     optional EccType ecc_type = 3 [default = NONE, | ||||
|         (help) = "ECC type to use for IMG data: NONE, VECTOR"]; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "mx/mx.h" | ||||
| #include "crc.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "sector.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "arch/mx/mx.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "lib/sector.h" | ||||
| #include <string.h> | ||||
|  | ||||
| const int SECTOR_SIZE = 256; | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| #ifndef MX_H | ||||
| #define MX_H | ||||
|  | ||||
| #include "decoders/decoders.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
|  | ||||
| extern std::unique_ptr<Decoder> createMxDecoder(const DecoderProto& config); | ||||
|  | ||||
|   | ||||
| @@ -11,13 +11,13 @@ | ||||
|  * sure that the hardSectorId is correct. | ||||
|  */ | ||||
|  | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "northstar.h" | ||||
| #include "bytes.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "lib/decoders/decoders.pb.h" | ||||
| #include "fmt/format.h" | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| #include "globals.h" | ||||
| #include "lib/globals.h" | ||||
| #include "northstar.h" | ||||
| #include "sector.h" | ||||
| #include "bytes.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "image.h" | ||||
| #include "lib/sector.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "lib/image.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
|  | ||||
| #define GAP_FILL_SIZE_SD 30 | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "protocol.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "smaky6.h" | ||||
| #include "bytes.h" | ||||
| #include "crc.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "lib/crc.h" | ||||
| #include "fmt/format.h" | ||||
| #include "lib/decoders/decoders.pb.h" | ||||
| #include <string.h> | ||||
|   | ||||
| @@ -1,6 +1,4 @@ | ||||
| syntax = "proto2"; | ||||
|  | ||||
| import "lib/common.proto"; | ||||
|  | ||||
| message Smaky6DecoderProto {} | ||||
|  | ||||
|   | ||||
							
								
								
									
										84
									
								
								arch/tartu/decoder.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								arch/tartu/decoder.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "arch/tartu/tartu.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "lib/sector.h" | ||||
| #include <string.h> | ||||
|  | ||||
| constexpr uint64_t HEADER_BITS = 0xaaaaaaaa44895554LL; | ||||
| constexpr uint64_t DATA_BITS =   0xaaaaaaaa44895545LL; | ||||
|  | ||||
| static const FluxPattern HEADER_PATTERN(64, HEADER_BITS); | ||||
| static const FluxPattern DATA_PATTERN(64, DATA_BITS); | ||||
|  | ||||
| const FluxMatchers ANY_RECORD_PATTERN { | ||||
|     &HEADER_PATTERN, | ||||
|     &DATA_PATTERN | ||||
| }; | ||||
|  | ||||
| class TartuDecoder : public Decoder | ||||
| { | ||||
| public: | ||||
|     TartuDecoder(const DecoderProto& config): | ||||
|         Decoder(config), | ||||
|         _config(config.tartu()) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     void beginTrack() override | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     nanoseconds_t advanceToNextRecord() override | ||||
|     { | ||||
|         return seekToPattern(ANY_RECORD_PATTERN); | ||||
|     } | ||||
|  | ||||
|     void decodeSectorRecord() override | ||||
|     { | ||||
|         if (readRaw64() != HEADER_BITS) | ||||
|             return; | ||||
|  | ||||
|         auto bits = readRawBits(16 * 4); | ||||
|         auto bytes = decodeFmMfm(bits).slice(0, 4); | ||||
|          | ||||
|         ByteReader br(bytes); | ||||
|         uint8_t track = br.read_8(); | ||||
|         _sector->logicalTrack = track >> 1; | ||||
|         _sector->logicalSide = track & 1; | ||||
|         br.skip(1); /* seems always to be 1 */ | ||||
|         _sector->logicalSector = br.read_8(); | ||||
|         uint8_t wantChecksum = br.read_8(); | ||||
|         uint8_t gotChecksum = ~sumBytes(bytes.slice(0, 3)); | ||||
|          | ||||
|         if (wantChecksum == gotChecksum) | ||||
|             _sector->status = Sector::DATA_MISSING; | ||||
|  | ||||
|         _sector->status = Sector::DATA_MISSING; | ||||
|     } | ||||
|  | ||||
|     void decodeDataRecord() override | ||||
|     { | ||||
|         if (readRaw64() != DATA_BITS) | ||||
|             return; | ||||
|      | ||||
|         const auto& bits = readRawBits(129 * 16); | ||||
|         const auto& bytes = decodeFmMfm(bits).slice(0, 129); | ||||
|         _sector->data = bytes.slice(0, 128); | ||||
|  | ||||
|         uint8_t wantChecksum = bytes.reader().seek(128).read_8(); | ||||
|         uint8_t gotChecksum = ~sumBytes(_sector->data); | ||||
|         _sector->status = (wantChecksum == gotChecksum) ? Sector::OK : Sector::BAD_CHECKSUM; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     const TartuDecoderProto& _config; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Decoder> createTartuDecoder(const DecoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Decoder>(new TartuDecoder(config)); | ||||
| } | ||||
|  | ||||
							
								
								
									
										114
									
								
								arch/tartu/encoder.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								arch/tartu/encoder.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,114 @@ | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "arch/tartu/tartu.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/sector.h" | ||||
| #include <string.h> | ||||
|  | ||||
| class TartuEncoder : public Encoder | ||||
| { | ||||
| public: | ||||
|     TartuEncoder(const EncoderProto& config): | ||||
|         Encoder(config), | ||||
|         _config(config.tartu()) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     std::unique_ptr<Fluxmap> encode(std::shared_ptr<const TrackInfo>& trackInfo, | ||||
|         const std::vector<std::shared_ptr<const Sector>>& sectors, | ||||
|         const Image& image) override | ||||
|     { | ||||
|         _clockRateUs = _config.clock_period_us(); | ||||
|         int bitsPerRevolution = | ||||
|             (_config.target_rotational_period_ms() * 1000.0) / _clockRateUs; | ||||
|  | ||||
|         const auto& sector = *sectors.begin(); | ||||
|         _bits.resize(bitsPerRevolution); | ||||
|         _cursor = 0; | ||||
|  | ||||
|         writeFillerRawBitsUs(_config.gap1_us()); | ||||
|         bool first = true; | ||||
|         for (const auto& sectorData : sectors) | ||||
|         { | ||||
|             if (!first) | ||||
|                 writeFillerRawBitsUs(_config.gap4_us()); | ||||
|             first = false; | ||||
|             writeSector(sectorData); | ||||
|         } | ||||
|  | ||||
|         if (_cursor > _bits.size()) | ||||
|             error("track data overrun"); | ||||
|         writeFillerRawBitsUs(_config.target_rotational_period_ms() * 1000.0); | ||||
|  | ||||
|         std::unique_ptr<Fluxmap> fluxmap(new Fluxmap); | ||||
|         fluxmap->appendBits(_bits, | ||||
|             calculatePhysicalClockPeriod(_clockRateUs * 1e3, | ||||
|                 _config.target_rotational_period_ms() * 1e6)); | ||||
|         return fluxmap; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     void writeBytes(const Bytes& bytes) | ||||
|     { | ||||
|         encodeMfm(_bits, _cursor, bytes, _lastBit); | ||||
|     } | ||||
|  | ||||
|     void writeRawBits(uint64_t data, int width) | ||||
|     { | ||||
|         _cursor += width; | ||||
|         _lastBit = data & 1; | ||||
|         for (int i = 0; i < width; i++) | ||||
|         { | ||||
|             unsigned pos = _cursor - i - 1; | ||||
|             if (pos < _bits.size()) | ||||
|                 _bits[pos] = data & 1; | ||||
|             data >>= 1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void writeFillerRawBitsUs(double us) | ||||
|     { | ||||
|         unsigned count = (us / _clockRateUs) / 2; | ||||
|         for (int i = 0; i < count; i++) | ||||
|             writeRawBits(0b10, 2); | ||||
|     }; | ||||
|  | ||||
|     void writeSector(const std::shared_ptr<const Sector>& sectorData) | ||||
|     { | ||||
|         writeRawBits(_config.header_marker(), 64); | ||||
|         { | ||||
|             Bytes bytes; | ||||
|             ByteWriter bw(bytes); | ||||
|             bw.write_8( | ||||
|                 (sectorData->logicalTrack << 1) | sectorData->logicalSide); | ||||
|             bw.write_8(1); | ||||
|             bw.write_8(sectorData->logicalSector); | ||||
|             bw.write_8(~sumBytes(bytes.slice(0, 3))); | ||||
|             writeBytes(bytes); | ||||
|         } | ||||
|  | ||||
|         writeFillerRawBitsUs(_config.gap3_us()); | ||||
|         writeRawBits(_config.data_marker(), 64); | ||||
|         { | ||||
|             Bytes bytes; | ||||
|             ByteWriter bw(bytes); | ||||
|             bw.append(sectorData->data); | ||||
|             bw.write_8(~sumBytes(bytes.slice(0, sectorData->data.size()))); | ||||
|             writeBytes(bytes); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     const TartuEncoderProto& _config; | ||||
|     double _clockRateUs; | ||||
|     std::vector<bool> _bits; | ||||
|     unsigned _cursor; | ||||
|     bool _lastBit; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Encoder> createTartuEncoder(const EncoderProto& config) | ||||
| { | ||||
|     return std::unique_ptr<Encoder>(new TartuEncoder(config)); | ||||
| } | ||||
							
								
								
									
										8
									
								
								arch/tartu/tartu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								arch/tartu/tartu.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| #ifndef TARTU_H | ||||
| #define TARTU_H | ||||
|  | ||||
| extern std::unique_ptr<Decoder> createTartuDecoder(const DecoderProto& config); | ||||
| extern std::unique_ptr<Encoder> createTartuEncoder(const EncoderProto& config); | ||||
|  | ||||
| #endif | ||||
|  | ||||
							
								
								
									
										27
									
								
								arch/tartu/tartu.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								arch/tartu/tartu.proto
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| syntax = "proto2"; | ||||
|  | ||||
| import "lib/common.proto"; | ||||
|  | ||||
| message TartuDecoderProto {} | ||||
|  | ||||
| message TartuEncoderProto { | ||||
|     optional double clock_period_us = 1 | ||||
|         [ default = 2.0, (help) = "clock rate on the real device (for MFM)" ]; | ||||
|     optional double target_rotational_period_ms = 2 | ||||
|         [ default=200, (help) = "rotational period of target disk" ]; | ||||
|     optional double gap1_us = 3 | ||||
|         [ default = 1200, | ||||
|           (help) = "size of gap 1 (the post-index gap)" ]; | ||||
|     optional double gap3_us = 4 | ||||
|         [ default = 150, | ||||
|           (help) = "size of gap 3 (the pre-data gap)" ]; | ||||
|     optional double gap4_us = 5 | ||||
|         [ default = 180, | ||||
|           (help) = "size of gap 4 (the post-data or format gap)" ]; | ||||
|     optional uint64 header_marker = 6 | ||||
|         [ default = 0xaaaaaaaa44895554, | ||||
|           (help) = "64-bit raw bit pattern of header record marker" ]; | ||||
|     optional uint64 data_marker = 7 | ||||
|         [ default = 0xaaaaaaaa44895545, | ||||
|           (help) = "64-bit raw bit pattern of data record marker" ]; | ||||
| } | ||||
| @@ -1,11 +1,11 @@ | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "tids990/tids990.h" | ||||
| #include "crc.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "sector.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "arch/tids990/tids990.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "lib/sector.h" | ||||
| #include <string.h> | ||||
| #include <fmt/format.h> | ||||
|  | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "tids990.h" | ||||
| #include "crc.h" | ||||
| #include "readerwriter.h" | ||||
| #include "image.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/readerwriter.h" | ||||
| #include "lib/image.h" | ||||
| #include "arch/tids990/tids990.pb.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
| #include <fmt/format.h> | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "protocol.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "victor9k.h" | ||||
| #include "crc.h" | ||||
| #include "bytes.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "fmt/format.h" | ||||
| #include <string.h> | ||||
| #include <algorithm> | ||||
|   | ||||
| @@ -1,17 +1,17 @@ | ||||
| #include "globals.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "encoders/encoders.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/encoders/encoders.h" | ||||
| #include "victor9k.h" | ||||
| #include "crc.h" | ||||
| #include "sector.h" | ||||
| #include "readerwriter.h" | ||||
| #include "image.h" | ||||
| #include "lib/crc.h" | ||||
| #include "lib/sector.h" | ||||
| #include "lib/readerwriter.h" | ||||
| #include "lib/image.h" | ||||
| #include "fmt/format.h" | ||||
| #include "arch/victor9k/victor9k.pb.h" | ||||
| #include "lib/encoders/encoders.pb.h" | ||||
| #include "lib/layout.h" | ||||
| #include <ctype.h> | ||||
| #include "bytes.h" | ||||
| #include "lib/bytes.h" | ||||
|  | ||||
| static bool lastBit; | ||||
|  | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| #include "globals.h" | ||||
| #include "fluxmap.h" | ||||
| #include "decoders/fluxmapreader.h" | ||||
| #include "lib/globals.h" | ||||
| #include "lib/fluxmap.h" | ||||
| #include "lib/decoders/fluxmapreader.h" | ||||
| #include "protocol.h" | ||||
| #include "decoders/decoders.h" | ||||
| #include "sector.h" | ||||
| #include "lib/decoders/decoders.h" | ||||
| #include "lib/sector.h" | ||||
| #include "zilogmcz.h" | ||||
| #include "bytes.h" | ||||
| #include "crc.h" | ||||
| #include "lib/bytes.h" | ||||
| #include "lib/crc.h" | ||||
| #include "fmt/format.h" | ||||
| #include <string.h> | ||||
| #include <algorithm> | ||||
|   | ||||
							
								
								
									
										194
									
								
								build.lua
									
									
									
									
									
								
							
							
						
						
									
										194
									
								
								build.lua
									
									
									
									
									
								
							| @@ -1,194 +0,0 @@ | ||||
| vars.cflags = { "$(CFLAGS)" } | ||||
| vars.cxxflags = { "$(CXXFLAGS)" } | ||||
| vars.ldflags = { "-pthread" } | ||||
|  | ||||
| include "build/protobuf.lua" | ||||
| include "build/dependency.lua" | ||||
| include "build/tests.lua" | ||||
|  | ||||
| dependency { | ||||
| 	name = "fmt_dep", | ||||
| 	pkg_config = "fmt", | ||||
| } | ||||
|  | ||||
| dependency { | ||||
| 	name = "stb_dep", | ||||
| 	pkg_config = "stb", | ||||
| 	fallback = "dep/stb+stb" | ||||
| } | ||||
|  | ||||
| dependency { | ||||
| 	name = "protobuf_dep", | ||||
| 	pkg_config = "protobuf" | ||||
| } | ||||
|  | ||||
| dependency { | ||||
| 	name = "zlib_dep", | ||||
| 	pkg_config = "zlib" | ||||
| } | ||||
|  | ||||
| proto_cc_library { | ||||
| 	name = "config_lib", | ||||
| 	srcs = { | ||||
| 		"./lib/common.proto", | ||||
| 		"./lib/config.proto", | ||||
| 		"./lib/decoders/decoders.proto", | ||||
| 		"./lib/drive.proto", | ||||
| 		"./lib/encoders/encoders.proto", | ||||
| 		"./lib/fl2.proto", | ||||
| 		"./lib/fluxsink/fluxsink.proto", | ||||
| 		"./lib/fluxsource/fluxsource.proto", | ||||
| 		"./lib/imagereader/imagereader.proto", | ||||
| 		"./lib/imagewriter/imagewriter.proto", | ||||
| 		"./lib/mapper.proto", | ||||
| 		"./lib/usb/usb.proto", | ||||
| 		"./arch/aeslanier/aeslanier.proto", | ||||
| 		"./arch/agat/agat.proto", | ||||
| 		"./arch/amiga/amiga.proto", | ||||
| 		"./arch/apple2/apple2.proto", | ||||
| 		"./arch/brother/brother.proto", | ||||
| 		"./arch/c64/c64.proto", | ||||
| 		"./arch/f85/f85.proto", | ||||
| 		"./arch/fb100/fb100.proto", | ||||
| 		"./arch/ibm/ibm.proto", | ||||
| 		"./arch/macintosh/macintosh.proto", | ||||
| 		"./arch/micropolis/micropolis.proto", | ||||
| 		"./arch/mx/mx.proto", | ||||
| 		"./arch/northstar/northstar.proto", | ||||
| 		"./arch/rolandd20/rolandd20.proto", | ||||
| 		"./arch/tids990/tids990.proto", | ||||
| 		"./arch/victor9k/victor9k.proto", | ||||
| 		"./arch/zilogmcz/zilogmcz.proto", | ||||
| 	} | ||||
| } | ||||
|  | ||||
| clibrary { | ||||
| 	name = "protocol_lib", | ||||
| 	hdrs = { "./protocol.h" } | ||||
| } | ||||
|  | ||||
| clibrary { | ||||
| 	name = "libfluxengine", | ||||
| 	srcs = { | ||||
| 		"./arch/aeslanier/decoder.cc", | ||||
| 		"./arch/agat/agat.cc", | ||||
| 		"./arch/agat/decoder.cc", | ||||
| 		"./arch/amiga/amiga.cc", | ||||
| 		"./arch/amiga/decoder.cc", | ||||
| 		"./arch/amiga/encoder.cc", | ||||
| 		"./arch/apple2/decoder.cc", | ||||
| 		"./arch/apple2/encoder.cc", | ||||
| 		"./arch/brother/decoder.cc", | ||||
| 		"./arch/brother/encoder.cc", | ||||
| 		"./arch/c64/c64.cc", | ||||
| 		"./arch/c64/decoder.cc", | ||||
| 		"./arch/c64/encoder.cc", | ||||
| 		"./arch/f85/decoder.cc", | ||||
| 		"./arch/fb100/decoder.cc", | ||||
| 		"./arch/ibm/decoder.cc", | ||||
| 		"./arch/ibm/encoder.cc", | ||||
| 		"./arch/macintosh/decoder.cc", | ||||
| 		"./arch/macintosh/encoder.cc", | ||||
| 		"./arch/micropolis/decoder.cc", | ||||
| 		"./arch/micropolis/encoder.cc", | ||||
| 		"./arch/mx/decoder.cc", | ||||
| 		"./arch/northstar/decoder.cc", | ||||
| 		"./arch/northstar/encoder.cc", | ||||
| 		"./arch/rolandd20/rolandd20.cc", | ||||
| 		"./arch/tids990/decoder.cc", | ||||
| 		"./arch/tids990/encoder.cc", | ||||
| 		"./arch/victor9k/decoder.cc", | ||||
| 		"./arch/victor9k/encoder.cc", | ||||
| 		"./arch/zilogmcz/decoder.cc", | ||||
| 		"./lib/bitmap.cc", | ||||
| 		"./lib/bytes.cc", | ||||
| 		"./lib/crc.cc", | ||||
| 		"./lib/csvreader.cc", | ||||
| 		"./lib/decoders/decoders.cc", | ||||
| 		"./lib/decoders/fluxdecoder.cc", | ||||
| 		"./lib/decoders/fluxmapreader.cc", | ||||
| 		"./lib/decoders/fmmfm.cc", | ||||
| 		"./lib/encoders/encoders.cc", | ||||
| 		"./lib/flags.cc", | ||||
| 		"./lib/fluxmap.cc", | ||||
| 		"./lib/fluxsink/aufluxsink.cc", | ||||
| 		"./lib/fluxsink/fl2fluxsink.cc", | ||||
| 		"./lib/fluxsink/fluxsink.cc", | ||||
| 		"./lib/fluxsink/hardwarefluxsink.cc", | ||||
| 		"./lib/fluxsink/scpfluxsink.cc", | ||||
| 		"./lib/fluxsink/vcdfluxsink.cc", | ||||
| 		"./lib/fluxsource/cwffluxsource.cc", | ||||
| 		"./lib/fluxsource/erasefluxsource.cc", | ||||
| 		"./lib/fluxsource/fl2fluxsource.cc", | ||||
| 		"./lib/fluxsource/fluxsource.cc", | ||||
| 		"./lib/fluxsource/hardwarefluxsource.cc", | ||||
| 		"./lib/fluxsource/kryoflux.cc", | ||||
| 		"./lib/fluxsource/kryofluxfluxsource.cc", | ||||
| 		"./lib/fluxsource/scpfluxsource.cc", | ||||
| 		"./lib/fluxsource/testpatternfluxsource.cc", | ||||
| 		"./lib/globals.cc", | ||||
| 		"./lib/hexdump.cc", | ||||
| 		"./lib/image.cc", | ||||
| 		"./lib/imagereader/d64imagereader.cc", | ||||
| 		"./lib/imagereader/d88imagereader.cc", | ||||
| 		"./lib/imagereader/dimimagereader.cc", | ||||
| 		"./lib/imagereader/diskcopyimagereader.cc", | ||||
| 		"./lib/imagereader/fdiimagereader.cc", | ||||
| 		"./lib/imagereader/imagereader.cc", | ||||
| 		"./lib/imagereader/imdimagereader.cc", | ||||
| 		"./lib/imagereader/imgimagereader.cc", | ||||
| 		"./lib/imagereader/jv3imagereader.cc", | ||||
| 		"./lib/imagereader/nfdimagereader.cc", | ||||
| 		"./lib/imagereader/nsiimagereader.cc", | ||||
| 		"./lib/imagereader/td0imagereader.cc", | ||||
| 		"./lib/imagewriter/d64imagewriter.cc", | ||||
| 		"./lib/imagewriter/d88imagewriter.cc", | ||||
| 		"./lib/imagewriter/diskcopyimagewriter.cc", | ||||
| 		"./lib/imagewriter/imagewriter.cc", | ||||
| 		"./lib/imagewriter/imgimagewriter.cc", | ||||
| 		"./lib/imagewriter/ldbsimagewriter.cc", | ||||
| 		"./lib/imagewriter/nsiimagewriter.cc", | ||||
| 		"./lib/imagewriter/rawimagewriter.cc", | ||||
| 		"./lib/imginputoutpututils.cc", | ||||
| 		"./lib/ldbs.cc", | ||||
| 		"./lib/logger.cc", | ||||
| 		"./lib/mapper.cc", | ||||
| 		"./lib/proto.cc", | ||||
| 		"./lib/readerwriter.cc", | ||||
| 		"./lib/sector.cc", | ||||
| 		"./lib/usb/fluxengineusb.cc", | ||||
| 		"./lib/usb/greaseweazle.cc", | ||||
| 		"./lib/usb/greaseweazleusb.cc", | ||||
| 		"./lib/usb/serial.cc", | ||||
| 		"./lib/usb/usb.cc", | ||||
| 		"./lib/usb/usbfinder.cc", | ||||
| 		"./lib/utils.cc", | ||||
| 		"protocol.h", | ||||
| 	}, | ||||
| 	deps = { | ||||
| 		"+config_lib", | ||||
| 		"+protocol_lib", | ||||
| 		"+fmt_dep", | ||||
| 		"+protobuf_dep", | ||||
| 		"+zlib_dep", | ||||
| 		"dep/libusbp+libusbp", | ||||
| 	}, | ||||
| 	dep_cflags = { "-Ilib", "-Iarch", "-I." }, | ||||
| 	vars = { | ||||
| 		["+cflags"] = { "-Ilib", "-Iarch", "-I." } | ||||
| 	} | ||||
| } | ||||
|  | ||||
| installable { | ||||
| 	name = "all", | ||||
| 	map = { | ||||
| 		["fluxengine"] = "src+fluxengine", | ||||
| 		["fluxengine-gui"] = "src/gui+fluxengine", | ||||
| 		["brother120tool"] = "tools+brother120tool", | ||||
| 		["brother240tool"] = "tools+brother240tool", | ||||
| 		["upgrade-flux-file"] = "tools+upgrade-flux-file", | ||||
| 	} | ||||
| } | ||||
|  | ||||
| include "tests/build.lua" | ||||
|  | ||||
							
								
								
									
										325
									
								
								build.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										325
									
								
								build.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,325 @@ | ||||
| from build.ab import export | ||||
| from build.c import clibrary, cxxlibrary | ||||
| from build.protobuf import proto, protocc | ||||
| from build.pkg import package, hostpackage | ||||
| from build.utils import test | ||||
| from glob import glob | ||||
| import config | ||||
| import re | ||||
|  | ||||
| package(name="protobuf_lib", package="protobuf") | ||||
| package(name="z_lib", package="zlib") | ||||
| package(name="fmt_lib", package="fmt", fallback="dep/fmt") | ||||
| package(name="sqlite3_lib", package="sqlite3") | ||||
|  | ||||
| hostpackage(name="protobuf_host_lib", package="protobuf") | ||||
| hostpackage(name="z_host_lib", package="zlib") | ||||
| hostpackage(name="fmt_host_lib", package="fmt") | ||||
| hostpackage(name="sqlite3_host_lib", package="sqlite3") | ||||
|  | ||||
| clibrary(name="protocol", hdrs={"protocol.h": "./protocol.h"}) | ||||
|  | ||||
| proto(name="fl2_proto", srcs=["lib/fl2.proto"]) | ||||
| protocc(name="fl2_proto_lib", srcs=["+fl2_proto"]) | ||||
|  | ||||
| cxxlibrary( | ||||
|     name="lib", | ||||
|     srcs=[ | ||||
|         "./lib/bitmap.cc", | ||||
|         "./lib/bytes.cc", | ||||
|         "./lib/config.cc", | ||||
|         "./lib/crc.cc", | ||||
|         "./lib/csvreader.cc", | ||||
|         "./lib/decoders/decoders.cc", | ||||
|         "./lib/decoders/fluxdecoder.cc", | ||||
|         "./lib/decoders/fluxmapreader.cc", | ||||
|         "./lib/decoders/fmmfm.cc", | ||||
|         "./lib/encoders/encoders.cc", | ||||
|         "./lib/fl2.cc", | ||||
|         "./lib/flags.cc", | ||||
|         "./lib/fluxmap.cc", | ||||
|         "./lib/fluxsink/a2rfluxsink.cc", | ||||
|         "./lib/fluxsink/aufluxsink.cc", | ||||
|         "./lib/fluxsink/fl2fluxsink.cc", | ||||
|         "./lib/fluxsink/fluxsink.cc", | ||||
|         "./lib/fluxsink/hardwarefluxsink.cc", | ||||
|         "./lib/fluxsink/scpfluxsink.cc", | ||||
|         "./lib/fluxsink/vcdfluxsink.cc", | ||||
|         "./lib/fluxsource/a2rfluxsource.cc", | ||||
|         "./lib/fluxsource/catweasel.cc", | ||||
|         "./lib/fluxsource/cwffluxsource.cc", | ||||
|         "./lib/fluxsource/dmkfluxsource.cc", | ||||
|         "./lib/fluxsource/erasefluxsource.cc", | ||||
|         "./lib/fluxsource/fl2fluxsource.cc", | ||||
|         "./lib/fluxsource/fluxsource.cc", | ||||
|         "./lib/fluxsource/flx.cc", | ||||
|         "./lib/fluxsource/flxfluxsource.cc", | ||||
|         "./lib/fluxsource/hardwarefluxsource.cc", | ||||
|         "./lib/fluxsource/kryoflux.cc", | ||||
|         "./lib/fluxsource/kryofluxfluxsource.cc", | ||||
|         "./lib/fluxsource/memoryfluxsource.cc", | ||||
|         "./lib/fluxsource/scpfluxsource.cc", | ||||
|         "./lib/fluxsource/testpatternfluxsource.cc", | ||||
|         "./lib/globals.cc", | ||||
|         "./lib/hexdump.cc", | ||||
|         "./lib/image.cc", | ||||
|         "./lib/imagereader/d64imagereader.cc", | ||||
|         "./lib/imagereader/d88imagereader.cc", | ||||
|         "./lib/imagereader/dimimagereader.cc", | ||||
|         "./lib/imagereader/diskcopyimagereader.cc", | ||||
|         "./lib/imagereader/fdiimagereader.cc", | ||||
|         "./lib/imagereader/imagereader.cc", | ||||
|         "./lib/imagereader/imdimagereader.cc", | ||||
|         "./lib/imagereader/imgimagereader.cc", | ||||
|         "./lib/imagereader/jv3imagereader.cc", | ||||
|         "./lib/imagereader/nfdimagereader.cc", | ||||
|         "./lib/imagereader/nsiimagereader.cc", | ||||
|         "./lib/imagereader/td0imagereader.cc", | ||||
|         "./lib/imagewriter/d64imagewriter.cc", | ||||
|         "./lib/imagewriter/d88imagewriter.cc", | ||||
|         "./lib/imagewriter/diskcopyimagewriter.cc", | ||||
|         "./lib/imagewriter/imagewriter.cc", | ||||
|         "./lib/imagewriter/imdimagewriter.cc", | ||||
|         "./lib/imagewriter/imgimagewriter.cc", | ||||
|         "./lib/imagewriter/ldbsimagewriter.cc", | ||||
|         "./lib/imagewriter/nsiimagewriter.cc", | ||||
|         "./lib/imagewriter/rawimagewriter.cc", | ||||
|         "./lib/layout.cc", | ||||
|         "./lib/ldbs.cc", | ||||
|         "./lib/logger.cc", | ||||
|         "./lib/proto.cc", | ||||
|         "./lib/readerwriter.cc", | ||||
|         "./lib/sector.cc", | ||||
|         "./lib/usb/fluxengineusb.cc", | ||||
|         "./lib/usb/greaseweazle.cc", | ||||
|         "./lib/usb/greaseweazleusb.cc", | ||||
|         "./lib/usb/serial.cc", | ||||
|         "./lib/usb/usb.cc", | ||||
|         "./lib/usb/usbfinder.cc", | ||||
|         "./lib/utils.cc", | ||||
|         "./lib/vfs/acorndfs.cc", | ||||
|         "./lib/vfs/amigaffs.cc", | ||||
|         "./lib/vfs/appledos.cc", | ||||
|         "./lib/vfs/applesingle.cc", | ||||
|         "./lib/vfs/brother120fs.cc", | ||||
|         "./lib/vfs/cbmfs.cc", | ||||
|         "./lib/vfs/cpmfs.cc", | ||||
|         "./lib/vfs/fatfs.cc", | ||||
|         "./lib/vfs/fluxsectorinterface.cc", | ||||
|         "./lib/vfs/imagesectorinterface.cc", | ||||
|         "./lib/vfs/lif.cc", | ||||
|         "./lib/vfs/machfs.cc", | ||||
|         "./lib/vfs/microdos.cc", | ||||
|         "./lib/vfs/philefs.cc", | ||||
|         "./lib/vfs/prodos.cc", | ||||
|         "./lib/vfs/roland.cc", | ||||
|         "./lib/vfs/smaky6fs.cc", | ||||
|         "./lib/vfs/vfs.cc", | ||||
|         "./lib/vfs/zdos.cc", | ||||
|         "./arch/aeslanier/decoder.cc", | ||||
|         "./arch/agat/agat.cc", | ||||
|         "./arch/agat/decoder.cc", | ||||
|         "./arch/agat/encoder.cc", | ||||
|         "./arch/amiga/amiga.cc", | ||||
|         "./arch/amiga/decoder.cc", | ||||
|         "./arch/amiga/encoder.cc", | ||||
|         "./arch/apple2/decoder.cc", | ||||
|         "./arch/apple2/encoder.cc", | ||||
|         "./arch/brother/decoder.cc", | ||||
|         "./arch/brother/encoder.cc", | ||||
|         "./arch/c64/c64.cc", | ||||
|         "./arch/c64/decoder.cc", | ||||
|         "./arch/c64/encoder.cc", | ||||
|         "./arch/f85/decoder.cc", | ||||
|         "./arch/fb100/decoder.cc", | ||||
|         "./arch/ibm/decoder.cc", | ||||
|         "./arch/ibm/encoder.cc", | ||||
|         "./arch/macintosh/decoder.cc", | ||||
|         "./arch/macintosh/encoder.cc", | ||||
|         "./arch/micropolis/decoder.cc", | ||||
|         "./arch/micropolis/encoder.cc", | ||||
|         "./arch/mx/decoder.cc", | ||||
|         "./arch/northstar/decoder.cc", | ||||
|         "./arch/northstar/encoder.cc", | ||||
|         "./arch/rolandd20/decoder.cc", | ||||
|         "./arch/smaky6/decoder.cc", | ||||
|         "./arch/tartu/decoder.cc", | ||||
|         "./arch/tartu/encoder.cc", | ||||
|         "./arch/tids990/decoder.cc", | ||||
|         "./arch/tids990/encoder.cc", | ||||
|         "./arch/victor9k/decoder.cc", | ||||
|         "./arch/victor9k/encoder.cc", | ||||
|         "./arch/zilogmcz/decoder.cc", | ||||
|     ], | ||||
|     hdrs={ | ||||
|         "arch/ibm/ibm.h": "./arch/ibm/ibm.h", | ||||
|         "arch/apple2/data_gcr.h": "./arch/apple2/data_gcr.h", | ||||
|         "arch/apple2/apple2.h": "./arch/apple2/apple2.h", | ||||
|         "arch/smaky6/smaky6.h": "./arch/smaky6/smaky6.h", | ||||
|         "arch/tids990/tids990.h": "./arch/tids990/tids990.h", | ||||
|         "arch/zilogmcz/zilogmcz.h": "./arch/zilogmcz/zilogmcz.h", | ||||
|         "arch/amiga/amiga.h": "./arch/amiga/amiga.h", | ||||
|         "arch/f85/data_gcr.h": "./arch/f85/data_gcr.h", | ||||
|         "arch/f85/f85.h": "./arch/f85/f85.h", | ||||
|         "arch/mx/mx.h": "./arch/mx/mx.h", | ||||
|         "arch/aeslanier/aeslanier.h": "./arch/aeslanier/aeslanier.h", | ||||
|         "arch/northstar/northstar.h": "./arch/northstar/northstar.h", | ||||
|         "arch/brother/data_gcr.h": "./arch/brother/data_gcr.h", | ||||
|         "arch/brother/brother.h": "./arch/brother/brother.h", | ||||
|         "arch/brother/header_gcr.h": "./arch/brother/header_gcr.h", | ||||
|         "arch/macintosh/data_gcr.h": "./arch/macintosh/data_gcr.h", | ||||
|         "arch/macintosh/macintosh.h": "./arch/macintosh/macintosh.h", | ||||
|         "arch/agat/agat.h": "./arch/agat/agat.h", | ||||
|         "arch/fb100/fb100.h": "./arch/fb100/fb100.h", | ||||
|         "arch/victor9k/data_gcr.h": "./arch/victor9k/data_gcr.h", | ||||
|         "arch/victor9k/victor9k.h": "./arch/victor9k/victor9k.h", | ||||
|         "arch/rolandd20/rolandd20.h": "./arch/rolandd20/rolandd20.h", | ||||
|         "arch/micropolis/micropolis.h": "./arch/micropolis/micropolis.h", | ||||
|         "arch/c64/data_gcr.h": "./arch/c64/data_gcr.h", | ||||
|         "arch/c64/c64.h": "./arch/c64/c64.h", | ||||
|         "arch/tartu/tartu.h": "./arch/tartu/tartu.h", | ||||
|         "lib/a2r.h": "./lib/a2r.h", | ||||
|         "lib/bitmap.h": "./lib/bitmap.h", | ||||
|         "lib/bytes.h": "./lib/bytes.h", | ||||
|         "lib/config.h": "./lib/config.h", | ||||
|         "lib/crc.h": "./lib/crc.h", | ||||
|         "lib/csvreader.h": "./lib/csvreader.h", | ||||
|         "lib/decoders/decoders.h": "./lib/decoders/decoders.h", | ||||
|         "lib/decoders/fluxdecoder.h": "./lib/decoders/fluxdecoder.h", | ||||
|         "lib/decoders/fluxmapreader.h": "./lib/decoders/fluxmapreader.h", | ||||
|         "lib/decoders/rawbits.h": "./lib/decoders/rawbits.h", | ||||
|         "lib/encoders/encoders.h": "./lib/encoders/encoders.h", | ||||
|         "lib/scp.h": "./lib/scp.h", | ||||
|         "lib/fl2.h": "./lib/fl2.h", | ||||
|         "lib/flags.h": "./lib/flags.h", | ||||
|         "lib/flux.h": "./lib/flux.h", | ||||
|         "lib/fluxmap.h": "./lib/fluxmap.h", | ||||
|         "lib/fluxsink/fluxsink.h": "./lib/fluxsink/fluxsink.h", | ||||
|         "lib/fluxsource/catweasel.h": "lib/fluxsource/catweasel.h", | ||||
|         "lib/fluxsource/fluxsource.h": "lib/fluxsource/fluxsource.h", | ||||
|         "lib/fluxsource/flx.h": "lib/fluxsource/flx.h", | ||||
|         "lib/fluxsource/kryoflux.h": "lib/fluxsource/kryoflux.h", | ||||
|         "lib/globals.h": "./lib/globals.h", | ||||
|         "lib/image.h": "./lib/image.h", | ||||
|         "lib/imagereader/imagereader.h": "./lib/imagereader/imagereader.h", | ||||
|         "lib/imagewriter/imagewriter.h": "./lib/imagewriter/imagewriter.h", | ||||
|         "lib/layout.h": "./lib/layout.h", | ||||
|         "lib/ldbs.h": "./lib/ldbs.h", | ||||
|         "lib/logger.h": "./lib/logger.h", | ||||
|         "lib/proto.h": "./lib/proto.h", | ||||
|         "lib/readerwriter.h": "./lib/readerwriter.h", | ||||
|         "lib/sector.h": "./lib/sector.h", | ||||
|         "lib/usb/greaseweazle.h": "./lib/usb/greaseweazle.h", | ||||
|         "lib/usb/usb.h": "./lib/usb/usb.h", | ||||
|         "lib/usb/usbfinder.h": "./lib/usb/usbfinder.h", | ||||
|         "lib/utils.h": "./lib/utils.h", | ||||
|         "lib/vfs/applesingle.h": "./lib/vfs/applesingle.h", | ||||
|         "lib/vfs/sectorinterface.h": "./lib/vfs/sectorinterface.h", | ||||
|         "lib/vfs/vfs.h": "./lib/vfs/vfs.h", | ||||
|     }, | ||||
|     deps=[ | ||||
|         "+fl2_proto_lib", | ||||
|         "+fmt_lib", | ||||
|         "+protocol", | ||||
|         "dep/adflib", | ||||
|         "dep/agg", | ||||
|         "dep/fatfs", | ||||
|         "dep/hfsutils", | ||||
|         "dep/libusbp", | ||||
|         "dep/stb", | ||||
|         "lib+config_proto_lib", | ||||
|     ], | ||||
| ) | ||||
|  | ||||
| corpustests = [] | ||||
| if not glob("../fluxengine-testdata/data"): | ||||
|     print("fluxengine-testdata not found; skipping corpus tests") | ||||
| else: | ||||
|     corpus = [ | ||||
|         ("acorndfs", "", "--200"), | ||||
|         ("agat", "", ""), | ||||
|         ("amiga", "", ""), | ||||
|         ("apple2", "", "--140 40track_drive"), | ||||
|         ("atarist", "", "--360"), | ||||
|         ("atarist", "", "--370"), | ||||
|         ("atarist", "", "--400"), | ||||
|         ("atarist", "", "--410"), | ||||
|         ("atarist", "", "--720"), | ||||
|         ("atarist", "", "--740"), | ||||
|         ("atarist", "", "--800"), | ||||
|         ("atarist", "", "--820"), | ||||
|         ("bk", "", ""), | ||||
|         ("brother", "", "--120 40track_drive"), | ||||
|         ("brother", "", "--240"), | ||||
|         ( | ||||
|             "commodore", | ||||
|             "scripts/commodore1541_test.textpb", | ||||
|             "--171 40track_drive", | ||||
|         ), | ||||
|         ( | ||||
|             "commodore", | ||||
|             "scripts/commodore1541_test.textpb", | ||||
|             "--192 40track_drive", | ||||
|         ), | ||||
|         ("commodore", "", "--800"), | ||||
|         ("commodore", "", "--1620"), | ||||
|         ("hplif", "", "--264"), | ||||
|         ("hplif", "", "--608"), | ||||
|         ("hplif", "", "--616"), | ||||
|         ("hplif", "", "--770"), | ||||
|         ("ibm", "", "--1200"), | ||||
|         ("ibm", "", "--1232"), | ||||
|         ("ibm", "", "--1440"), | ||||
|         ("ibm", "", "--1680"), | ||||
|         ("ibm", "", "--180 40track_drive"), | ||||
|         ("ibm", "", "--160 40track_drive"), | ||||
|         ("ibm", "", "--320 40track_drive"), | ||||
|         ("ibm", "", "--360 40track_drive"), | ||||
|         ("ibm", "", "--720_96"), | ||||
|         ("ibm", "", "--720_135"), | ||||
|         ("mac", "scripts/mac400_test.textpb", "--400"), | ||||
|         ("mac", "scripts/mac800_test.textpb", "--800"), | ||||
|         ("n88basic", "", ""), | ||||
|         ("rx50", "", ""), | ||||
|         ("tartu", "", "--390 40track_drive"), | ||||
|         ("tartu", "", "--780"), | ||||
|         ("tids990", "", ""), | ||||
|         ("victor9k", "", "--612"), | ||||
|         ("victor9k", "", "--1224"), | ||||
|     ] | ||||
|  | ||||
|     for c in corpus: | ||||
|         name = re.sub(r"[^a-zA-Z0-9]", "_", "".join(c), 0) | ||||
|         corpustests += [ | ||||
|             test( | ||||
|                 name=f"corpustest_{name}_{format}", | ||||
|                 ins=["src+fluxengine"], | ||||
|                 deps=["scripts/encodedecodetest.sh"], | ||||
|                 commands=[ | ||||
|                     "{deps[0]} " | ||||
|                     + c[0] | ||||
|                     + " " | ||||
|                     + format | ||||
|                     + " {ins[0]} '" | ||||
|                     + c[1] | ||||
|                     + "' '" | ||||
|                     + c[2] | ||||
|                     + "' $(dir {outs[0]}) > /dev/null" | ||||
|                 ], | ||||
|                 label="CORPUSTEST", | ||||
|             ) | ||||
|             for format in ["scp", "flux"] | ||||
|         ] | ||||
|  | ||||
| export( | ||||
|     name="all", | ||||
|     items={ | ||||
|         "fluxengine$(EXT)": "src+fluxengine", | ||||
|         "fluxengine-gui$(EXT)": "src/gui", | ||||
|         "brother120tool$(EXT)": "tools+brother120tool", | ||||
|         "brother240tool$(EXT)": "tools+brother240tool", | ||||
|         "upgrade-flux-file$(EXT)": "tools+upgrade-flux-file", | ||||
|     } | ||||
|     | ({"FluxEngine.pkg": "src/gui+fluxengine_pkg"} if config.osx else {}), | ||||
|     deps=["tests", "src/formats+docs", "scripts+mkdocindex"] + corpustests, | ||||
| ) | ||||
							
								
								
									
										19
									
								
								build/_objectify.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								build/_objectify.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| import sys | ||||
| from functools import partial | ||||
|  | ||||
| if len(sys.argv) != 3: | ||||
|     sys.exit("Usage: %s <file> <symbol>" % sys.argv[0]) | ||||
| filename = sys.argv[1] | ||||
| symbol = sys.argv[2] | ||||
|  | ||||
| print("const uint8_t " + symbol + "[] = {") | ||||
| n = 0 | ||||
| with open(filename, "rb") as in_file: | ||||
|     for c in iter(partial(in_file.read, 1), b""): | ||||
|         print("0x%02X," % ord(c), end="") | ||||
|         n += 1 | ||||
|         if n % 16 == 0: | ||||
|             print() | ||||
| print("};") | ||||
|  | ||||
| print("const size_t " + symbol + "_len = sizeof(" + symbol + ");") | ||||
							
								
								
									
										55
									
								
								build/ab.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								build/ab.mk
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| ifeq ($(findstring 4.,$(MAKE_VERSION)),) | ||||
| $(error You need GNU Make 4.x for this (if you're on OSX, use gmake).) | ||||
| endif | ||||
|  | ||||
| OBJ ?= .obj | ||||
| PYTHON ?= python3 | ||||
| CC ?= gcc | ||||
| CXX ?= g++ | ||||
| AR ?= ar | ||||
| CFLAGS ?= -g -Og | ||||
| LDFLAGS ?= -g | ||||
| PKG_CONFIG ?= pkg-config | ||||
| ECHO ?= echo | ||||
| TARGETS ?= +all | ||||
|  | ||||
| ifdef VERBOSE | ||||
| 	hide = | ||||
| else | ||||
| 	ifdef V | ||||
| 		hide = | ||||
| 	else | ||||
| 		hide = @ | ||||
| 	endif | ||||
| endif | ||||
|  | ||||
| ifeq ($(OS), Windows_NT) | ||||
| 	EXT ?= .exe | ||||
| endif | ||||
| EXT ?= | ||||
|  | ||||
| include $(OBJ)/build.mk | ||||
|  | ||||
| MAKEFLAGS += -r | ||||
| .DELETE_ON_ERROR: | ||||
|  | ||||
| .PHONY: update-ab | ||||
| update-ab: | ||||
| 	@echo "Press RETURN to update ab from the repository, or CTRL+C to cancel." \ | ||||
| 		&& read a \ | ||||
| 		&& (curl -L https://github.com/davidgiven/ab/releases/download/dev/distribution.tar.xz | tar xvJf -) \ | ||||
| 		&& echo "Done." | ||||
|  | ||||
| .PHONY: clean | ||||
| clean:: | ||||
| 	@echo CLEAN | ||||
| 	$(hide) rm -rf $(OBJ) | ||||
|  | ||||
| export PYTHONHASHSEED = 1 | ||||
| build-files = $(shell find . -name 'build.py') $(wildcard build/*.py) $(wildcard config.py) | ||||
| $(OBJ)/build.mk: Makefile $(build-files) | ||||
| 	@echo "AB" | ||||
| 	@mkdir -p $(OBJ) | ||||
| 	$(hide) $(PYTHON) -X pycache_prefix=$(OBJ) build/ab.py $(patsubst %,-t %,$(TARGETS)) -o $@ \ | ||||
| 		build.py || rm -f $@ | ||||
|  | ||||
							
								
								
									
										562
									
								
								build/ab.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										562
									
								
								build/ab.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,562 @@ | ||||
| from collections.abc import Iterable, Sequence | ||||
| from os.path import * | ||||
| from types import SimpleNamespace | ||||
| import argparse | ||||
| import functools | ||||
| import importlib | ||||
| import importlib.abc | ||||
| import importlib.util | ||||
| import inspect | ||||
| import re | ||||
| import sys | ||||
| import builtins | ||||
| import string | ||||
| import fnmatch | ||||
| import traceback | ||||
|  | ||||
| defaultGlobals = {} | ||||
| targets = {} | ||||
| unmaterialisedTargets = set() | ||||
| materialisingStack = [] | ||||
| outputFp = None | ||||
| cwdStack = [""] | ||||
|  | ||||
| sys.path += ["."] | ||||
| old_import = builtins.__import__ | ||||
|  | ||||
|  | ||||
| def new_import(name, *args, **kwargs): | ||||
|     if name not in sys.modules: | ||||
|         path = name.replace(".", "/") + ".py" | ||||
|         if isfile(path): | ||||
|             sys.stderr.write(f"loading {path}\n") | ||||
|             loader = importlib.machinery.SourceFileLoader(name, path) | ||||
|  | ||||
|             spec = importlib.util.spec_from_loader( | ||||
|                 name, loader, origin="built-in" | ||||
|             ) | ||||
|             module = importlib.util.module_from_spec(spec) | ||||
|             sys.modules[name] = module | ||||
|             cwdStack.append(dirname(path)) | ||||
|             spec.loader.exec_module(module) | ||||
|             cwdStack.pop() | ||||
|  | ||||
|     return old_import(name, *args, **kwargs) | ||||
|  | ||||
|  | ||||
| builtins.__import__ = new_import | ||||
|  | ||||
|  | ||||
| class ABException(BaseException): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class Invocation: | ||||
|     name = None | ||||
|     callback = None | ||||
|     types = None | ||||
|     ins = None | ||||
|     outs = None | ||||
|     binding = None | ||||
|     traits = None | ||||
|     attr = None | ||||
|     attrdeps = None | ||||
|  | ||||
|     def __init__(self): | ||||
|         self.attr = SimpleNamespace() | ||||
|         self.attrdeps = SimpleNamespace() | ||||
|         self.traits = set() | ||||
|  | ||||
|     def __eq__(self, other): | ||||
|         return self.name is other.name | ||||
|  | ||||
|     def __hash__(self): | ||||
|         return id(self.name) | ||||
|  | ||||
|     def materialise(self, replacing=False): | ||||
|         if self in unmaterialisedTargets: | ||||
|             if not replacing and (self in materialisingStack): | ||||
|                 print("Found dependency cycle:") | ||||
|                 for i in materialisingStack: | ||||
|                     print(f"  {i.name}") | ||||
|                 print(f"  {self.name}") | ||||
|                 sys.exit(1) | ||||
|  | ||||
|             materialisingStack.append(self) | ||||
|  | ||||
|             # Perform type conversion to the declared rule parameter types. | ||||
|  | ||||
|             try: | ||||
|                 self.args = {} | ||||
|                 for k, v in self.binding.arguments.items(): | ||||
|                     if k != "kwargs": | ||||
|                         t = self.types.get(k, None) | ||||
|                         if t: | ||||
|                             v = t(v).convert(self) | ||||
|                         self.args[k] = v | ||||
|                     else: | ||||
|                         for kk, vv in v.items(): | ||||
|                             t = self.types.get(kk, None) | ||||
|                             if t: | ||||
|                                 vv = t(vv).convert(self) | ||||
|                             self.args[kk] = vv | ||||
|  | ||||
|                 # Actually call the callback. | ||||
|  | ||||
|                 cwdStack.append(self.cwd) | ||||
|                 self.callback(**self.args) | ||||
|                 cwdStack.pop() | ||||
|             except BaseException as e: | ||||
|                 print(f"Error materialising {self}: {self.callback}") | ||||
|                 print(f"Arguments: {self.args}") | ||||
|                 raise e | ||||
|  | ||||
|             if self.outs is None: | ||||
|                 raise ABException(f"{self.name} didn't set self.outs") | ||||
|  | ||||
|             if self in unmaterialisedTargets: | ||||
|                 unmaterialisedTargets.remove(self) | ||||
|  | ||||
|             materialisingStack.pop() | ||||
|  | ||||
|     def bubbleattr(self, attr, xs): | ||||
|         xs = targetsof(xs, cwd=self.cwd) | ||||
|         a = set() | ||||
|         if hasattr(self.attrdeps, attr): | ||||
|             a = getattr(self.attrdeps, attr) | ||||
|  | ||||
|         for x in xs: | ||||
|             a.add(x) | ||||
|         setattr(self.attrdeps, attr, a) | ||||
|  | ||||
|     def __repr__(self): | ||||
|         return "'%s'" % self.name | ||||
|  | ||||
|  | ||||
| def Rule(func): | ||||
|     sig = inspect.signature(func) | ||||
|  | ||||
|     @functools.wraps(func) | ||||
|     def wrapper(*, name=None, replaces=None, **kwargs): | ||||
|         cwd = None | ||||
|         if name: | ||||
|             if ("+" in name) and not name.startswith("+"): | ||||
|                 (cwd, _) = name.split("+", 1) | ||||
|         if not cwd: | ||||
|             cwd = cwdStack[-1] | ||||
|  | ||||
|         if name: | ||||
|             i = Invocation() | ||||
|             if name.startswith("./"): | ||||
|                 name = join(cwd, name) | ||||
|             elif "+" not in name: | ||||
|                 name = join(cwd, "+" + name) | ||||
|  | ||||
|             i.name = name | ||||
|             i.localname = name.split("+")[-1] | ||||
|  | ||||
|             if name in targets: | ||||
|                 raise ABException(f"target {i.name} has already been defined") | ||||
|             targets[name] = i | ||||
|         elif replaces: | ||||
|             i = replaces | ||||
|             name = i.name | ||||
|         else: | ||||
|             raise ABException("you must supply either 'name' or 'replaces'") | ||||
|  | ||||
|         i.cwd = cwd | ||||
|         i.sentinel = "$(OBJ)/.sentinels/" + name + ".mark" | ||||
|         i.types = func.__annotations__ | ||||
|         i.callback = func | ||||
|         i.traits.add(func.__name__) | ||||
|  | ||||
|         i.binding = sig.bind(name=name, self=i, **kwargs) | ||||
|         i.binding.apply_defaults() | ||||
|  | ||||
|         unmaterialisedTargets.add(i) | ||||
|         if replaces: | ||||
|             i.materialise(replacing=True) | ||||
|         return i | ||||
|  | ||||
|     defaultGlobals[func.__name__] = wrapper | ||||
|     return wrapper | ||||
|  | ||||
|  | ||||
| class Type: | ||||
|     def __init__(self, value): | ||||
|         self.value = value | ||||
|  | ||||
|  | ||||
| class List(Type): | ||||
|     def convert(self, invocation): | ||||
|         value = self.value | ||||
|         if not value: | ||||
|             return [] | ||||
|         if type(value) is str: | ||||
|             return [value] | ||||
|         return list(value) | ||||
|  | ||||
|  | ||||
| class Targets(Type): | ||||
|     def convert(self, invocation): | ||||
|         value = self.value | ||||
|         if not value: | ||||
|             return [] | ||||
|         if type(value) is str: | ||||
|             value = [value] | ||||
|         if type(value) is list: | ||||
|             value = targetsof(value, cwd=invocation.cwd) | ||||
|         return value | ||||
|  | ||||
|  | ||||
| class Target(Type): | ||||
|     def convert(self, invocation): | ||||
|         value = self.value | ||||
|         if not value: | ||||
|             return None | ||||
|         return targetof(value, cwd=invocation.cwd) | ||||
|  | ||||
|  | ||||
| class TargetsMap(Type): | ||||
|     def convert(self, invocation): | ||||
|         value = self.value | ||||
|         if not value: | ||||
|             return {} | ||||
|         if type(value) is dict: | ||||
|             return { | ||||
|                 k: targetof(v, cwd=invocation.cwd) for k, v in value.items() | ||||
|             } | ||||
|         raise ABException(f"wanted a dict of targets, got a {type(value)}") | ||||
|  | ||||
|  | ||||
| def flatten(*xs): | ||||
|     def recurse(xs): | ||||
|         for x in xs: | ||||
|             if isinstance(x, Iterable) and not isinstance(x, (str, bytes)): | ||||
|                 yield from recurse(x) | ||||
|             else: | ||||
|                 yield x | ||||
|  | ||||
|     return list(recurse(xs)) | ||||
|  | ||||
|  | ||||
| def fileinvocation(s): | ||||
|     i = Invocation() | ||||
|     i.name = s | ||||
|     i.outs = [s] | ||||
|     targets[s] = i | ||||
|     return i | ||||
|  | ||||
|  | ||||
| def targetof(s, cwd=None): | ||||
|     if isinstance(s, Invocation): | ||||
|         s.materialise() | ||||
|         return s | ||||
|  | ||||
|     if type(s) != str: | ||||
|         raise ABException("parameter of targetof is not a single target") | ||||
|  | ||||
|     if s in targets: | ||||
|         t = targets[s] | ||||
|         t.materialise() | ||||
|         return t | ||||
|  | ||||
|     if s.startswith("."): | ||||
|         if cwd == None: | ||||
|             raise ABException( | ||||
|                 "relative target names can't be used in targetof without supplying cwd" | ||||
|             ) | ||||
|         if s.startswith(".+"): | ||||
|             s = cwd + s[1:] | ||||
|         elif s.startswith("./"): | ||||
|             s = normpath(join(cwd, s)) | ||||
|  | ||||
|     elif s.endswith("/"): | ||||
|         return fileinvocation(s) | ||||
|     elif s.startswith("$"): | ||||
|         return fileinvocation(s) | ||||
|  | ||||
|     if "+" not in s: | ||||
|         if isdir(s): | ||||
|             s = s + "+" + basename(s) | ||||
|         else: | ||||
|             return fileinvocation(s) | ||||
|  | ||||
|     (path, target) = s.split("+", 2) | ||||
|     s = join(path, "+" + target) | ||||
|     loadbuildfile(join(path, "build.py")) | ||||
|     if not s in targets: | ||||
|         raise ABException( | ||||
|             f"build file at {path} doesn't contain +{target} when trying to resolve {s}" | ||||
|         ) | ||||
|     i = targets[s] | ||||
|     i.materialise() | ||||
|     return i | ||||
|  | ||||
|  | ||||
| def targetsof(*xs, cwd=None): | ||||
|     return flatten([targetof(x, cwd) for x in flatten(xs)]) | ||||
|  | ||||
|  | ||||
| def filenamesof(*xs): | ||||
|     s = [] | ||||
|     for t in flatten(xs): | ||||
|         if type(t) == str: | ||||
|             t = normpath(t) | ||||
|             s += [t] | ||||
|         else: | ||||
|             s += [f for f in [normpath(f) for f in filenamesof(t.outs)]] | ||||
|     return s | ||||
|  | ||||
|  | ||||
| def filenamesmatchingof(xs, pattern): | ||||
|     return fnmatch.filter(filenamesof(xs), pattern) | ||||
|  | ||||
|  | ||||
| def targetswithtraitsof(xs, trait): | ||||
|     return [target for target in targetsof(xs) if trait in target.traits] | ||||
|  | ||||
|  | ||||
| def targetnamesof(*xs): | ||||
|     s = [] | ||||
|     for x in flatten(xs): | ||||
|         if type(x) == str: | ||||
|             x = normpath(x) | ||||
|             if x not in s: | ||||
|                 s += [x] | ||||
|         else: | ||||
|             if x.name not in s: | ||||
|                 s += [x.name] | ||||
|     return s | ||||
|  | ||||
|  | ||||
| def filenameof(x): | ||||
|     xs = filenamesof(x) | ||||
|     if len(xs) != 1: | ||||
|         raise ABException("expected a single item") | ||||
|     return xs[0] | ||||
|  | ||||
|  | ||||
| def bubbledattrsof(x, attr): | ||||
|     x = targetsof(x) | ||||
|     alltargets = set() | ||||
|     pending = set(x) if isinstance(x, Iterable) else {x} | ||||
|     while pending: | ||||
|         t = pending.pop() | ||||
|         if t not in alltargets: | ||||
|             alltargets.add(t) | ||||
|             if hasattr(t.attrdeps, attr): | ||||
|                 pending.update(getattr(t.attrdeps, attr)) | ||||
|  | ||||
|     values = [] | ||||
|     for t in alltargets: | ||||
|         if hasattr(t.attr, attr): | ||||
|             values += getattr(t.attr, attr) | ||||
|     return values | ||||
|  | ||||
|  | ||||
| def stripext(path): | ||||
|     return splitext(path)[0] | ||||
|  | ||||
|  | ||||
| def emit(*args): | ||||
|     outputFp.write(" ".join(flatten(args))) | ||||
|     outputFp.write("\n") | ||||
|  | ||||
|  | ||||
| def templateexpand(s, invocation): | ||||
|     class Formatter(string.Formatter): | ||||
|         def get_field(self, name, a1, a2): | ||||
|             return ( | ||||
|                 eval(name, invocation.callback.__globals__, invocation.args), | ||||
|                 False, | ||||
|             ) | ||||
|  | ||||
|         def format_field(self, value, format_spec): | ||||
|             if type(self) == str: | ||||
|                 return value | ||||
|             return " ".join( | ||||
|                 [templateexpand(f, invocation) for f in filenamesof(value)] | ||||
|             ) | ||||
|  | ||||
|     return Formatter().format(s) | ||||
|  | ||||
|  | ||||
| def emitter_rule(rule, ins, outs, deps=[]): | ||||
|     emit("") | ||||
|     emit(".PHONY:", rule.name) | ||||
|     emit(rule.name, ":", rule.sentinel) | ||||
|  | ||||
|     emit( | ||||
|         rule.sentinel, | ||||
|         # filenamesof(outs) if outs else [], | ||||
|         ":", | ||||
|         filenamesof(ins), | ||||
|         filenamesof(deps), | ||||
|     ) | ||||
|  | ||||
|  | ||||
| def emitter_endrule(rule, outs): | ||||
|     emit("\t$(hide) mkdir -p", dirname(rule.sentinel)) | ||||
|     emit("\t$(hide) touch", rule.sentinel) | ||||
|  | ||||
|     for f in filenamesof(outs): | ||||
|         emit(".SECONDARY:", f) | ||||
|         emit(f, ":", rule.sentinel, ";") | ||||
|  | ||||
|  | ||||
| def emitter_label(s): | ||||
|     emit("\t$(hide)", "$(ECHO)", s) | ||||
|  | ||||
|  | ||||
| def emitter_exec(cs): | ||||
|     for c in cs: | ||||
|         emit("\t$(hide)", c) | ||||
|  | ||||
|  | ||||
| def unmake(*ss): | ||||
|     return [ | ||||
|         re.sub(r"\$\(([^)]*)\)", r"$\1", s) for s in flatten(filenamesof(ss)) | ||||
|     ] | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def simplerule( | ||||
|     self, | ||||
|     name, | ||||
|     ins: Targets = None, | ||||
|     outs: List = [], | ||||
|     deps: Targets = None, | ||||
|     commands: List = [], | ||||
|     label="RULE", | ||||
|     **kwargs, | ||||
| ): | ||||
|     self.ins = ins | ||||
|     self.outs = outs | ||||
|     self.deps = deps | ||||
|     emitter_rule(self, ins + deps, outs) | ||||
|     emitter_label(templateexpand("{label} {name}", self)) | ||||
|  | ||||
|     dirs = [] | ||||
|     cs = [] | ||||
|     for out in filenamesof(outs): | ||||
|         dir = dirname(out) | ||||
|         if dir and dir not in dirs: | ||||
|             dirs += [dir] | ||||
|  | ||||
|         cs = [("mkdir -p %s" % dir) for dir in dirs] | ||||
|  | ||||
|     for c in commands: | ||||
|         cs += [templateexpand(c, self)] | ||||
|  | ||||
|     emitter_exec(cs) | ||||
|     emitter_endrule(self, outs) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def normalrule( | ||||
|     self, | ||||
|     name=None, | ||||
|     ins: Targets = None, | ||||
|     deps: Targets = None, | ||||
|     outs: List = [], | ||||
|     label="RULE", | ||||
|     objdir=None, | ||||
|     commands: List = [], | ||||
|     **kwargs, | ||||
| ): | ||||
|     objdir = objdir or join("$(OBJ)", name) | ||||
|  | ||||
|     self.attr.objdir = objdir | ||||
|     simplerule( | ||||
|         replaces=self, | ||||
|         ins=ins, | ||||
|         deps=deps, | ||||
|         outs=[join(objdir, f) for f in outs], | ||||
|         label=label, | ||||
|         commands=commands, | ||||
|         **kwargs, | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def export(self, name=None, items: TargetsMap = {}, deps: Targets = None): | ||||
|     cs = [] | ||||
|     self.ins = [] | ||||
|     self.outs = [] | ||||
|     for dest, src in items.items(): | ||||
|         destf = filenameof(dest) | ||||
|         dir = dirname(destf) | ||||
|  | ||||
|         srcs = filenamesof(src) | ||||
|         if len(srcs) != 1: | ||||
|             raise ABException( | ||||
|                 "a dependency of an export must have exactly one output file" | ||||
|             ) | ||||
|  | ||||
|         subrule = simplerule( | ||||
|             name=self.name + "/+" + destf, | ||||
|             ins=[srcs[0]], | ||||
|             outs=[destf], | ||||
|             commands=["cp %s %s" % (srcs[0], destf)], | ||||
|             label="CP", | ||||
|         ) | ||||
|         subrule.materialise() | ||||
|         emit("clean::") | ||||
|         emit("\t$(hide) rm -f", destf) | ||||
|  | ||||
|         self.ins += [subrule] | ||||
|  | ||||
|     emitter_rule( | ||||
|         self, | ||||
|         self.ins, | ||||
|         self.outs, | ||||
|         [(d.outs if d.outs else d.sentinel) for d in deps], | ||||
|     ) | ||||
|     emitter_endrule(self, self.outs) | ||||
|  | ||||
|  | ||||
| def loadbuildfile(filename): | ||||
|     filename = filename.replace("/", ".").removesuffix(".py") | ||||
|     builtins.__import__(filename) | ||||
|  | ||||
|  | ||||
| def load(filename): | ||||
|     loadbuildfile(filename) | ||||
|     callerglobals = inspect.stack()[1][0].f_globals | ||||
|     for k, v in defaultGlobals.items(): | ||||
|         callerglobals[k] = v | ||||
|  | ||||
|  | ||||
| def main(): | ||||
|     parser = argparse.ArgumentParser() | ||||
|     parser.add_argument("-o", "--output") | ||||
|     parser.add_argument("files", nargs="+") | ||||
|     parser.add_argument("-t", "--targets", action="append") | ||||
|     args = parser.parse_args() | ||||
|     if not args.targets: | ||||
|         raise ABException("no targets supplied") | ||||
|  | ||||
|     global outputFp | ||||
|     outputFp = open(args.output, "wt") | ||||
|  | ||||
|     for k in ("Rule", "Targets", "load", "filenamesof", "stripext"): | ||||
|         defaultGlobals[k] = globals()[k] | ||||
|  | ||||
|     global __name__ | ||||
|     sys.modules["build.ab"] = sys.modules[__name__] | ||||
|     __name__ = "build.ab" | ||||
|  | ||||
|     for f in args.files: | ||||
|         loadbuildfile(f) | ||||
|  | ||||
|     for t in flatten([a.split(",") for a in args.targets]): | ||||
|         (path, target) = t.split("+", 2) | ||||
|         s = join(path, "+" + target) | ||||
|         if s not in targets: | ||||
|             raise ABException("target %s is not defined" % s) | ||||
|         targets[s].materialise() | ||||
|     emit("AB_LOADED = 1\n") | ||||
|  | ||||
|  | ||||
| main() | ||||
							
								
								
									
										251
									
								
								build/build.lua
									
									
									
									
									
								
							
							
						
						
									
										251
									
								
								build/build.lua
									
									
									
									
									
								
							| @@ -1,251 +0,0 @@ | ||||
| local OBJDIR = "$(OBJDIR)" | ||||
|  | ||||
| local function objdir(e) | ||||
| 	return concatpath(OBJDIR, e.cwd, e.name) | ||||
| end | ||||
|  | ||||
| definerule("normalrule", | ||||
| 	{ | ||||
| 		ins = { type="targets" }, | ||||
| 		deps = { type="targets", default={} }, | ||||
| 		outs = { type="targets", default={} }, | ||||
| 		outleaves = { type="strings" }, | ||||
| 		label = { type="string", optional=true }, | ||||
| 		objdir = { type="string", optional=true }, | ||||
| 		commands = { type="strings" }, | ||||
| 	}, | ||||
| 	function (e) | ||||
| 		local dir = e.objdir or objdir(e) | ||||
| 		local realouts = {} | ||||
| 		for _, v in pairs(e.outleaves) do | ||||
| 			realouts[#realouts+1] = concatpath(dir, v) | ||||
| 		end | ||||
|  | ||||
| 		local vars = inherit(e.vars, { | ||||
| 			dir = dir | ||||
| 		}) | ||||
|  | ||||
| 		local result = simplerule { | ||||
| 			name = e.name, | ||||
| 			ins = e.ins, | ||||
| 			deps = e.deps, | ||||
| 			outs = concat(realouts, filenamesof(e.outs)), | ||||
| 			label = e.label, | ||||
| 			commands = e.commands, | ||||
| 			vars = vars, | ||||
| 		} | ||||
| 		result.dir = dir | ||||
| 		return result | ||||
| 	end | ||||
| ) | ||||
|  | ||||
| local function is_clike(f) | ||||
| 	return f:find("%.c$") or f:find("%.cc$") or f:find("%.cpp$") | ||||
| end | ||||
|  | ||||
| definerule("cfile", | ||||
| 	{ | ||||
| 		srcs = { type="targets" }, | ||||
| 		deps = { type="targets", default={} } | ||||
| 	}, | ||||
| 	function (e) | ||||
| 		local cflags = e.vars.cflags | ||||
| 		local cxxflags = e.vars.cxxflags | ||||
| 		for _, target in ipairs(targetsof(e.deps)) do | ||||
| 			if target.is.clibrary then | ||||
| 				cflags = concat(cflags, target.dep_cflags) | ||||
| 				cxxflags = concat(cxxflags, target.dep_cxxflags) | ||||
| 			end | ||||
| 		end | ||||
|  | ||||
| 		local src = filter(filenamesof(e.srcs), is_clike) | ||||
| 		local cmd | ||||
| 		local cxx = false | ||||
| 		if src[1]:find("%.c$") then | ||||
| 			cmd = "$(CC) -c -o %{outs[1]} %{ins[1]} %{hdrpaths} %{cflags}" | ||||
| 		else | ||||
| 			cmd = "$(CXX) -c -o %{outs[1]} %{ins[1]} %{hdrpaths} %{cflags} %{cxxflags}" | ||||
| 			cxx = true | ||||
| 		end | ||||
|  | ||||
| 		local outleaf = basename(e.name)..".o" | ||||
| 		local rule = normalrule { | ||||
| 			name = e.name, | ||||
| 			cwd = e.cwd, | ||||
| 			ins = e.srcs, | ||||
| 			deps = e.deps, | ||||
| 			outleaves = {outleaf}, | ||||
| 			label = e.label, | ||||
| 			commands = cmd, | ||||
| 			vars = { | ||||
| 				hdrpaths = {}, | ||||
| 				cflags = cflags, | ||||
| 				cxxflags = cxxflags, | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		rule.is.cxxfile = cxx | ||||
| 		return rule | ||||
| 	end | ||||
| ) | ||||
|  | ||||
| local function do_cfiles(e) | ||||
| 	local outs = {} | ||||
| 	local srcs = filenamesof(e.srcs) | ||||
| 	for _, f in ipairs(sorted(filter(srcs, is_clike))) do | ||||
| 		local ofile | ||||
| 		if f:find(OBJDIR, 1, true) == 1 then | ||||
| 			ofile = e.name.."/"..f:sub(#OBJDIR+1)..".o" | ||||
| 		else | ||||
| 			ofile = e.name.."/"..f..".o" | ||||
| 		end | ||||
| 		outs[#outs+1] = cfile { | ||||
| 			name = ofile, | ||||
| 			srcs = { f }, | ||||
| 			deps = e.deps | ||||
| 		} | ||||
| 	end | ||||
| 	return outs | ||||
| end | ||||
|  | ||||
| definerule("clibrary", | ||||
| 	{ | ||||
| 		srcs = { type="targets", default={} }, | ||||
| 		deps = { type="targets", default={} }, | ||||
| 		hdrs = { type="targets", default={} }, | ||||
| 		dep_cflags = { type="strings", default={} }, | ||||
| 		dep_cxxflags = { type="strings", default={} }, | ||||
| 		dep_ldflags = { type="strings", default={} }, | ||||
| 		dep_libs = { type="strings", default={} }, | ||||
| 	}, | ||||
| 	function (e) | ||||
| 		local ins = do_cfiles(e) | ||||
| 		local cxx = false | ||||
| 		for _, f in ipairs(ins) do | ||||
| 			if f.is.cxxfile then | ||||
| 				cxx = true | ||||
| 				break | ||||
| 			end | ||||
| 		end | ||||
|  | ||||
| 		local mkdirs = {} | ||||
| 		local copies = {} | ||||
| 		local outs = {} | ||||
| 		local function copy_file(src, dest) | ||||
| 			mkdirs[#mkdirs+1] = "mkdir -p %{dir}/"..dirname(dest) | ||||
| 			copies[#copies+1] = "cp "..src.." %{dir}/"..dest | ||||
| 			outs[#outs+1] = objdir(e).."/"..dest | ||||
| 		end | ||||
|  | ||||
| 		local deps = {} | ||||
| 		for k, v in pairs(e.hdrs) do | ||||
| 			deps[#deps+1] = v | ||||
| 			if type(k) == "number" then | ||||
| 				v = filenamesof(v) | ||||
| 				for _, v in ipairs(v) do | ||||
| 					if not startswith(e.cwd, v) then | ||||
| 						error(string.format("filename '%s' is not local to '%s' --- ".. | ||||
| 							"you'll have to specify the output filename manually", v, e.cwd)) | ||||
| 					end | ||||
| 					copy_file(v, v:gsub("^"..e.cwd, "")) | ||||
| 				end | ||||
| 			else | ||||
| 				v = filenamesof(v) | ||||
| 				if #v ~= 1 then | ||||
| 					error("each mapped hdrs item can only cope with a single file") | ||||
| 				end | ||||
| 				copy_file(v[1], k) | ||||
| 			end | ||||
| 		end | ||||
|  | ||||
| 		ins = sorted(filenamesof(ins)) | ||||
| 		local has_ar = (#ins ~= 0) | ||||
| 		local lib = normalrule { | ||||
| 			name = e.name, | ||||
| 			cwd = e.cwd, | ||||
| 			ins = sorted(filenamesof(ins)), | ||||
| 			deps = deps, | ||||
| 			outs = outs, | ||||
| 			outleaves = { e.name..".a" }, | ||||
| 			label = e.label, | ||||
| 			commands = { | ||||
| 				sorted(mkdirs), | ||||
| 				sorted(copies), | ||||
| 				has_ar and "rm -f %{outs[1]} && $(AR) cqs %{outs[1]} %{ins}" or {}, | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		lib.dep_cflags = concat(e.dep_cflags, "-I"..lib.dir) | ||||
| 		lib.dep_cxxflags = e.dep_cxxflags | ||||
| 		lib.dep_ldflags = e.dep_ldflags | ||||
| 		lib.dep_libs = concat(e.dep_libs, has_ar and matching(filenamesof(lib), "%.a$") or {}) | ||||
| 		lib.dep_cxx = cxx | ||||
|  | ||||
| 		for _, d in pairs(targetsof(e.deps)) do | ||||
| 			lib.dep_cflags = concat(lib.dep_cflags, d.dep_cflags) | ||||
| 			lib.dep_cxxflags = concat(lib.dep_cxxflags, d.dep_cxxflags) | ||||
| 			lib.dep_ldflags = concat(lib.dep_ldflags, d.dep_ldflags) | ||||
| 			lib.dep_libs = concat(lib.dep_libs, d.dep_libs) | ||||
| 			lib.dep_cxx = lib.dep_cxx or d.dep_cxx | ||||
| 		end | ||||
|  | ||||
| 		return lib | ||||
| 	end | ||||
| ) | ||||
|  | ||||
| definerule("cprogram", | ||||
| 	{ | ||||
| 		srcs = { type="targets", default={} }, | ||||
| 		deps = { type="targets", default={} }, | ||||
| 	}, | ||||
| 	function (e) | ||||
| 		local deps = e.deps | ||||
| 		local ins = {} | ||||
| 		local cxx = false | ||||
|  | ||||
| 		if (#e.srcs > 0) then | ||||
| 			local objs = do_cfiles(e) | ||||
| 			for _, obj in pairs(objs) do | ||||
| 				if obj.is.cxxfile then | ||||
| 					cxx = true | ||||
| 				end | ||||
| 				ins[#ins+1] = obj | ||||
| 			end | ||||
| 		end | ||||
|  | ||||
| 		local libs = {} | ||||
| 		local cflags = {} | ||||
| 		local cxxflags = {} | ||||
| 		local ldflags = {} | ||||
| 		for _, lib in pairs(e.deps) do | ||||
| 			cflags = concat(cflags, lib.dep_cflags) | ||||
| 			cxxflags = concat(cxxflags, lib.dep_cxxflags) | ||||
| 			ldflags = concat(ldflags, lib.dep_ldflags) | ||||
| 			libs = concat(libs, lib.dep_libs) | ||||
| 			cxx = cxx or lib.dep_cxx | ||||
| 		end | ||||
|  | ||||
| 		local command | ||||
| 		if cxx then | ||||
| 			command = "$(CXX) $(LDFLAGS) %{ldflags} -o %{outs[1]} %{ins} %{libs} %{libs}" | ||||
| 		else | ||||
| 			command = "$(CC) $(LDFLAGS) %{ldflags} -o %{outs[1]} %{ins} %{libs} %{libs}" | ||||
| 		end | ||||
|  | ||||
| 		return normalrule { | ||||
| 			name = e.name, | ||||
| 			cwd = e.cwd, | ||||
| 			deps = deps, | ||||
| 			ins = ins, | ||||
| 			outleaves = { e.name }, | ||||
| 			commands = { command }, | ||||
| 			vars = { | ||||
| 				cflags = cflags, | ||||
| 				cxxflags = cxxflags, | ||||
| 				ldflags = ldflags, | ||||
| 				libs = libs, | ||||
| 			} | ||||
| 		} | ||||
| 	end | ||||
| ) | ||||
|  | ||||
							
								
								
									
										372
									
								
								build/c.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										372
									
								
								build/c.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,372 @@ | ||||
| from os.path import basename, join | ||||
| from build.ab import ( | ||||
|     ABException, | ||||
|     List, | ||||
|     Rule, | ||||
|     Targets, | ||||
|     TargetsMap, | ||||
|     filenameof, | ||||
|     filenamesmatchingof, | ||||
|     filenamesof, | ||||
|     flatten, | ||||
|     normalrule, | ||||
|     bubbledattrsof, | ||||
|     stripext, | ||||
|     targetswithtraitsof, | ||||
| ) | ||||
| from os.path import * | ||||
| from types import SimpleNamespace | ||||
|  | ||||
|  | ||||
| class Toolchain: | ||||
|     label = "" | ||||
|     cfile = ["$(CC) -c -o {outs[0]} {ins[0]} $(CFLAGS) {cflags}"] | ||||
|     cxxfile = ["$(CXX) -c -o {outs[0]} {ins[0]} $(CFLAGS) {cflags}"] | ||||
|     clibrary = ["$(AR) cqs {outs[0]} {ins}"] | ||||
|     cxxlibrary = ["$(AR) cqs {outs[0]} {ins}"] | ||||
|     cprogram = ["$(CC) -o {outs[0]} {ins} {ldflags} $(LDFLAGS)"] | ||||
|     cxxprogram = ["$(CXX) -o {outs[0]} {ins} {ldflags} $(LDFLAGS)"] | ||||
|  | ||||
|  | ||||
| class HostToolchain: | ||||
|     label = "HOST " | ||||
|     cfile = ["$(HOSTCC) -c -o {outs[0]} {ins[0]} $(HOSTCFLAGS) {cflags}"] | ||||
|     cxxfile = ["$(HOSTCXX) -c -o {outs[0]} {ins[0]} $(HOSTCFLAGS) {cflags}"] | ||||
|     clibrary = ["$(HOSTAR) cqs {outs[0]} {ins}"] | ||||
|     cxxlibrary = ["$(HOSTAR) cqs {outs[0]} {ins}"] | ||||
|     cprogram = ["$(HOSTCC) -o {outs[0]} {ins} {ldflags} $(HOSTLDFLAGS)"] | ||||
|     cxxprogram = ["$(HOSTCXX) -o {outs[0]} {ins} {ldflags} $(HOSTLDFLAGS)"] | ||||
|  | ||||
|  | ||||
| def cfileimpl(self, name, srcs, deps, suffix, commands, label, kind, cflags): | ||||
|     outleaf = stripext(basename(filenameof(srcs[0]))) + suffix | ||||
|  | ||||
|     normalrule( | ||||
|         replaces=self, | ||||
|         ins=srcs, | ||||
|         deps=deps, | ||||
|         outs=[outleaf], | ||||
|         label=label, | ||||
|         commands=commands, | ||||
|         cflags=cflags + bubbledattrsof(deps, "caller_cflags"), | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def cfile( | ||||
|     self, | ||||
|     name, | ||||
|     srcs: Targets = None, | ||||
|     deps: Targets = None, | ||||
|     cflags: List = [], | ||||
|     suffix=".o", | ||||
|     toolchain=Toolchain, | ||||
|     commands=None, | ||||
|     label=None, | ||||
| ): | ||||
|     if not label: | ||||
|         label = toolchain.label + "CC" | ||||
|     if not commands: | ||||
|         commands = toolchain.cfile | ||||
|     cfileimpl(self, name, srcs, deps, suffix, commands, label, "cfile", cflags) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def cxxfile( | ||||
|     self, | ||||
|     name, | ||||
|     srcs: Targets = None, | ||||
|     deps: Targets = None, | ||||
|     cflags: List = [], | ||||
|     suffix=".o", | ||||
|     toolchain=Toolchain, | ||||
|     commands=None, | ||||
|     label=None, | ||||
| ): | ||||
|     if not label: | ||||
|         label = toolchain.label + "CXX" | ||||
|     if not commands: | ||||
|         commands = toolchain.cxxfile | ||||
|     cfileimpl( | ||||
|         self, name, srcs, deps, suffix, commands, label, "cxxfile", cflags | ||||
|     ) | ||||
|  | ||||
|  | ||||
| def findsources(name, srcs, deps, cflags, toolchain, filerule): | ||||
|     objs = [] | ||||
|     for s in flatten(srcs): | ||||
|         objs += [ | ||||
|             filerule( | ||||
|                 name=join(name, f.removeprefix("$(OBJ)/")), | ||||
|                 srcs=[f], | ||||
|                 deps=deps, | ||||
|                 cflags=cflags, | ||||
|                 toolchain=toolchain, | ||||
|             ) | ||||
|             for f in filenamesof(s) | ||||
|             if f.endswith(".c") | ||||
|             or f.endswith(".cc") | ||||
|             or f.endswith(".cpp") | ||||
|             or f.endswith(".S") | ||||
|             or f.endswith(".s") | ||||
|         ] | ||||
|         if any(f.endswith(".o") for f in filenamesof(s)): | ||||
|             objs += [s] | ||||
|  | ||||
|     return objs | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def cheaders( | ||||
|     self, | ||||
|     name, | ||||
|     hdrs: TargetsMap = None, | ||||
|     caller_cflags: List = None, | ||||
|     deps: Targets = None, | ||||
| ): | ||||
|     cs = [] | ||||
|     ins = list(hdrs.values()) | ||||
|     outs = [] | ||||
|     i = 0 | ||||
|     for dest, src in hdrs.items(): | ||||
|         s = filenamesof(src) | ||||
|         if len(s) != 1: | ||||
|             raise ABException( | ||||
|                 "the target of a header must return exactly one file" | ||||
|             ) | ||||
|  | ||||
|         cs += ["cp {ins[" + str(i) + "]} {outs[" + str(i) + "]}"] | ||||
|         outs += [dest] | ||||
|         i = i + 1 | ||||
|  | ||||
|     r = normalrule( | ||||
|         replaces=self, | ||||
|         ins=ins, | ||||
|         outs=outs, | ||||
|         commands=cs, | ||||
|         deps=deps, | ||||
|         label="CHEADERS", | ||||
|     ) | ||||
|     r.materialise() | ||||
|     self.attr.caller_cflags = caller_cflags + ["-I" + r.attr.objdir] | ||||
|     self.bubbleattr("caller_cflags", deps) | ||||
|  | ||||
|  | ||||
| def libraryimpl( | ||||
|     self, | ||||
|     name, | ||||
|     srcs, | ||||
|     deps, | ||||
|     hdrs, | ||||
|     caller_cflags, | ||||
|     caller_ldflags, | ||||
|     cflags, | ||||
|     ldflags, | ||||
|     toolchain, | ||||
|     commands, | ||||
|     label, | ||||
|     kind, | ||||
| ): | ||||
|     hr = None | ||||
|     if hdrs and not srcs: | ||||
|         cheaders( | ||||
|             replaces=self, | ||||
|             hdrs=hdrs, | ||||
|             deps=targetswithtraitsof(deps, "cheaders"), | ||||
|             caller_cflags=caller_cflags, | ||||
|         ) | ||||
|         return | ||||
|     if hdrs: | ||||
|         hr = cheaders( | ||||
|             name=self.localname + "_hdrs", | ||||
|             hdrs=hdrs, | ||||
|             deps=targetswithtraitsof(deps, "cheaders"), | ||||
|             caller_cflags=caller_cflags, | ||||
|         ) | ||||
|         hr.materialise() | ||||
|         deps = deps + [hr] | ||||
|  | ||||
|     objs = findsources( | ||||
|         name, | ||||
|         srcs, | ||||
|         targetswithtraitsof(deps, "cheaders"), | ||||
|         cflags + bubbledattrsof(deps, "caller_cflags"), | ||||
|         toolchain, | ||||
|         kind, | ||||
|     ) | ||||
|  | ||||
|     normalrule( | ||||
|         replaces=self, | ||||
|         ins=objs, | ||||
|         outs=[basename(name) + ".a"], | ||||
|         label=label, | ||||
|         commands=commands, | ||||
|     ) | ||||
|     self.outs = self.outs + (hr.outs if hr else []) | ||||
|  | ||||
|     self.traits.add("cheaders") | ||||
|     self.attr.caller_ldflags = caller_ldflags | ||||
|     self.bubbleattr("caller_ldflags", deps) | ||||
|     self.bubbleattr("caller_cflags", deps) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def clibrary( | ||||
|     self, | ||||
|     name, | ||||
|     srcs: Targets = None, | ||||
|     deps: Targets = None, | ||||
|     hdrs: TargetsMap = None, | ||||
|     caller_cflags: List = [], | ||||
|     caller_ldflags: List = [], | ||||
|     cflags: List = [], | ||||
|     ldflags: List = [], | ||||
|     toolchain=Toolchain, | ||||
|     commands=None, | ||||
|     label=None, | ||||
|     cfilerule=cfile, | ||||
| ): | ||||
|     if not label: | ||||
|         label = toolchain.label + "LIB" | ||||
|     if not commands: | ||||
|         commands = toolchain.clibrary | ||||
|     libraryimpl( | ||||
|         self, | ||||
|         name, | ||||
|         srcs, | ||||
|         deps, | ||||
|         hdrs, | ||||
|         caller_cflags, | ||||
|         caller_ldflags, | ||||
|         cflags, | ||||
|         ldflags, | ||||
|         toolchain, | ||||
|         commands, | ||||
|         label, | ||||
|         cfilerule, | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def cxxlibrary( | ||||
|     self, | ||||
|     name, | ||||
|     srcs: Targets = None, | ||||
|     deps: Targets = None, | ||||
|     hdrs: TargetsMap = None, | ||||
|     caller_cflags: List = [], | ||||
|     caller_ldflags: List = [], | ||||
|     cflags: List = [], | ||||
|     ldflags: List = [], | ||||
|     toolchain=Toolchain, | ||||
|     commands=None, | ||||
|     label=None, | ||||
| ): | ||||
|     if not label: | ||||
|         label = toolchain.label + "LIB" | ||||
|     if not commands: | ||||
|         commands = toolchain.clibrary | ||||
|     libraryimpl( | ||||
|         self, | ||||
|         name, | ||||
|         srcs, | ||||
|         deps, | ||||
|         hdrs, | ||||
|         caller_cflags, | ||||
|         caller_ldflags, | ||||
|         cflags, | ||||
|         ldflags, | ||||
|         toolchain, | ||||
|         commands, | ||||
|         label, | ||||
|         cxxfile, | ||||
|     ) | ||||
|  | ||||
|  | ||||
| def programimpl( | ||||
|     self, | ||||
|     name, | ||||
|     srcs, | ||||
|     deps, | ||||
|     cflags, | ||||
|     ldflags, | ||||
|     toolchain, | ||||
|     commands, | ||||
|     label, | ||||
|     filerule, | ||||
|     kind, | ||||
| ): | ||||
|     ars = filenamesmatchingof(deps, "*.a") | ||||
|     deps = deps + filenamesmatchingof(srcs, "*.h") | ||||
|     ldflags = ldflags + bubbledattrsof(deps, "caller_ldflags") | ||||
|  | ||||
|     cfiles = findsources(name, srcs, deps, cflags, toolchain, filerule) | ||||
|     normalrule( | ||||
|         replaces=self, | ||||
|         ins=cfiles + ars + ars, | ||||
|         outs=[basename(name) + "$(EXT)"], | ||||
|         deps=deps, | ||||
|         label=toolchain.label + label, | ||||
|         commands=commands, | ||||
|         ldflags=ldflags, | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def cprogram( | ||||
|     self, | ||||
|     name, | ||||
|     srcs: Targets = None, | ||||
|     deps: Targets = None, | ||||
|     cflags: List = [], | ||||
|     ldflags: List = [], | ||||
|     toolchain=Toolchain, | ||||
|     commands=None, | ||||
|     label="CLINK", | ||||
|     cfilerule=cfile, | ||||
|     cfilekind="cprogram", | ||||
| ): | ||||
|     if not commands: | ||||
|         commands = toolchain.cprogram | ||||
|     programimpl( | ||||
|         self, | ||||
|         name, | ||||
|         srcs, | ||||
|         deps, | ||||
|         cflags, | ||||
|         ldflags, | ||||
|         toolchain, | ||||
|         commands, | ||||
|         label, | ||||
|         cfilerule, | ||||
|         cfilekind, | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def cxxprogram( | ||||
|     self, | ||||
|     name, | ||||
|     srcs: Targets = None, | ||||
|     deps: Targets = None, | ||||
|     cflags: List = [], | ||||
|     ldflags: List = [], | ||||
|     toolchain=Toolchain, | ||||
|     commands=None, | ||||
|     label="CXXLINK", | ||||
| ): | ||||
|     if not commands: | ||||
|         commands = toolchain.cxxprogram | ||||
|     programimpl( | ||||
|         self, | ||||
|         name, | ||||
|         srcs, | ||||
|         deps, | ||||
|         cflags, | ||||
|         ldflags, | ||||
|         toolchain, | ||||
|         commands, | ||||
|         label, | ||||
|         cxxfile, | ||||
|         "cxxprogram", | ||||
|     ) | ||||
							
								
								
									
										81
									
								
								build/pkg.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								build/pkg.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | ||||
| from build.ab import Rule, emit, Target, bubbledattrsof, filenamesof | ||||
| from types import SimpleNamespace | ||||
| import os | ||||
| import subprocess | ||||
|  | ||||
| emit( | ||||
|     """ | ||||
| PKG_CONFIG ?= pkg-config | ||||
| PACKAGES := $(shell $(PKG_CONFIG) --list-all | cut -d' ' -f1 | sort) | ||||
|  | ||||
| HOST_PKG_CONFIG ?= pkg-config | ||||
| HOST_PACKAGES := $(shell $(HOST_PKG_CONFIG) --list-all | cut -d' ' -f1 | sort) | ||||
| """ | ||||
| ) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def package(self, name, package=None, fallback: Target = None): | ||||
|     emit("ifeq ($(filter %s, $(PACKAGES)),)" % package) | ||||
|     if fallback: | ||||
|         emit(f"PACKAGE_DEPS_{package} := ", filenamesof(fallback)) | ||||
|         emit( | ||||
|             f"PACKAGE_CFLAGS_{package} :=", | ||||
|             bubbledattrsof(fallback, "caller_cflags"), | ||||
|         ) | ||||
|         emit( | ||||
|             f"PACKAGE_LDFLAGS_{package} := ", | ||||
|             bubbledattrsof(fallback, "caller_ldflags"), | ||||
|             f"$(filter %.a, $(PACKAGE_DEPS_{package}))", | ||||
|         ) | ||||
|     else: | ||||
|         emit(f"$(error Required package '{package}' not installed.)") | ||||
|     emit("else") | ||||
|     emit( | ||||
|         f"PACKAGE_CFLAGS_{package} := $(shell $(PKG_CONFIG) --cflags {package})" | ||||
|     ) | ||||
|     emit( | ||||
|         f"PACKAGE_LDFLAGS_{package} := $(shell $(PKG_CONFIG) --libs {package})" | ||||
|     ) | ||||
|     emit(f"PACKAGE_DEPS_{package} :=") | ||||
|     emit("endif") | ||||
|  | ||||
|     self.attr.caller_cflags = [f"$(PACKAGE_CFLAGS_{package})"] | ||||
|     self.attr.caller_ldflags = [f"$(PACKAGE_LDFLAGS_{package})"] | ||||
|     self.traits.add("clibrary") | ||||
|     self.traits.add("cheaders") | ||||
|  | ||||
|     self.ins = [] | ||||
|     self.outs = [f"$(PACKAGE_DEPS_{package})"] | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def hostpackage(self, name, package=None, fallback: Target = None): | ||||
|     emit("ifeq ($(filter %s, $(HOST_PACKAGES)),)" % package) | ||||
|     if fallback: | ||||
|         emit( | ||||
|             f"HOST_PACKAGE_CFLAGS_{package} :=", | ||||
|             bubbledattrsof(fallback, "caller_cflags"), | ||||
|         ) | ||||
|         emit( | ||||
|             f"HOST_PACKAGE_LDFLAGS_{package} := ", | ||||
|             bubbledattrsof(fallback, "caller_ldflags"), | ||||
|         ) | ||||
|         emit(f"HOST_PACKAGE_DEP_{package} := ", fallback.name) | ||||
|     else: | ||||
|         emit(f"$(error Required host package '{package}' not installed.)") | ||||
|     emit("else") | ||||
|     emit( | ||||
|         f"HOST_PACKAGE_CFLAGS_{package} := $(shell $(HOST_PKG_CONFIG) --cflags {package})" | ||||
|     ) | ||||
|     emit( | ||||
|         f"HOST_PACKAGE_LDFLAGS_{package} := $(shell $(HOST_PKG_CONFIG) --libs {package})" | ||||
|     ) | ||||
|     emit(f"HOST_PACKAGE_DEP_{package} := ") | ||||
|     emit("endif") | ||||
|  | ||||
|     self.attr.caller_cflags = [f"$(HOST_PACKAGE_CFLAGS_{package})"] | ||||
|     self.attr.caller_ldflags = [f"$(HOST_PACKAGE_LDFLAGS_{package})"] | ||||
|  | ||||
|     self.ins = [] | ||||
|     self.outs = [f"$(HOST_PACKAGE_DEP_{package})"] | ||||
							
								
								
									
										73
									
								
								build/protobuf.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								build/protobuf.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | ||||
| from os.path import join | ||||
| from build.ab import ( | ||||
|     Rule, | ||||
|     Targets, | ||||
|     emit, | ||||
|     normalrule, | ||||
|     filenamesof, | ||||
|     filenamesmatchingof, | ||||
|     bubbledattrsof, | ||||
|     targetswithtraitsof, | ||||
| ) | ||||
| from build.c import cxxlibrary | ||||
| from types import SimpleNamespace | ||||
| from build.pkg import package | ||||
|  | ||||
| emit( | ||||
|     """ | ||||
| PROTOC ?= protoc | ||||
| ifeq ($(filter protobuf, $(PACKAGES)),) | ||||
| $(error Required package 'protobuf' not installed.)" | ||||
| endif | ||||
| """ | ||||
| ) | ||||
|  | ||||
| lib = package(name="protobuf_lib", package="protobuf") | ||||
|  | ||||
| @Rule | ||||
| def proto(self, name, srcs: Targets = None, deps: Targets = None): | ||||
|     normalrule( | ||||
|         replaces=self, | ||||
|         ins=srcs, | ||||
|         outs=[f"{name}.descriptor"], | ||||
|         deps=deps, | ||||
|         commands=[ | ||||
|             "$(PROTOC) --include_source_info --descriptor_set_out={outs[0]} {ins}" | ||||
|         ], | ||||
|         label="PROTO", | ||||
|     ) | ||||
|     self.attr.protosrcs = filenamesof(srcs) | ||||
|     self.bubbleattr("protosrcs", deps) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def protocc(self, name, srcs: Targets = None, deps: Targets = None): | ||||
|     outs = [] | ||||
|     protos = [] | ||||
|  | ||||
|     for f in filenamesmatchingof(bubbledattrsof(srcs, "protosrcs"), "*.proto"): | ||||
|         cc = f.replace(".proto", ".pb.cc") | ||||
|         h = f.replace(".proto", ".pb.h") | ||||
|         protos += [f] | ||||
|         srcs += [f] | ||||
|         outs += [cc, h] | ||||
|  | ||||
|     srcname = f"{name}_srcs" | ||||
|     objdir = join("$(OBJ)", srcname) | ||||
|     r = normalrule( | ||||
|         name=srcname, | ||||
|         ins=protos, | ||||
|         outs=outs, | ||||
|         deps=deps, | ||||
|         commands=["$(PROTOC) --cpp_out={self.attr.objdir} {ins}"], | ||||
|         label="PROTOCC", | ||||
|     ) | ||||
|  | ||||
|     headers = {f: join(objdir, f) for f in outs if f.endswith(".pb.h")} | ||||
|  | ||||
|     cxxlibrary( | ||||
|         replaces=self, | ||||
|         srcs=[r], | ||||
|         deps=targetswithtraitsof(deps, "cheaders") + [lib], | ||||
|         hdrs=headers, | ||||
|     ) | ||||
| @@ -1,18 +0,0 @@ | ||||
| definerule("test", | ||||
| 	{ | ||||
| 		srcs = { type="targets", default={} }, | ||||
| 	}, | ||||
| 	function (e) | ||||
| 		if vars.TESTS == "yes" then | ||||
| 			normalrule { | ||||
| 				name = e.name, | ||||
| 				ins = e.srcs, | ||||
| 				outleaves = { "log.txt" }, | ||||
| 				commands = { | ||||
| 					"%{ins} > %{outs}", | ||||
| 				} | ||||
| 			} | ||||
| 		end | ||||
| 	end | ||||
| ) | ||||
|  | ||||
							
								
								
									
										43
									
								
								build/utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								build/utils.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| from build.ab import Rule, normalrule, Target, filenameof, Targets | ||||
| from os.path import basename | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def objectify(self, name, src: Target, symbol): | ||||
|     normalrule( | ||||
|         replaces=self, | ||||
|         ins=["build/_objectify.py", src], | ||||
|         outs=[basename(filenameof(src)) + ".h"], | ||||
|         commands=["$(PYTHON) {ins[0]} {ins[1]} " + symbol + " > {outs}"], | ||||
|         label="OBJECTIFY", | ||||
|     ) | ||||
|  | ||||
|  | ||||
| @Rule | ||||
| def test( | ||||
|     self, | ||||
|     name, | ||||
|     command: Target = None, | ||||
|     commands=None, | ||||
|     ins: Targets = None, | ||||
|     deps: Targets = None, | ||||
|     label="TEST", | ||||
| ): | ||||
|     if command: | ||||
|         normalrule( | ||||
|             replaces=self, | ||||
|             ins=[command], | ||||
|             outs=["sentinel"], | ||||
|             commands=["{ins[0]}", "touch {outs}"], | ||||
|             deps=deps, | ||||
|             label=label, | ||||
|         ) | ||||
|     else: | ||||
|         normalrule( | ||||
|             replaces=self, | ||||
|             ins=ins, | ||||
|             outs=["sentinel"], | ||||
|             commands=commands + ["touch {outs}"], | ||||
|             deps=deps, | ||||
|             label=label, | ||||
|         ) | ||||
							
								
								
									
										11
									
								
								config.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								config.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| import platform | ||||
| import os | ||||
|  | ||||
| if os.getenv("BUILDTYPE") == "windows": | ||||
|     windows = True | ||||
|     osx = False | ||||
|     unix = False | ||||
| else: | ||||
|     windows = False | ||||
|     osx = platform.system() == "Darwin" | ||||
|     unix = True | ||||
| @@ -1,22 +0,0 @@ | ||||
| ADFLIB_SRCS = \ | ||||
| 	dep/adflib/src/adf_bitm.c \ | ||||
| 	dep/adflib/src/adf_cache.c \ | ||||
| 	dep/adflib/src/adf_dir.c \ | ||||
| 	dep/adflib/src/adf_disk.c \ | ||||
| 	dep/adflib/src/adf_dump.c \ | ||||
| 	dep/adflib/src/adf_env.c \ | ||||
| 	dep/adflib/src/adf_file.c \ | ||||
| 	dep/adflib/src/adf_hd.c \ | ||||
| 	dep/adflib/src/adf_link.c \ | ||||
| 	dep/adflib/src/adf_raw.c \ | ||||
| 	dep/adflib/src/adf_salv.c \ | ||||
| 	dep/adflib/src/adf_util.c \ | ||||
|  | ||||
| ADFLIB_OBJS = $(patsubst %.c, $(OBJDIR)/%.o, $(ADFLIB_SRCS)) | ||||
| $(ADFLIB_OBJS): CFLAGS += -Idep/adflib/src -Idep/adflib | ||||
| ADFLIB_LIB = $(OBJDIR)/libadflib.a | ||||
| $(ADFLIB_LIB): $(ADFLIB_OBJS) | ||||
| ADFLIB_CFLAGS = -Idep/adflib/src | ||||
| ADFLIB_LDFLAGS = | ||||
| OBJS += $(ADFLIB_OBJS) | ||||
|  | ||||
							
								
								
									
										47
									
								
								dep/adflib/build.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								dep/adflib/build.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| from build.c import clibrary | ||||
|  | ||||
| clibrary( | ||||
|     name="adflib", | ||||
|     srcs=[ | ||||
|         "./src/adf_bitm.c", | ||||
|         "./src/adf_bitm.h", | ||||
|         "./src/adf_cache.c", | ||||
|         "./src/adf_cache.h", | ||||
|         "./src/adf_dir.c", | ||||
|         "./src/adf_dir.h", | ||||
|         "./src/adf_disk.c", | ||||
|         "./src/adf_disk.h", | ||||
|         "./src/adf_dump.c", | ||||
|         "./src/adf_dump.h", | ||||
|         "./src/adf_env.c", | ||||
|         "./src/adf_env.h", | ||||
|         "./src/adf_file.c", | ||||
|         "./src/adf_file.h", | ||||
|         "./src/adf_hd.c", | ||||
|         "./src/adf_hd.h", | ||||
|         "./src/adf_link.c", | ||||
|         "./src/adf_link.h", | ||||
|         "./src/adf_raw.c", | ||||
|         "./src/adf_raw.h", | ||||
|         "./src/adf_salv.c", | ||||
|         "./src/adf_salv.h", | ||||
|         "./src/adf_str.h", | ||||
|         "./src/adf_util.c", | ||||
|         "./src/adf_util.h", | ||||
|         "./src/defendian.h", | ||||
|         "./src/hd_blk.h", | ||||
|         "./src/prefix.h", | ||||
|         "./adf_nativ.h", | ||||
|         "./config.h", | ||||
|         "./src/adflib.h", | ||||
|     ], | ||||
|     cflags=["-Idep/adflib", "-Idep/adflib/src"], | ||||
|     hdrs={ | ||||
|         "adf_blk.h": "./src/adf_blk.h", | ||||
|         "adf_defs.h": "./src/adf_defs.h", | ||||
|         "adf_err.h": "./src/adf_err.h", | ||||
|         "adf_nativ.h": "./adf_nativ.h", | ||||
|         "adf_str.h": "./src/adf_str.h", | ||||
|         "adflib.h": "./src/adflib.h", | ||||
|     }, | ||||
| ) | ||||
| @@ -1,38 +0,0 @@ | ||||
| AGG_SRCS = \ | ||||
| 	dep/agg/src/agg_arrowhead.cpp \ | ||||
| 	dep/agg/src/agg_line_aa_basics.cpp \ | ||||
| 	dep/agg/src/agg_vcgen_bspline.cpp \ | ||||
| 	dep/agg/src/agg_vpgen_segmentator.cpp \ | ||||
| 	dep/agg/src/agg_color_rgba.cpp \ | ||||
| 	dep/agg/src/agg_sqrt_tables.cpp \ | ||||
| 	dep/agg/src/agg_bspline.cpp \ | ||||
| 	dep/agg/src/agg_curves.cpp \ | ||||
| 	dep/agg/src/agg_rounded_rect.cpp \ | ||||
| 	dep/agg/src/agg_vcgen_markers_term.cpp \ | ||||
| 	dep/agg/src/agg_vcgen_dash.cpp \ | ||||
| 	dep/agg/src/agg2d.cpp \ | ||||
| 	dep/agg/src/agg_trans_affine.cpp \ | ||||
| 	dep/agg/src/agg_gsv_text.cpp \ | ||||
| 	dep/agg/src/agg_vcgen_smooth_poly1.cpp \ | ||||
| 	dep/agg/src/agg_trans_single_path.cpp \ | ||||
| 	dep/agg/src/agg_vpgen_clip_polygon.cpp \ | ||||
| 	dep/agg/src/agg_embedded_raster_fonts.cpp \ | ||||
| 	dep/agg/src/agg_trans_double_path.cpp \ | ||||
| 	dep/agg/src/agg_vcgen_stroke.cpp \ | ||||
| 	dep/agg/src/agg_arc.cpp \ | ||||
| 	dep/agg/src/agg_image_filters.cpp \ | ||||
| 	dep/agg/src/agg_trans_warp_magnifier.cpp \ | ||||
| 	dep/agg/src/agg_vpgen_clip_polyline.cpp \ | ||||
| 	dep/agg/src/agg_bezier_arc.cpp \ | ||||
| 	dep/agg/src/agg_line_profile_aa.cpp \ | ||||
| 	dep/agg/src/agg_vcgen_contour.cpp \ | ||||
| 	 | ||||
| AGG_OBJS = $(patsubst %.cpp, $(OBJDIR)/%.o, $(AGG_SRCS)) | ||||
| AGG_LIB = $(OBJDIR)/libagg.a | ||||
| $(AGG_LIB): $(AGG_OBJS) | ||||
| AGG_LDFLAGS = $(AGG_LIB) | ||||
| AGG_CFLAGS = -Idep/agg/include | ||||
| OBJS += $(AGG_OBJS) | ||||
|  | ||||
| $(AGG_OBJS): CFLAGS += $(AGG_CFLAGS) | ||||
|  | ||||
							
								
								
									
										164
									
								
								dep/agg/build.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								dep/agg/build.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,164 @@ | ||||
| from build.c import cxxlibrary | ||||
|  | ||||
| cxxlibrary( | ||||
|     name="agg", | ||||
|     srcs=[ | ||||
|         "./src/agg_arrowhead.cpp", | ||||
|         "./src/agg_line_aa_basics.cpp", | ||||
|         "./src/agg_vcgen_bspline.cpp", | ||||
|         "./src/agg_vpgen_segmentator.cpp", | ||||
|         "./src/agg_color_rgba.cpp", | ||||
|         "./src/agg_sqrt_tables.cpp", | ||||
|         "./src/agg_bspline.cpp", | ||||
|         "./src/agg_curves.cpp", | ||||
|         "./src/agg_rounded_rect.cpp", | ||||
|         "./src/agg_vcgen_markers_term.cpp", | ||||
|         "./src/agg_vcgen_dash.cpp", | ||||
|         "./src/agg2d.cpp", | ||||
|         "./src/agg_trans_affine.cpp", | ||||
|         "./src/agg_gsv_text.cpp", | ||||
|         "./src/agg_vcgen_smooth_poly1.cpp", | ||||
|         "./src/agg_trans_single_path.cpp", | ||||
|         "./src/agg_vpgen_clip_polygon.cpp", | ||||
|         "./src/agg_embedded_raster_fonts.cpp", | ||||
|         "./src/agg_trans_double_path.cpp", | ||||
|         "./src/agg_vcgen_stroke.cpp", | ||||
|         "./src/agg_arc.cpp", | ||||
|         "./src/agg_image_filters.cpp", | ||||
|         "./src/agg_trans_warp_magnifier.cpp", | ||||
|         "./src/agg_vpgen_clip_polyline.cpp", | ||||
|         "./src/agg_bezier_arc.cpp", | ||||
|         "./src/agg_line_profile_aa.cpp", | ||||
|         "./src/agg_vcgen_contour.cpp", | ||||
|     ], | ||||
|     hdrs={ | ||||
|         "agg2d.h": "./include/agg2d.h", | ||||
|         "agg_alpha_mask_u8.h": "./include/agg_alpha_mask_u8.h", | ||||
|         "agg_arc.h": "./include/agg_arc.h", | ||||
|         "agg_array.h": "./include/agg_array.h", | ||||
|         "agg_arrowhead.h": "./include/agg_arrowhead.h", | ||||
|         "agg_basics.h": "./include/agg_basics.h", | ||||
|         "agg_bezier_arc.h": "./include/agg_bezier_arc.h", | ||||
|         "agg_bitset_iterator.h": "./include/agg_bitset_iterator.h", | ||||
|         "agg_blur.h": "./include/agg_blur.h", | ||||
|         "agg_bounding_rect.h": "./include/agg_bounding_rect.h", | ||||
|         "agg_bspline.h": "./include/agg_bspline.h", | ||||
|         "agg_clip_liang_barsky.h": "./include/agg_clip_liang_barsky.h", | ||||
|         "agg_color_gray.h": "./include/agg_color_gray.h", | ||||
|         "agg_color_rgba.h": "./include/agg_color_rgba.h", | ||||
|         "agg_config.h": "./include/agg_config.h", | ||||
|         "agg_conv_adaptor_vcgen.h": "./include/agg_conv_adaptor_vcgen.h", | ||||
|         "agg_conv_adaptor_vpgen.h": "./include/agg_conv_adaptor_vpgen.h", | ||||
|         "agg_conv_bspline.h": "./include/agg_conv_bspline.h", | ||||
|         "agg_conv_clip_polygon.h": "./include/agg_conv_clip_polygon.h", | ||||
|         "agg_conv_clip_polyline.h": "./include/agg_conv_clip_polyline.h", | ||||
|         "agg_conv_close_polygon.h": "./include/agg_conv_close_polygon.h", | ||||
|         "agg_conv_concat.h": "./include/agg_conv_concat.h", | ||||
|         "agg_conv_contour.h": "./include/agg_conv_contour.h", | ||||
|         "agg_conv_curve.h": "./include/agg_conv_curve.h", | ||||
|         "agg_conv_dash.h": "./include/agg_conv_dash.h", | ||||
|         "agg_conv_gpc.h": "./include/agg_conv_gpc.h", | ||||
|         "agg_conv_marker_adaptor.h": "./include/agg_conv_marker_adaptor.h", | ||||
|         "agg_conv_marker.h": "./include/agg_conv_marker.h", | ||||
|         "agg_conv_segmentator.h": "./include/agg_conv_segmentator.h", | ||||
|         "agg_conv_shorten_path.h": "./include/agg_conv_shorten_path.h", | ||||
|         "agg_conv_smooth_poly1.h": "./include/agg_conv_smooth_poly1.h", | ||||
|         "agg_conv_stroke.h": "./include/agg_conv_stroke.h", | ||||
|         "agg_conv_transform.h": "./include/agg_conv_transform.h", | ||||
|         "agg_conv_unclose_polygon.h": "./include/agg_conv_unclose_polygon.h", | ||||
|         "agg_curves.h": "./include/agg_curves.h", | ||||
|         "agg_dda_line.h": "./include/agg_dda_line.h", | ||||
|         "agg_ellipse_bresenham.h": "./include/agg_ellipse_bresenham.h", | ||||
|         "agg_ellipse.h": "./include/agg_ellipse.h", | ||||
|         "agg_embedded_raster_fonts.h": "./include/agg_embedded_raster_fonts.h", | ||||
|         "agg_font_cache_manager2.h": "./include/agg_font_cache_manager2.h", | ||||
|         "agg_font_cache_manager.h": "./include/agg_font_cache_manager.h", | ||||
|         "agg_gamma_functions.h": "./include/agg_gamma_functions.h", | ||||
|         "agg_gamma_lut.h": "./include/agg_gamma_lut.h", | ||||
|         "agg_glyph_raster_bin.h": "./include/agg_glyph_raster_bin.h", | ||||
|         "agg_gradient_lut.h": "./include/agg_gradient_lut.h", | ||||
|         "agg_gsv_text.h": "./include/agg_gsv_text.h", | ||||
|         "agg_image_accessors.h": "./include/agg_image_accessors.h", | ||||
|         "agg_image_filters.h": "./include/agg_image_filters.h", | ||||
|         "agg_line_aa_basics.h": "./include/agg_line_aa_basics.h", | ||||
|         "agg_math.h": "./include/agg_math.h", | ||||
|         "agg_math_stroke.h": "./include/agg_math_stroke.h", | ||||
|         "agg_path_length.h": "./include/agg_path_length.h", | ||||
|         "agg_path_storage.h": "./include/agg_path_storage.h", | ||||
|         "agg_path_storage_integer.h": "./include/agg_path_storage_integer.h", | ||||
|         "agg_pattern_filters_rgba.h": "./include/agg_pattern_filters_rgba.h", | ||||
|         "agg_pixfmt_amask_adaptor.h": "./include/agg_pixfmt_amask_adaptor.h", | ||||
|         "agg_pixfmt_base.h": "./include/agg_pixfmt_base.h", | ||||
|         "agg_pixfmt_gray.h": "./include/agg_pixfmt_gray.h", | ||||
|         "agg_pixfmt_rgba.h": "./include/agg_pixfmt_rgba.h", | ||||
|         "agg_pixfmt_rgb.h": "./include/agg_pixfmt_rgb.h", | ||||
|         "agg_pixfmt_rgb_packed.h": "./include/agg_pixfmt_rgb_packed.h", | ||||
|         "agg_pixfmt_transposer.h": "./include/agg_pixfmt_transposer.h", | ||||
|         "agg_rasterizer_cells_aa.h": "./include/agg_rasterizer_cells_aa.h", | ||||
|         "agg_rasterizer_compound_aa.h": "./include/agg_rasterizer_compound_aa.h", | ||||
|         "agg_rasterizer_outline_aa.h": "./include/agg_rasterizer_outline_aa.h", | ||||
|         "agg_rasterizer_outline.h": "./include/agg_rasterizer_outline.h", | ||||
|         "agg_rasterizer_scanline_aa.h": "./include/agg_rasterizer_scanline_aa.h", | ||||
|         "agg_rasterizer_scanline_aa_nogamma.h": "./include/agg_rasterizer_scanline_aa_nogamma.h", | ||||
|         "agg_rasterizer_sl_clip.h": "./include/agg_rasterizer_sl_clip.h", | ||||
|         "agg_renderer_base.h": "./include/agg_renderer_base.h", | ||||
|         "agg_renderer_markers.h": "./include/agg_renderer_markers.h", | ||||
|         "agg_renderer_mclip.h": "./include/agg_renderer_mclip.h", | ||||
|         "agg_renderer_outline_aa.h": "./include/agg_renderer_outline_aa.h", | ||||
|         "agg_renderer_outline_image.h": "./include/agg_renderer_outline_image.h", | ||||
|         "agg_renderer_primitives.h": "./include/agg_renderer_primitives.h", | ||||
|         "agg_renderer_raster_text.h": "./include/agg_renderer_raster_text.h", | ||||
|         "agg_renderer_scanline.h": "./include/agg_renderer_scanline.h", | ||||
|         "agg_rendering_buffer_dynarow.h": "./include/agg_rendering_buffer_dynarow.h", | ||||
|         "agg_rendering_buffer.h": "./include/agg_rendering_buffer.h", | ||||
|         "agg_rounded_rect.h": "./include/agg_rounded_rect.h", | ||||
|         "agg_scanline_bin.h": "./include/agg_scanline_bin.h", | ||||
|         "agg_scanline_boolean_algebra.h": "./include/agg_scanline_boolean_algebra.h", | ||||
|         "agg_scanline_p.h": "./include/agg_scanline_p.h", | ||||
|         "agg_scanline_storage_aa.h": "./include/agg_scanline_storage_aa.h", | ||||
|         "agg_scanline_storage_bin.h": "./include/agg_scanline_storage_bin.h", | ||||
|         "agg_scanline_u.h": "./include/agg_scanline_u.h", | ||||
|         "agg_shorten_path.h": "./include/agg_shorten_path.h", | ||||
|         "agg_simul_eq.h": "./include/agg_simul_eq.h", | ||||
|         "agg_span_allocator.h": "./include/agg_span_allocator.h", | ||||
|         "agg_span_converter.h": "./include/agg_span_converter.h", | ||||
|         "agg_span_gouraud_gray.h": "./include/agg_span_gouraud_gray.h", | ||||
|         "agg_span_gouraud.h": "./include/agg_span_gouraud.h", | ||||
|         "agg_span_gouraud_rgba.h": "./include/agg_span_gouraud_rgba.h", | ||||
|         "agg_span_gradient_alpha.h": "./include/agg_span_gradient_alpha.h", | ||||
|         "agg_span_gradient_contour.h": "./include/agg_span_gradient_contour.h", | ||||
|         "agg_span_gradient.h": "./include/agg_span_gradient.h", | ||||
|         "agg_span_gradient_image.h": "./include/agg_span_gradient_image.h", | ||||
|         "agg_span_image_filter_gray.h": "./include/agg_span_image_filter_gray.h", | ||||
|         "agg_span_image_filter.h": "./include/agg_span_image_filter.h", | ||||
|         "agg_span_image_filter_rgba.h": "./include/agg_span_image_filter_rgba.h", | ||||
|         "agg_span_image_filter_rgb.h": "./include/agg_span_image_filter_rgb.h", | ||||
|         "agg_span_interpolator_adaptor.h": "./include/agg_span_interpolator_adaptor.h", | ||||
|         "agg_span_interpolator_linear.h": "./include/agg_span_interpolator_linear.h", | ||||
|         "agg_span_interpolator_persp.h": "./include/agg_span_interpolator_persp.h", | ||||
|         "agg_span_interpolator_trans.h": "./include/agg_span_interpolator_trans.h", | ||||
|         "agg_span_pattern_gray.h": "./include/agg_span_pattern_gray.h", | ||||
|         "agg_span_pattern_rgba.h": "./include/agg_span_pattern_rgba.h", | ||||
|         "agg_span_pattern_rgb.h": "./include/agg_span_pattern_rgb.h", | ||||
|         "agg_span_solid.h": "./include/agg_span_solid.h", | ||||
|         "agg_span_subdiv_adaptor.h": "./include/agg_span_subdiv_adaptor.h", | ||||
|         "agg_trans_affine.h": "./include/agg_trans_affine.h", | ||||
|         "agg_trans_bilinear.h": "./include/agg_trans_bilinear.h", | ||||
|         "agg_trans_double_path.h": "./include/agg_trans_double_path.h", | ||||
|         "agg_trans_perspective.h": "./include/agg_trans_perspective.h", | ||||
|         "agg_trans_single_path.h": "./include/agg_trans_single_path.h", | ||||
|         "agg_trans_viewport.h": "./include/agg_trans_viewport.h", | ||||
|         "agg_trans_warp_magnifier.h": "./include/agg_trans_warp_magnifier.h", | ||||
|         "agg_vcgen_bspline.h": "./include/agg_vcgen_bspline.h", | ||||
|         "agg_vcgen_contour.h": "./include/agg_vcgen_contour.h", | ||||
|         "agg_vcgen_dash.h": "./include/agg_vcgen_dash.h", | ||||
|         "agg_vcgen_markers_term.h": "./include/agg_vcgen_markers_term.h", | ||||
|         "agg_vcgen_smooth_poly1.h": "./include/agg_vcgen_smooth_poly1.h", | ||||
|         "agg_vcgen_stroke.h": "./include/agg_vcgen_stroke.h", | ||||
|         "agg_vcgen_vertex_sequence.h": "./include/agg_vcgen_vertex_sequence.h", | ||||
|         "agg_vertex_sequence.h": "./include/agg_vertex_sequence.h", | ||||
|         "agg_vpgen_clip_polygon.h": "./include/agg_vpgen_clip_polygon.h", | ||||
|         "agg_vpgen_clip_polyline.h": "./include/agg_vpgen_clip_polyline.h", | ||||
|         "agg_vpgen_segmentator.h": "./include/agg_vpgen_segmentator.h", | ||||
|     }, | ||||
| ) | ||||
| @@ -1,21 +0,0 @@ | ||||
| ifeq ($(OS), Windows_NT) | ||||
|  | ||||
| EMU_SRCS = \ | ||||
| 	dep/emu/fnmatch.c | ||||
|  | ||||
| EMU_OBJS = $(patsubst %.c, $(OBJDIR)/%.o, $(EMU_SRCS)) | ||||
| $(EMU_OBJS): CFLAGS += -Idep/emu | ||||
| EMU_LIB = $(OBJDIR)/libemu.a | ||||
| $(EMU_LIB): $(EMU_OBJS) | ||||
| EMU_CFLAGS = -Idep/emu | ||||
| EMU_LDFLAGS = $(EMU_LIB) | ||||
| OBJS += $(EMU_OBJS) | ||||
|  | ||||
| else | ||||
|  | ||||
| EMU_LIB = | ||||
| EMU_CFLAGS = | ||||
| EMU_LDFLAGS = | ||||
|  | ||||
| endif | ||||
|  | ||||
							
								
								
									
										3
									
								
								dep/emu/build.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								dep/emu/build.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| from build.c import clibrary | ||||
|  | ||||
| clibrary(name="emu", srcs=["./fnmatch.c"], hdrs={"fnmatch.h": "./fnmatch.h"}) | ||||
| @@ -1,13 +0,0 @@ | ||||
| FATFS_SRCS = \ | ||||
| 	dep/fatfs/source/ff.c \ | ||||
| 	dep/fatfs/source/ffsystem.c \ | ||||
| 	dep/fatfs/source/ffunicode.c \ | ||||
| 	 | ||||
| FATFS_OBJS = $(patsubst %.c, $(OBJDIR)/%.o, $(FATFS_SRCS)) | ||||
| $(FATFS_OBJS): CFLAGS += -Idep/fatfs/source | ||||
| FATFS_LIB = $(OBJDIR)/libfatfs.a | ||||
| $(FATFS_LIB): $(FATFS_OBJS) | ||||
| FATFS_CFLAGS = -Idep/fatfs/source | ||||
| FATFS_LDFLAGS =  | ||||
| OBJS += $(FATFS_OBJS) | ||||
|  | ||||
							
								
								
									
										18
									
								
								dep/fatfs/build.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								dep/fatfs/build.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| from build.c import clibrary | ||||
|  | ||||
| clibrary( | ||||
|     name="fatfs", | ||||
|     srcs=[ | ||||
|         "./source/ff.c", | ||||
|         "./source/ffsystem.c", | ||||
|         "./source/ffunicode.c", | ||||
|         "./source/ff.h", | ||||
|         "./source/ffconf.h", | ||||
|         "./source/diskio.h", | ||||
|     ], | ||||
|     hdrs={ | ||||
|         "ff.h": "./source/ff.h", | ||||
|         "ffconf.h": "./source/ffconf.h", | ||||
|         "diskio.h": "./source/diskio.h", | ||||
|     }, | ||||
| ) | ||||
							
								
								
									
										8
									
								
								dep/fmt/.clang-format
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								dep/fmt/.clang-format
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| # Run manually to reformat a file: | ||||
| # clang-format -i --style=file <file> | ||||
| Language: Cpp | ||||
| BasedOnStyle: Google | ||||
| IndentPPDirectives: AfterHash | ||||
| IndentCaseLabels: false | ||||
| AlwaysBreakTemplateDeclarations: false | ||||
| DerivePointerAlignment: false | ||||
							
								
								
									
										453
									
								
								dep/fmt/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										453
									
								
								dep/fmt/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,453 @@ | ||||
| cmake_minimum_required(VERSION 3.8...3.26) | ||||
|  | ||||
| # Fallback for using newer policies on CMake <3.12. | ||||
| if (${CMAKE_VERSION} VERSION_LESS 3.12) | ||||
|   cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) | ||||
| endif () | ||||
|  | ||||
| # Determine if fmt is built as a subproject (using add_subdirectory) | ||||
| # or if it is the master project. | ||||
| if (NOT DEFINED FMT_MASTER_PROJECT) | ||||
|   set(FMT_MASTER_PROJECT OFF) | ||||
|   if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) | ||||
|     set(FMT_MASTER_PROJECT ON) | ||||
|     message(STATUS "CMake version: ${CMAKE_VERSION}") | ||||
|   endif () | ||||
| endif () | ||||
|  | ||||
| # Joins arguments and places the results in ${result_var}. | ||||
| function(join result_var) | ||||
|   set(result "") | ||||
|   foreach (arg ${ARGN}) | ||||
|     set(result "${result}${arg}") | ||||
|   endforeach () | ||||
|   set(${result_var} "${result}" PARENT_SCOPE) | ||||
| endfunction() | ||||
|  | ||||
| # DEPRECATED! Should be merged into add_module_library. | ||||
| function(enable_module target) | ||||
|   if (MSVC) | ||||
|     set(BMI ${CMAKE_CURRENT_BINARY_DIR}/${target}.ifc) | ||||
|     target_compile_options(${target} | ||||
|       PRIVATE /interface /ifcOutput ${BMI} | ||||
|       INTERFACE /reference fmt=${BMI}) | ||||
|     set_target_properties(${target} PROPERTIES ADDITIONAL_CLEAN_FILES ${BMI}) | ||||
|     set_source_files_properties(${BMI} PROPERTIES GENERATED ON) | ||||
|   endif () | ||||
| endfunction() | ||||
|  | ||||
| # Adds a library compiled with C++20 module support. | ||||
| # `enabled` is a CMake variables that specifies if modules are enabled. | ||||
| # If modules are disabled `add_module_library` falls back to creating a | ||||
| # non-modular library. | ||||
| # | ||||
| # Usage: | ||||
| #   add_module_library(<name> [sources...] FALLBACK [sources...] [IF enabled]) | ||||
| function(add_module_library name) | ||||
|   cmake_parse_arguments(AML "" "IF" "FALLBACK" ${ARGN}) | ||||
|   set(sources ${AML_UNPARSED_ARGUMENTS}) | ||||
|  | ||||
|   add_library(${name}) | ||||
|   set_target_properties(${name} PROPERTIES LINKER_LANGUAGE CXX) | ||||
|  | ||||
|   if (NOT ${${AML_IF}}) | ||||
|     # Create a non-modular library. | ||||
|     target_sources(${name} PRIVATE ${AML_FALLBACK}) | ||||
|     return() | ||||
|   endif () | ||||
|  | ||||
|   # Modules require C++20. | ||||
|   target_compile_features(${name} PUBLIC cxx_std_20) | ||||
|   if (CMAKE_COMPILER_IS_GNUCXX) | ||||
|     target_compile_options(${name} PUBLIC -fmodules-ts) | ||||
|   endif () | ||||
|  | ||||
|   # `std` is affected by CMake options and may be higher than C++20. | ||||
|   get_target_property(std ${name} CXX_STANDARD) | ||||
|  | ||||
|   if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") | ||||
|     set(pcms) | ||||
|     foreach (src ${sources}) | ||||
|       get_filename_component(pcm ${src} NAME_WE) | ||||
|       set(pcm ${pcm}.pcm) | ||||
|  | ||||
|       # Propagate -fmodule-file=*.pcm to targets that link with this library. | ||||
|       target_compile_options( | ||||
|         ${name} PUBLIC -fmodule-file=${CMAKE_CURRENT_BINARY_DIR}/${pcm}) | ||||
|  | ||||
|       # Use an absolute path to prevent target_link_libraries prepending -l | ||||
|       # to it. | ||||
|       set(pcms ${pcms} ${CMAKE_CURRENT_BINARY_DIR}/${pcm}) | ||||
|       add_custom_command( | ||||
|         OUTPUT ${pcm} | ||||
|         COMMAND ${CMAKE_CXX_COMPILER} | ||||
|                 -std=c++${std} -x c++-module --precompile -c | ||||
|                 -o ${pcm} ${CMAKE_CURRENT_SOURCE_DIR}/${src} | ||||
|                 "-I$<JOIN:$<TARGET_PROPERTY:${name},INCLUDE_DIRECTORIES>,;-I>" | ||||
|         # Required by the -I generator expression above. | ||||
|         COMMAND_EXPAND_LISTS | ||||
|         DEPENDS ${src}) | ||||
|     endforeach () | ||||
|  | ||||
|     # Add .pcm files as sources to make sure they are built before the library. | ||||
|     set(sources) | ||||
|     foreach (pcm ${pcms}) | ||||
|       get_filename_component(pcm_we ${pcm} NAME_WE) | ||||
|       set(obj ${pcm_we}.o) | ||||
|       # Use an absolute path to prevent target_link_libraries prepending -l. | ||||
|       set(sources ${sources} ${pcm} ${CMAKE_CURRENT_BINARY_DIR}/${obj}) | ||||
|       add_custom_command( | ||||
|         OUTPUT ${obj} | ||||
|         COMMAND ${CMAKE_CXX_COMPILER} $<TARGET_PROPERTY:${name},COMPILE_OPTIONS> | ||||
|                 -c -o ${obj} ${pcm} | ||||
|         DEPENDS ${pcm}) | ||||
|     endforeach () | ||||
|   endif () | ||||
|   target_sources(${name} PRIVATE ${sources}) | ||||
| endfunction() | ||||
|  | ||||
| include(CMakeParseArguments) | ||||
|  | ||||
| # Sets a cache variable with a docstring joined from multiple arguments: | ||||
| #   set(<variable> <value>... CACHE <type> <docstring>...) | ||||
| # This allows splitting a long docstring for readability. | ||||
| function(set_verbose) | ||||
|   # cmake_parse_arguments is broken in CMake 3.4 (cannot parse CACHE) so use | ||||
|   # list instead. | ||||
|   list(GET ARGN 0 var) | ||||
|   list(REMOVE_AT ARGN 0) | ||||
|   list(GET ARGN 0 val) | ||||
|   list(REMOVE_AT ARGN 0) | ||||
|   list(REMOVE_AT ARGN 0) | ||||
|   list(GET ARGN 0 type) | ||||
|   list(REMOVE_AT ARGN 0) | ||||
|   join(doc ${ARGN}) | ||||
|   set(${var} ${val} CACHE ${type} ${doc}) | ||||
| endfunction() | ||||
|  | ||||
| # Set the default CMAKE_BUILD_TYPE to Release. | ||||
| # This should be done before the project command since the latter can set | ||||
| # CMAKE_BUILD_TYPE itself (it does so for nmake). | ||||
| if (FMT_MASTER_PROJECT AND NOT CMAKE_BUILD_TYPE) | ||||
|   set_verbose(CMAKE_BUILD_TYPE Release CACHE STRING | ||||
|               "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or " | ||||
|               "CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.") | ||||
| endif () | ||||
|  | ||||
| project(FMT CXX) | ||||
| include(GNUInstallDirs) | ||||
| set_verbose(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE STRING | ||||
|             "Installation directory for include files, a relative path that " | ||||
|             "will be joined with ${CMAKE_INSTALL_PREFIX} or an absolute path.") | ||||
|  | ||||
| option(FMT_PEDANTIC "Enable extra warnings and expensive tests." OFF) | ||||
| option(FMT_WERROR "Halt the compilation with an error on compiler warnings." | ||||
|        OFF) | ||||
|  | ||||
| # Options that control generation of various targets. | ||||
| option(FMT_DOC "Generate the doc target." ${FMT_MASTER_PROJECT}) | ||||
| option(FMT_INSTALL "Generate the install target." ON) | ||||
| option(FMT_TEST "Generate the test target." ${FMT_MASTER_PROJECT}) | ||||
| option(FMT_FUZZ "Generate the fuzz target." OFF) | ||||
| option(FMT_CUDA_TEST "Generate the cuda-test target." OFF) | ||||
| option(FMT_OS "Include core requiring OS (Windows/Posix) " ON) | ||||
| option(FMT_MODULE "Build a module instead of a traditional library." OFF) | ||||
| option(FMT_SYSTEM_HEADERS "Expose headers with marking them as system." OFF) | ||||
|  | ||||
| if (FMT_TEST AND FMT_MODULE) | ||||
|   # The tests require {fmt} to be compiled as traditional library | ||||
|   message(STATUS "Testing is incompatible with build mode 'module'.") | ||||
| endif () | ||||
| set(FMT_SYSTEM_HEADERS_ATTRIBUTE "") | ||||
| if (FMT_SYSTEM_HEADERS) | ||||
|   set(FMT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM) | ||||
| endif () | ||||
| if (CMAKE_SYSTEM_NAME STREQUAL "MSDOS") | ||||
|   set(FMT_TEST OFF) | ||||
|   message(STATUS "MSDOS is incompatible with gtest") | ||||
| endif () | ||||
|  | ||||
| # Get version from core.h | ||||
| file(READ include/fmt/core.h core_h) | ||||
| if (NOT core_h MATCHES "FMT_VERSION ([0-9]+)([0-9][0-9])([0-9][0-9])") | ||||
|   message(FATAL_ERROR "Cannot get FMT_VERSION from core.h.") | ||||
| endif () | ||||
| # Use math to skip leading zeros if any. | ||||
| math(EXPR CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1}) | ||||
| math(EXPR CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2}) | ||||
| math(EXPR CPACK_PACKAGE_VERSION_PATCH ${CMAKE_MATCH_3}) | ||||
| join(FMT_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}. | ||||
|                  ${CPACK_PACKAGE_VERSION_PATCH}) | ||||
| message(STATUS "Version: ${FMT_VERSION}") | ||||
|  | ||||
| message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") | ||||
|  | ||||
| if (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY) | ||||
|   set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin) | ||||
| endif () | ||||
|  | ||||
| set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} | ||||
|   "${CMAKE_CURRENT_SOURCE_DIR}/support/cmake") | ||||
|  | ||||
| include(CheckCXXCompilerFlag) | ||||
| include(JoinPaths) | ||||
|  | ||||
| if (FMT_MASTER_PROJECT AND NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET) | ||||
|   set_verbose(CMAKE_CXX_VISIBILITY_PRESET hidden CACHE STRING | ||||
|               "Preset for the export of private symbols") | ||||
|   set_property(CACHE CMAKE_CXX_VISIBILITY_PRESET PROPERTY STRINGS | ||||
|                hidden default) | ||||
| endif () | ||||
|  | ||||
| if (FMT_MASTER_PROJECT AND NOT DEFINED CMAKE_VISIBILITY_INLINES_HIDDEN) | ||||
|   set_verbose(CMAKE_VISIBILITY_INLINES_HIDDEN ON CACHE BOOL | ||||
|               "Whether to add a compile flag to hide symbols of inline functions") | ||||
| endif () | ||||
|  | ||||
| if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") | ||||
|   set(PEDANTIC_COMPILE_FLAGS -pedantic-errors -Wall -Wextra -pedantic | ||||
|       -Wold-style-cast -Wundef | ||||
|       -Wredundant-decls -Wwrite-strings -Wpointer-arith | ||||
|       -Wcast-qual -Wformat=2 -Wmissing-include-dirs | ||||
|       -Wcast-align | ||||
|       -Wctor-dtor-privacy -Wdisabled-optimization | ||||
|       -Winvalid-pch -Woverloaded-virtual | ||||
|       -Wconversion -Wundef | ||||
|       -Wno-ctor-dtor-privacy -Wno-format-nonliteral) | ||||
|   if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6) | ||||
|       set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} | ||||
|          -Wno-dangling-else -Wno-unused-local-typedefs) | ||||
|   endif () | ||||
|   if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) | ||||
|       set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wdouble-promotion | ||||
|           -Wtrampolines -Wzero-as-null-pointer-constant -Wuseless-cast | ||||
|           -Wvector-operation-performance -Wsized-deallocation -Wshadow) | ||||
|   endif () | ||||
|   if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0) | ||||
|       set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wshift-overflow=2 | ||||
|           -Wnull-dereference -Wduplicated-cond) | ||||
|   endif () | ||||
|   set(WERROR_FLAG -Werror) | ||||
| endif () | ||||
|  | ||||
| if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") | ||||
|   set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -pedantic -Wconversion -Wundef | ||||
|       -Wdeprecated -Wweak-vtables -Wshadow | ||||
|       -Wno-gnu-zero-variadic-macro-arguments) | ||||
|   check_cxx_compiler_flag(-Wzero-as-null-pointer-constant HAS_NULLPTR_WARNING) | ||||
|   if (HAS_NULLPTR_WARNING) | ||||
|     set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} | ||||
|         -Wzero-as-null-pointer-constant) | ||||
|   endif () | ||||
|   set(WERROR_FLAG -Werror) | ||||
| endif () | ||||
|  | ||||
| if (MSVC) | ||||
|   set(PEDANTIC_COMPILE_FLAGS /W3) | ||||
|   set(WERROR_FLAG /WX) | ||||
| endif () | ||||
|  | ||||
| if (FMT_MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio") | ||||
|   # If Microsoft SDK is installed create script run-msbuild.bat that | ||||
|   # calls SetEnv.cmd to set up build environment and runs msbuild. | ||||
|   # It is useful when building Visual Studio projects with the SDK | ||||
|   # toolchain rather than Visual Studio. | ||||
|   include(FindSetEnv) | ||||
|   if (WINSDK_SETENV) | ||||
|     set(MSBUILD_SETUP "call \"${WINSDK_SETENV}\"") | ||||
|   endif () | ||||
|   # Set FrameworkPathOverride to get rid of MSB3644 warnings. | ||||
|   join(netfxpath | ||||
|        "C:\\Program Files\\Reference Assemblies\\Microsoft\\Framework\\" | ||||
|        ".NETFramework\\v4.0") | ||||
|   file(WRITE run-msbuild.bat " | ||||
|     ${MSBUILD_SETUP} | ||||
|     ${CMAKE_MAKE_PROGRAM} -p:FrameworkPathOverride=\"${netfxpath}\" %*") | ||||
| endif () | ||||
|  | ||||
| function(add_headers VAR) | ||||
|   set(headers ${${VAR}}) | ||||
|   foreach (header ${ARGN}) | ||||
|     set(headers ${headers} include/fmt/${header}) | ||||
|   endforeach() | ||||
|   set(${VAR} ${headers} PARENT_SCOPE) | ||||
| endfunction() | ||||
|  | ||||
| # Define the fmt library, its includes and the needed defines. | ||||
| add_headers(FMT_HEADERS args.h chrono.h color.h compile.h core.h format.h | ||||
|                         format-inl.h os.h ostream.h printf.h ranges.h std.h | ||||
|                         xchar.h) | ||||
| set(FMT_SOURCES src/format.cc) | ||||
| if (FMT_OS) | ||||
|   set(FMT_SOURCES ${FMT_SOURCES} src/os.cc) | ||||
| endif () | ||||
|  | ||||
| add_module_library(fmt src/fmt.cc FALLBACK | ||||
|                    ${FMT_SOURCES} ${FMT_HEADERS} README.md ChangeLog.md | ||||
|                    IF FMT_MODULE) | ||||
| add_library(fmt::fmt ALIAS fmt) | ||||
| if (FMT_MODULE) | ||||
|   enable_module(fmt) | ||||
| endif () | ||||
|  | ||||
| if (FMT_WERROR) | ||||
|   target_compile_options(fmt PRIVATE ${WERROR_FLAG}) | ||||
| endif () | ||||
| if (FMT_PEDANTIC) | ||||
|   target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS}) | ||||
| endif () | ||||
|  | ||||
| if (cxx_std_11 IN_LIST CMAKE_CXX_COMPILE_FEATURES) | ||||
|   target_compile_features(fmt PUBLIC cxx_std_11) | ||||
| else () | ||||
|   message(WARNING "Feature cxx_std_11 is unknown for the CXX compiler") | ||||
| endif () | ||||
|  | ||||
| target_include_directories(fmt ${FMT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC | ||||
|   $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include> | ||||
|   $<INSTALL_INTERFACE:${FMT_INC_DIR}>) | ||||
|  | ||||
| set(FMT_DEBUG_POSTFIX d CACHE STRING "Debug library postfix.") | ||||
|  | ||||
| set_target_properties(fmt PROPERTIES | ||||
|   VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR} | ||||
|   PUBLIC_HEADER "${FMT_HEADERS}" | ||||
|   DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX}" | ||||
|  | ||||
|   # Workaround for Visual Studio 2017: | ||||
|   # Ensure the .pdb is created with the same name and in the same directory | ||||
|   # as the .lib. Newer VS versions already do this by default, but there is no | ||||
|   # harm in setting it for those too. Ignored by other generators. | ||||
|   COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" | ||||
|   COMPILE_PDB_NAME "fmt" | ||||
|   COMPILE_PDB_NAME_DEBUG "fmt${FMT_DEBUG_POSTFIX}") | ||||
|  | ||||
| # Set FMT_LIB_NAME for pkg-config fmt.pc. We cannot use the OUTPUT_NAME target | ||||
| # property because it's not set by default. | ||||
| set(FMT_LIB_NAME fmt) | ||||
| if (CMAKE_BUILD_TYPE STREQUAL "Debug") | ||||
|   set(FMT_LIB_NAME ${FMT_LIB_NAME}${FMT_DEBUG_POSTFIX}) | ||||
| endif () | ||||
|  | ||||
| if (BUILD_SHARED_LIBS) | ||||
|   target_compile_definitions(fmt PRIVATE FMT_LIB_EXPORT INTERFACE FMT_SHARED) | ||||
| endif () | ||||
| if (FMT_SAFE_DURATION_CAST) | ||||
|   target_compile_definitions(fmt PUBLIC FMT_SAFE_DURATION_CAST) | ||||
| endif () | ||||
|  | ||||
| add_library(fmt-header-only INTERFACE) | ||||
| add_library(fmt::fmt-header-only ALIAS fmt-header-only) | ||||
|  | ||||
| target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1) | ||||
| target_compile_features(fmt-header-only INTERFACE cxx_std_11) | ||||
|  | ||||
| target_include_directories(fmt-header-only | ||||
|   ${FMT_SYSTEM_HEADERS_ATTRIBUTE} INTERFACE | ||||
|   $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include> | ||||
|   $<INSTALL_INTERFACE:${FMT_INC_DIR}>) | ||||
|  | ||||
| # Install targets. | ||||
| if (FMT_INSTALL) | ||||
|   include(CMakePackageConfigHelpers) | ||||
|   set_verbose(FMT_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/fmt CACHE STRING | ||||
|               "Installation directory for cmake files, a relative path that " | ||||
|               "will be joined with ${CMAKE_INSTALL_PREFIX} or an absolute " | ||||
|               "path.") | ||||
|   set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake) | ||||
|   set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake) | ||||
|   set(pkgconfig ${PROJECT_BINARY_DIR}/fmt.pc) | ||||
|   set(targets_export_name fmt-targets) | ||||
|  | ||||
|   set_verbose(FMT_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING | ||||
|               "Installation directory for libraries, a relative path that " | ||||
|               "will be joined to ${CMAKE_INSTALL_PREFIX} or an absolute path.") | ||||
|  | ||||
|   set_verbose(FMT_PKGCONFIG_DIR ${CMAKE_INSTALL_LIBDIR}/pkgconfig CACHE STRING | ||||
|               "Installation directory for pkgconfig (.pc) files, a relative " | ||||
|               "path that will be joined with ${CMAKE_INSTALL_PREFIX} or an " | ||||
|               "absolute path.") | ||||
|  | ||||
|   # Generate the version, config and target files into the build directory. | ||||
|   write_basic_package_version_file( | ||||
|     ${version_config} | ||||
|     VERSION ${FMT_VERSION} | ||||
|     COMPATIBILITY AnyNewerVersion) | ||||
|  | ||||
|   join_paths(libdir_for_pc_file "\${exec_prefix}" "${FMT_LIB_DIR}") | ||||
|   join_paths(includedir_for_pc_file "\${prefix}" "${FMT_INC_DIR}") | ||||
|  | ||||
|   configure_file( | ||||
|     "${PROJECT_SOURCE_DIR}/support/cmake/fmt.pc.in" | ||||
|     "${pkgconfig}" | ||||
|     @ONLY) | ||||
|   configure_package_config_file( | ||||
|     ${PROJECT_SOURCE_DIR}/support/cmake/fmt-config.cmake.in | ||||
|     ${project_config} | ||||
|     INSTALL_DESTINATION ${FMT_CMAKE_DIR}) | ||||
|  | ||||
|   set(INSTALL_TARGETS fmt fmt-header-only) | ||||
|  | ||||
|   # Install the library and headers. | ||||
|   install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name} | ||||
|           LIBRARY DESTINATION ${FMT_LIB_DIR} | ||||
|           ARCHIVE DESTINATION ${FMT_LIB_DIR} | ||||
|           PUBLIC_HEADER DESTINATION "${FMT_INC_DIR}/fmt" | ||||
|           RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) | ||||
|  | ||||
|   # Use a namespace because CMake provides better diagnostics for namespaced | ||||
|   # imported targets. | ||||
|   export(TARGETS ${INSTALL_TARGETS} NAMESPACE fmt:: | ||||
|          FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake) | ||||
|  | ||||
|   # Install version, config and target files. | ||||
|   install( | ||||
|     FILES ${project_config} ${version_config} | ||||
|     DESTINATION ${FMT_CMAKE_DIR}) | ||||
|   install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR} | ||||
|           NAMESPACE fmt::) | ||||
|  | ||||
|   install(FILES "${pkgconfig}" DESTINATION "${FMT_PKGCONFIG_DIR}") | ||||
| endif () | ||||
|  | ||||
| if (FMT_DOC) | ||||
|   add_subdirectory(doc) | ||||
| endif () | ||||
|  | ||||
| if (FMT_TEST) | ||||
|   enable_testing() | ||||
|   add_subdirectory(test) | ||||
| endif () | ||||
|  | ||||
| # Control fuzzing independent of the unit tests. | ||||
| if (FMT_FUZZ) | ||||
|   add_subdirectory(test/fuzzing) | ||||
|  | ||||
|   # The FMT_FUZZ macro is used to prevent resource exhaustion in fuzzing | ||||
|   # mode and make fuzzing practically possible. It is similar to | ||||
|   # FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION but uses a different name to | ||||
|   # avoid interfering with fuzzing of projects that use {fmt}. | ||||
|   # See also https://llvm.org/docs/LibFuzzer.html#fuzzer-friendly-build-mode. | ||||
|   target_compile_definitions(fmt PUBLIC FMT_FUZZ) | ||||
| endif () | ||||
|  | ||||
| set(gitignore ${PROJECT_SOURCE_DIR}/.gitignore) | ||||
| if (FMT_MASTER_PROJECT AND EXISTS ${gitignore}) | ||||
|   # Get the list of ignored files from .gitignore. | ||||
|   file (STRINGS ${gitignore} lines) | ||||
|   list(REMOVE_ITEM lines /doc/html) | ||||
|   foreach (line ${lines}) | ||||
|     string(REPLACE "." "[.]" line "${line}") | ||||
|     string(REPLACE "*" ".*" line "${line}") | ||||
|     set(ignored_files ${ignored_files} "${line}$" "${line}/") | ||||
|   endforeach () | ||||
|   set(ignored_files ${ignored_files} | ||||
|     /.git /breathe /format-benchmark sphinx/ .buildinfo .doctrees) | ||||
|  | ||||
|   set(CPACK_SOURCE_GENERATOR ZIP) | ||||
|   set(CPACK_SOURCE_IGNORE_FILES ${ignored_files}) | ||||
|   set(CPACK_SOURCE_PACKAGE_FILE_NAME fmt-${FMT_VERSION}) | ||||
|   set(CPACK_PACKAGE_NAME fmt) | ||||
|   set(CPACK_RESOURCE_FILE_README ${PROJECT_SOURCE_DIR}/README.md) | ||||
|   include(CPack) | ||||
| endif () | ||||
							
								
								
									
										20
									
								
								dep/fmt/CONTRIBUTING.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								dep/fmt/CONTRIBUTING.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| Contributing to {fmt} | ||||
| ===================== | ||||
|  | ||||
| By submitting a pull request or a patch, you represent that you have the right | ||||
| to license your contribution to the {fmt} project owners and the community, | ||||
| agree that your contributions are licensed under the {fmt} license, and agree | ||||
| to future changes to the licensing. | ||||
|  | ||||
| All C++ code must adhere to [Google C++ Style Guide]( | ||||
| https://google.github.io/styleguide/cppguide.html) with the following | ||||
| exceptions: | ||||
|  | ||||
| * Exceptions are permitted | ||||
| * snake_case should be used instead of UpperCamelCase for function and type | ||||
|   names | ||||
|  | ||||
| All documentation must adhere to the [Google Developer Documentation Style | ||||
| Guide](https://developers.google.com/style). | ||||
|  | ||||
| Thanks for contributing! | ||||
							
								
								
									
										5533
									
								
								dep/fmt/ChangeLog.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5533
									
								
								dep/fmt/ChangeLog.md
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										27
									
								
								dep/fmt/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								dep/fmt/LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors | ||||
|  | ||||
| Permission is hereby granted, free of charge, to any person obtaining | ||||
| a copy of this software and associated documentation files (the | ||||
| "Software"), to deal in the Software without restriction, including | ||||
| without limitation the rights to use, copy, modify, merge, publish, | ||||
| distribute, sublicense, and/or sell copies of the Software, and to | ||||
| permit persons to whom the Software is furnished to do so, subject to | ||||
| the following conditions: | ||||
|  | ||||
| The above copyright notice and this permission notice shall be | ||||
| included in all copies or substantial portions of the Software. | ||||
|  | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||||
| NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||||
| LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||||
| OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||||
| WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
|  | ||||
| --- Optional exception to the license --- | ||||
|  | ||||
| As an exception, if, as a result of your compiling your source code, portions | ||||
| of this Software are embedded into a machine-executable object form of such | ||||
| source code, you may redistribute such embedded portions in such object form | ||||
| without including the above copyright and permission notices. | ||||
							
								
								
									
										490
									
								
								dep/fmt/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										490
									
								
								dep/fmt/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,490 @@ | ||||
| <img src="https://user-images.githubusercontent.com/576385/156254208-f5b743a9-88cf-439d-b0c0-923d53e8d551.png" alt="{fmt}" width="25%"/> | ||||
|  | ||||
| [](https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux) | ||||
| [](https://github.com/fmtlib/fmt/actions?query=workflow%3Amacos) | ||||
| [](https://github.com/fmtlib/fmt/actions?query=workflow%3Awindows) | ||||
| [](https://bugs.chromium.org/p/oss-fuzz/issues/list?\%0Acolspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20\%0ASummary&q=proj%3Dfmt&can=1) | ||||
| [](https://stackoverflow.com/questions/tagged/fmt) | ||||
| [](https://securityscorecards.dev/viewer/?uri=github.com/fmtlib/fmt) | ||||
|  | ||||
| **{fmt}** is an open-source formatting library providing a fast and safe | ||||
| alternative to C stdio and C++ iostreams. | ||||
|  | ||||
| If you like this project, please consider donating to one of the funds | ||||
| that help victims of the war in Ukraine: <https://www.stopputin.net/>. | ||||
|  | ||||
| [Documentation](https://fmt.dev) | ||||
|  | ||||
| [Cheat Sheets](https://hackingcpp.com/cpp/libs/fmt.html) | ||||
|  | ||||
| Q&A: ask questions on [StackOverflow with the tag | ||||
| fmt](https://stackoverflow.com/questions/tagged/fmt). | ||||
|  | ||||
| Try {fmt} in [Compiler Explorer](https://godbolt.org/z/Eq5763). | ||||
|  | ||||
| # Features | ||||
|  | ||||
| - Simple [format API](https://fmt.dev/latest/api.html) with positional | ||||
|   arguments for localization | ||||
| - Implementation of [C++20 | ||||
|   std::format](https://en.cppreference.com/w/cpp/utility/format) and | ||||
|   [C++23 std::print](https://en.cppreference.com/w/cpp/io/print) | ||||
| - [Format string syntax](https://fmt.dev/latest/syntax.html) similar | ||||
|   to Python\'s | ||||
|   [format](https://docs.python.org/3/library/stdtypes.html#str.format) | ||||
| - Fast IEEE 754 floating-point formatter with correct rounding, | ||||
|   shortness and round-trip guarantees using the | ||||
|   [Dragonbox](https://github.com/jk-jeon/dragonbox) algorithm | ||||
| - Portable Unicode support | ||||
| - Safe [printf | ||||
|   implementation](https://fmt.dev/latest/api.html#printf-formatting) | ||||
|   including the POSIX extension for positional arguments | ||||
| - Extensibility: [support for user-defined | ||||
|   types](https://fmt.dev/latest/api.html#formatting-user-defined-types) | ||||
| - High performance: faster than common standard library | ||||
|   implementations of `(s)printf`, iostreams, `to_string` and | ||||
|   `to_chars`, see [Speed tests](#speed-tests) and [Converting a | ||||
|   hundred million integers to strings per | ||||
|   second](http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html) | ||||
| - Small code size both in terms of source code with the minimum | ||||
|   configuration consisting of just three files, `core.h`, `format.h` | ||||
|   and `format-inl.h`, and compiled code; see [Compile time and code | ||||
|   bloat](#compile-time-and-code-bloat) | ||||
| - Reliability: the library has an extensive set of | ||||
|   [tests](https://github.com/fmtlib/fmt/tree/master/test) and is | ||||
|   [continuously fuzzed](https://bugs.chromium.org/p/oss-fuzz/issues/list?colspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20Summary&q=proj%3Dfmt&can=1) | ||||
| - Safety: the library is fully type-safe, errors in format strings can | ||||
|   be reported at compile time, automatic memory management prevents | ||||
|   buffer overflow errors | ||||
| - Ease of use: small self-contained code base, no external | ||||
|   dependencies, permissive MIT | ||||
|   [license](https://github.com/fmtlib/fmt/blob/master/LICENSE.rst) | ||||
| - [Portability](https://fmt.dev/latest/index.html#portability) with | ||||
|   consistent output across platforms and support for older compilers | ||||
| - Clean warning-free codebase even on high warning levels such as | ||||
|   `-Wall -Wextra -pedantic` | ||||
| - Locale independence by default | ||||
| - Optional header-only configuration enabled with the | ||||
|   `FMT_HEADER_ONLY` macro | ||||
|  | ||||
| See the [documentation](https://fmt.dev) for more details. | ||||
|  | ||||
| # Examples | ||||
|  | ||||
| **Print to stdout** ([run](https://godbolt.org/z/Tevcjh)) | ||||
|  | ||||
| ``` c++ | ||||
| #include <fmt/core.h> | ||||
|  | ||||
| int main() { | ||||
|   fmt::print("Hello, world!\n"); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| **Format a string** ([run](https://godbolt.org/z/oK8h33)) | ||||
|  | ||||
| ``` c++ | ||||
| std::string s = fmt::format("The answer is {}.", 42); | ||||
| // s == "The answer is 42." | ||||
| ``` | ||||
|  | ||||
| **Format a string using positional arguments** | ||||
| ([run](https://godbolt.org/z/Yn7Txe)) | ||||
|  | ||||
| ``` c++ | ||||
| std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy"); | ||||
| // s == "I'd rather be happy than right." | ||||
| ``` | ||||
|  | ||||
| **Print dates and times** ([run](https://godbolt.org/z/c31ExdY3W)) | ||||
|  | ||||
| ``` c++ | ||||
| #include <fmt/chrono.h> | ||||
|  | ||||
| int main() { | ||||
|   auto now = std::chrono::system_clock::now(); | ||||
|   fmt::print("Date and time: {}\n", now); | ||||
|   fmt::print("Time: {:%H:%M}\n", now); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Output: | ||||
|  | ||||
|     Date and time: 2023-12-26 19:10:31.557195597 | ||||
|     Time: 19:10 | ||||
|  | ||||
| **Print a container** ([run](https://godbolt.org/z/MxM1YqjE7)) | ||||
|  | ||||
| ``` c++ | ||||
| #include <vector> | ||||
| #include <fmt/ranges.h> | ||||
|  | ||||
| int main() { | ||||
|   std::vector<int> v = {1, 2, 3}; | ||||
|   fmt::print("{}\n", v); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Output: | ||||
|  | ||||
|     [1, 2, 3] | ||||
|  | ||||
| **Check a format string at compile time** | ||||
|  | ||||
| ``` c++ | ||||
| std::string s = fmt::format("{:d}", "I am not a number"); | ||||
| ``` | ||||
|  | ||||
| This gives a compile-time error in C++20 because `d` is an invalid | ||||
| format specifier for a string. | ||||
|  | ||||
| **Write a file from a single thread** | ||||
|  | ||||
| ``` c++ | ||||
| #include <fmt/os.h> | ||||
|  | ||||
| int main() { | ||||
|   auto out = fmt::output_file("guide.txt"); | ||||
|   out.print("Don't {}", "Panic"); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| This can be [5 to 9 times faster than | ||||
| fprintf](http://www.zverovich.net/2020/08/04/optimal-file-buffer-size.html). | ||||
|  | ||||
| **Print with colors and text styles** | ||||
|  | ||||
| ``` c++ | ||||
| #include <fmt/color.h> | ||||
|  | ||||
| int main() { | ||||
|   fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold, | ||||
|              "Hello, {}!\n", "world"); | ||||
|   fmt::print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) | | ||||
|              fmt::emphasis::underline, "Olá, {}!\n", "Mundo"); | ||||
|   fmt::print(fg(fmt::color::steel_blue) | fmt::emphasis::italic, | ||||
|              "你好{}!\n", "世界"); | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Output on a modern terminal with Unicode support: | ||||
|  | ||||
|  | ||||
|  | ||||
| # Benchmarks | ||||
|  | ||||
| ## Speed tests | ||||
|  | ||||
| | Library           | Method        | Run Time, s | | ||||
| |-------------------|---------------|-------------| | ||||
| | libc              | printf        |   0.91      | | ||||
| | libc++            | std::ostream  |   2.49      | | ||||
| | {fmt} 9.1         | fmt::print    |   0.74      | | ||||
| | Boost Format 1.80 | boost::format |   6.26      | | ||||
| | Folly Format      | folly::format |   1.87      | | ||||
|  | ||||
| {fmt} is the fastest of the benchmarked methods, \~20% faster than | ||||
| `printf`. | ||||
|  | ||||
| The above results were generated by building `tinyformat_test.cpp` on | ||||
| macOS 12.6.1 with `clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT`, and | ||||
| taking the best of three runs. In the test, the format string | ||||
| `"%0.10f:%04d:%+g:%s:%p:%c:%%\n"` or equivalent is filled 2,000,000 | ||||
| times with output sent to `/dev/null`; for further details refer to the | ||||
| [source](https://github.com/fmtlib/format-benchmark/blob/master/src/tinyformat-test.cc). | ||||
|  | ||||
| {fmt} is up to 20-30x faster than `std::ostringstream` and `sprintf` on | ||||
| IEEE754 `float` and `double` formatting | ||||
| ([dtoa-benchmark](https://github.com/fmtlib/dtoa-benchmark)) and faster | ||||
| than [double-conversion](https://github.com/google/double-conversion) | ||||
| and [ryu](https://github.com/ulfjack/ryu): | ||||
|  | ||||
| [](https://fmt.dev/unknown_mac64_clang12.0.html) | ||||
|  | ||||
| ## Compile time and code bloat | ||||
|  | ||||
| The script | ||||
| [bloat-test.py](https://github.com/fmtlib/format-benchmark/blob/master/bloat-test.py) | ||||
| from [format-benchmark](https://github.com/fmtlib/format-benchmark) | ||||
| tests compile time and code bloat for nontrivial projects. It generates | ||||
| 100 translation units and uses `printf()` or its alternative five times | ||||
| in each to simulate a medium-sized project. The resulting executable | ||||
| size and compile time (Apple LLVM version 8.1.0 (clang-802.0.42), macOS | ||||
| Sierra, best of three) is shown in the following tables. | ||||
|  | ||||
| **Optimized build (-O3)** | ||||
|  | ||||
| | Method        | Compile Time, s | Executable size, KiB | Stripped size, KiB | | ||||
| |---------------|-----------------|----------------------|--------------------| | ||||
| | printf        |   2.6           |   29                 |   26               | | ||||
| | printf+string |   16.4          |   29                 |   26               | | ||||
| | iostreams     |   31.1          |   59                 |   55               | | ||||
| | {fmt}         |   19.0          |   37                 |   34               | | ||||
| | Boost Format  |   91.9          |   226                |   203              | | ||||
| | Folly Format  |   115.7         |   101                |   88               | | ||||
|  | ||||
| As you can see, {fmt} has 60% less overhead in terms of resulting binary | ||||
| code size compared to iostreams and comes pretty close to `printf`. | ||||
| Boost Format and Folly Format have the largest overheads. | ||||
|  | ||||
| `printf+string` is the same as `printf` but with an extra `<string>` | ||||
| include to measure the overhead of the latter. | ||||
|  | ||||
| **Non-optimized build** | ||||
|  | ||||
| | Method        | Compile Time, s | Executable size, KiB | Stripped size, KiB | | ||||
| |---------------|-----------------|----------------------|--------------------| | ||||
| | printf        |   2.2           |   33                 |   30               | | ||||
| | printf+string |   16.0          |   33                 |   30               | | ||||
| | iostreams     |   28.3          |   56                 |   52               | | ||||
| | {fmt}         |   18.2          |   59                 |   50               | | ||||
| | Boost Format  |   54.1          |   365                |   303              | | ||||
| | Folly Format  |   79.9          |   445                |   430              | | ||||
|  | ||||
| `libc`, `lib(std)c++`, and `libfmt` are all linked as shared libraries | ||||
| to compare formatting function overhead only. Boost Format is a | ||||
| header-only library so it doesn\'t provide any linkage options. | ||||
|  | ||||
| ## Running the tests | ||||
|  | ||||
| Please refer to [Building the | ||||
| library](https://fmt.dev/latest/usage.html#building-the-library) for | ||||
| instructions on how to build the library and run the unit tests. | ||||
|  | ||||
| Benchmarks reside in a separate repository, | ||||
| [format-benchmarks](https://github.com/fmtlib/format-benchmark), so to | ||||
| run the benchmarks you first need to clone this repository and generate | ||||
| Makefiles with CMake: | ||||
|  | ||||
|     $ git clone --recursive https://github.com/fmtlib/format-benchmark.git | ||||
|     $ cd format-benchmark | ||||
|     $ cmake . | ||||
|  | ||||
| Then you can run the speed test: | ||||
|  | ||||
|     $ make speed-test | ||||
|  | ||||
| or the bloat test: | ||||
|  | ||||
|     $ make bloat-test | ||||
|  | ||||
| # Migrating code | ||||
|  | ||||
| [clang-tidy](https://clang.llvm.org/extra/clang-tidy/) v17 (not yet | ||||
| released) provides the | ||||
| [modernize-use-std-print](https://clang.llvm.org/extra/clang-tidy/checks/modernize/use-std-print.html) | ||||
| check that is capable of converting occurrences of `printf` and | ||||
| `fprintf` to `fmt::print` if configured to do so. (By default it | ||||
| converts to `std::print`.) | ||||
|  | ||||
| # Notable projects using this library | ||||
|  | ||||
| - [0 A.D.](https://play0ad.com/): a free, open-source, cross-platform | ||||
|   real-time strategy game | ||||
| - [AMPL/MP](https://github.com/ampl/mp): an open-source library for | ||||
|   mathematical programming | ||||
| - [Apple's FoundationDB](https://github.com/apple/foundationdb): an open-source, | ||||
|   distributed, transactional key-value store | ||||
| - [Aseprite](https://github.com/aseprite/aseprite): animated sprite | ||||
|   editor & pixel art tool | ||||
| - [AvioBook](https://www.aviobook.aero/en): a comprehensive aircraft | ||||
|   operations suite | ||||
| - [Blizzard Battle.net](https://battle.net/): an online gaming | ||||
|   platform | ||||
| - [Celestia](https://celestia.space/): real-time 3D visualization of | ||||
|   space | ||||
| - [Ceph](https://ceph.com/): a scalable distributed storage system | ||||
| - [ccache](https://ccache.dev/): a compiler cache | ||||
| - [ClickHouse](https://github.com/ClickHouse/ClickHouse): an | ||||
|   analytical database management system | ||||
| - [Contour](https://github.com/contour-terminal/contour/): a modern | ||||
|   terminal emulator | ||||
| - [CUAUV](https://cuauv.org/): Cornell University\'s autonomous | ||||
|   underwater vehicle | ||||
| - [Drake](https://drake.mit.edu/): a planning, control, and analysis | ||||
|   toolbox for nonlinear dynamical systems (MIT) | ||||
| - [Envoy](https://lyft.github.io/envoy/): C++ L7 proxy and | ||||
|   communication bus (Lyft) | ||||
| - [FiveM](https://fivem.net/): a modification framework for GTA V | ||||
| - [fmtlog](https://github.com/MengRao/fmtlog): a performant | ||||
|   fmtlib-style logging library with latency in nanoseconds | ||||
| - [Folly](https://github.com/facebook/folly): Facebook open-source | ||||
|   library | ||||
| - [GemRB](https://gemrb.org/): a portable open-source implementation | ||||
|   of Bioware's Infinity Engine | ||||
| - [Grand Mountain | ||||
|   Adventure](https://store.steampowered.com/app/1247360/Grand_Mountain_Adventure/): | ||||
|   a beautiful open-world ski & snowboarding game | ||||
| - [HarpyWar/pvpgn](https://github.com/pvpgn/pvpgn-server): Player vs | ||||
|   Player Gaming Network with tweaks | ||||
| - [KBEngine](https://github.com/kbengine/kbengine): an open-source | ||||
|   MMOG server engine | ||||
| - [Keypirinha](https://keypirinha.com/): a semantic launcher for | ||||
|   Windows | ||||
| - [Kodi](https://kodi.tv/) (formerly xbmc): home theater software | ||||
| - [Knuth](https://kth.cash/): high-performance Bitcoin full-node | ||||
| - [libunicode](https://github.com/contour-terminal/libunicode/): a | ||||
|   modern C++17 Unicode library | ||||
| - [MariaDB](https://mariadb.org/): relational database management | ||||
|   system | ||||
| - [Microsoft Verona](https://github.com/microsoft/verona): research | ||||
|   programming language for concurrent ownership | ||||
| - [MongoDB](https://mongodb.com/): distributed document database | ||||
| - [MongoDB Smasher](https://github.com/duckie/mongo_smasher): a small | ||||
|   tool to generate randomized datasets | ||||
| - [OpenSpace](https://openspaceproject.com/): an open-source | ||||
|   astrovisualization framework | ||||
| - [PenUltima Online (POL)](https://www.polserver.com/): an MMO server, | ||||
|   compatible with most Ultima Online clients | ||||
| - [PyTorch](https://github.com/pytorch/pytorch): an open-source | ||||
|   machine learning library | ||||
| - [quasardb](https://www.quasardb.net/): a distributed, | ||||
|   high-performance, associative database | ||||
| - [Quill](https://github.com/odygrd/quill): asynchronous low-latency | ||||
|   logging library | ||||
| - [QKW](https://github.com/ravijanjam/qkw): generalizing aliasing to | ||||
|   simplify navigation, and executing complex multi-line terminal | ||||
|   command sequences | ||||
| - [redis-cerberus](https://github.com/HunanTV/redis-cerberus): a Redis | ||||
|   cluster proxy | ||||
| - [redpanda](https://vectorized.io/redpanda): a 10x faster Kafka® | ||||
|   replacement for mission-critical systems written in C++ | ||||
| - [rpclib](http://rpclib.net/): a modern C++ msgpack-RPC server and | ||||
|   client library | ||||
| - [Salesforce Analytics | ||||
|   Cloud](https://www.salesforce.com/analytics-cloud/overview/): | ||||
|   business intelligence software | ||||
| - [Scylla](https://www.scylladb.com/): a Cassandra-compatible NoSQL | ||||
|   data store that can handle 1 million transactions per second on a | ||||
|   single server | ||||
| - [Seastar](http://www.seastar-project.org/): an advanced, open-source | ||||
|   C++ framework for high-performance server applications on modern | ||||
|   hardware | ||||
| - [spdlog](https://github.com/gabime/spdlog): super fast C++ logging | ||||
|   library | ||||
| - [Stellar](https://www.stellar.org/): financial platform | ||||
| - [Touch Surgery](https://www.touchsurgery.com/): surgery simulator | ||||
| - [TrinityCore](https://github.com/TrinityCore/TrinityCore): | ||||
|   open-source MMORPG framework | ||||
| - [🐙 userver framework](https://userver.tech/): open-source | ||||
|   asynchronous framework with a rich set of abstractions and database | ||||
|   drivers | ||||
| - [Windows Terminal](https://github.com/microsoft/terminal): the new | ||||
|   Windows terminal | ||||
|  | ||||
| [More\...](https://github.com/search?q=fmtlib&type=Code) | ||||
|  | ||||
| If you are aware of other projects using this library, please let me | ||||
| know by [email](mailto:victor.zverovich@gmail.com) or by submitting an | ||||
| [issue](https://github.com/fmtlib/fmt/issues). | ||||
|  | ||||
| # Motivation | ||||
|  | ||||
| So why yet another formatting library? | ||||
|  | ||||
| There are plenty of methods for doing this task, from standard ones like | ||||
| the printf family of function and iostreams to Boost Format and | ||||
| FastFormat libraries. The reason for creating a new library is that | ||||
| every existing solution that I found either had serious issues or | ||||
| didn\'t provide all the features I needed. | ||||
|  | ||||
| ## printf | ||||
|  | ||||
| The good thing about `printf` is that it is pretty fast and readily | ||||
| available being a part of the C standard library. The main drawback is | ||||
| that it doesn\'t support user-defined types. `printf` also has safety | ||||
| issues although they are somewhat mitigated with [\_\_attribute\_\_ | ||||
| ((format (printf, | ||||
| \...))](https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html) in | ||||
| GCC. There is a POSIX extension that adds positional arguments required | ||||
| for | ||||
| [i18n](https://en.wikipedia.org/wiki/Internationalization_and_localization) | ||||
| to `printf` but it is not a part of C99 and may not be available on some | ||||
| platforms. | ||||
|  | ||||
| ## iostreams | ||||
|  | ||||
| The main issue with iostreams is best illustrated with an example: | ||||
|  | ||||
| ``` c++ | ||||
| std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n"; | ||||
| ``` | ||||
|  | ||||
| which is a lot of typing compared to printf: | ||||
|  | ||||
| ``` c++ | ||||
| printf("%.2f\n", 1.23456); | ||||
| ``` | ||||
|  | ||||
| Matthew Wilson, the author of FastFormat, called this \"chevron hell\". | ||||
| iostreams don\'t support positional arguments by design. | ||||
|  | ||||
| The good part is that iostreams support user-defined types and are safe | ||||
| although error handling is awkward. | ||||
|  | ||||
| ## Boost Format | ||||
|  | ||||
| This is a very powerful library that supports both `printf`-like format | ||||
| strings and positional arguments. Its main drawback is performance. | ||||
| According to various benchmarks, it is much slower than other methods | ||||
| considered here. Boost Format also has excessive build times and severe | ||||
| code bloat issues (see [Benchmarks](#benchmarks)). | ||||
|  | ||||
| ## FastFormat | ||||
|  | ||||
| This is an interesting library that is fast, safe, and has positional | ||||
| arguments. However, it has significant limitations, citing its author: | ||||
|  | ||||
| > Three features that have no hope of being accommodated within the | ||||
| > current design are: | ||||
| > | ||||
| > - Leading zeros (or any other non-space padding) | ||||
| > - Octal/hexadecimal encoding | ||||
| > - Runtime width/alignment specification | ||||
|  | ||||
| It is also quite big and has a heavy dependency, STLSoft, which might be | ||||
| too restrictive for using it in some projects. | ||||
|  | ||||
| ## Boost Spirit.Karma | ||||
|  | ||||
| This is not a formatting library but I decided to include it here for | ||||
| completeness. As iostreams, it suffers from the problem of mixing | ||||
| verbatim text with arguments. The library is pretty fast, but slower on | ||||
| integer formatting than `fmt::format_to` with format string compilation | ||||
| on Karma\'s own benchmark, see [Converting a hundred million integers to | ||||
| strings per | ||||
| second](http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html). | ||||
|  | ||||
| # License | ||||
|  | ||||
| {fmt} is distributed under the MIT | ||||
| [license](https://github.com/fmtlib/fmt/blob/master/LICENSE). | ||||
|  | ||||
| # Documentation License | ||||
|  | ||||
| The [Format String Syntax](https://fmt.dev/latest/syntax.html) section | ||||
| in the documentation is based on the one from Python [string module | ||||
| documentation](https://docs.python.org/3/library/string.html#module-string). | ||||
| For this reason, the documentation is distributed under the Python | ||||
| Software Foundation license available in | ||||
| [doc/python-license.txt](https://raw.github.com/fmtlib/fmt/master/doc/python-license.txt). | ||||
| It only applies if you distribute the documentation of {fmt}. | ||||
|  | ||||
| # Maintainers | ||||
|  | ||||
| The {fmt} library is maintained by Victor Zverovich | ||||
| ([vitaut](https://github.com/vitaut)) with contributions from many other | ||||
| people. See | ||||
| [Contributors](https://github.com/fmtlib/fmt/graphs/contributors) and | ||||
| [Releases](https://github.com/fmtlib/fmt/releases) for some of the | ||||
| names. Let us know if your contribution is not listed or mentioned | ||||
| incorrectly and we\'ll make it right. | ||||
|  | ||||
| # Security Policy | ||||
|  | ||||
| To report a security issue, please disclose it at [security | ||||
| advisory](https://github.com/fmtlib/fmt/security/advisories/new). | ||||
|  | ||||
| This project is maintained by a team of volunteers on a | ||||
| reasonable-effort basis. As such, please give us at least 90 days to | ||||
| work on a fix before public exposure. | ||||
							
								
								
									
										2
									
								
								dep/fmt/UPSTREAM.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								dep/fmt/UPSTREAM.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| This is a pruned version of fmt 10.2.1, obtained from | ||||
| https://github.com/fmtlib/fmt/releases/tag/10.2.1. | ||||
							
								
								
									
										18
									
								
								dep/fmt/build.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								dep/fmt/build.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| from build.c import cxxlibrary, HostToolchain | ||||
|  | ||||
| cxxlibrary( | ||||
|     name="fmt", | ||||
|     srcs=[ | ||||
|         "./src/format.cc", | ||||
|         "./src/os.cc", | ||||
|     ], | ||||
|     cflags=["-Idep/fmt/include"], | ||||
|     hdrs={ | ||||
|         "fmt/args.h": "./include/fmt/args.h", | ||||
|         "fmt/chrono.h": "./include/fmt/chrono.h", | ||||
|         "fmt/core.h": "./include/fmt/core.h", | ||||
|         "fmt/format.h": "./include/fmt/format.h", | ||||
|         "fmt/ostream.h": "./include/fmt/ostream.h", | ||||
|         "fmt/ranges.h": "./include/fmt/ranges.h", | ||||
|     }, | ||||
| ) | ||||
							
								
								
									
										235
									
								
								dep/fmt/include/fmt/args.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										235
									
								
								dep/fmt/include/fmt/args.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,235 @@ | ||||
| // Formatting library for C++ - dynamic argument lists | ||||
| // | ||||
| // Copyright (c) 2012 - present, Victor Zverovich | ||||
| // All rights reserved. | ||||
| // | ||||
| // For the license information refer to format.h. | ||||
|  | ||||
| #ifndef FMT_ARGS_H_ | ||||
| #define FMT_ARGS_H_ | ||||
|  | ||||
| #include <functional>  // std::reference_wrapper | ||||
| #include <memory>      // std::unique_ptr | ||||
| #include <vector> | ||||
|  | ||||
| #include "core.h" | ||||
|  | ||||
| FMT_BEGIN_NAMESPACE | ||||
|  | ||||
| namespace detail { | ||||
|  | ||||
| template <typename T> struct is_reference_wrapper : std::false_type {}; | ||||
| template <typename T> | ||||
| struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {}; | ||||
|  | ||||
| template <typename T> auto unwrap(const T& v) -> const T& { return v; } | ||||
| template <typename T> | ||||
| auto unwrap(const std::reference_wrapper<T>& v) -> const T& { | ||||
|   return static_cast<const T&>(v); | ||||
| } | ||||
|  | ||||
| class dynamic_arg_list { | ||||
|   // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for | ||||
|   // templates it doesn't complain about inability to deduce single translation | ||||
|   // unit for placing vtable. So storage_node_base is made a fake template. | ||||
|   template <typename = void> struct node { | ||||
|     virtual ~node() = default; | ||||
|     std::unique_ptr<node<>> next; | ||||
|   }; | ||||
|  | ||||
|   template <typename T> struct typed_node : node<> { | ||||
|     T value; | ||||
|  | ||||
|     template <typename Arg> | ||||
|     FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {} | ||||
|  | ||||
|     template <typename Char> | ||||
|     FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg) | ||||
|         : value(arg.data(), arg.size()) {} | ||||
|   }; | ||||
|  | ||||
|   std::unique_ptr<node<>> head_; | ||||
|  | ||||
|  public: | ||||
|   template <typename T, typename Arg> auto push(const Arg& arg) -> const T& { | ||||
|     auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg)); | ||||
|     auto& value = new_node->value; | ||||
|     new_node->next = std::move(head_); | ||||
|     head_ = std::move(new_node); | ||||
|     return value; | ||||
|   } | ||||
| }; | ||||
| }  // namespace detail | ||||
|  | ||||
| /** | ||||
|   \rst | ||||
|   A dynamic version of `fmt::format_arg_store`. | ||||
|   It's equipped with a storage to potentially temporary objects which lifetimes | ||||
|   could be shorter than the format arguments object. | ||||
|  | ||||
|   It can be implicitly converted into `~fmt::basic_format_args` for passing | ||||
|   into type-erased formatting functions such as `~fmt::vformat`. | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename Context> | ||||
| class dynamic_format_arg_store | ||||
| #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 | ||||
|     // Workaround a GCC template argument substitution bug. | ||||
|     : public basic_format_args<Context> | ||||
| #endif | ||||
| { | ||||
|  private: | ||||
|   using char_type = typename Context::char_type; | ||||
|  | ||||
|   template <typename T> struct need_copy { | ||||
|     static constexpr detail::type mapped_type = | ||||
|         detail::mapped_type_constant<T, Context>::value; | ||||
|  | ||||
|     enum { | ||||
|       value = !(detail::is_reference_wrapper<T>::value || | ||||
|                 std::is_same<T, basic_string_view<char_type>>::value || | ||||
|                 std::is_same<T, detail::std_string_view<char_type>>::value || | ||||
|                 (mapped_type != detail::type::cstring_type && | ||||
|                  mapped_type != detail::type::string_type && | ||||
|                  mapped_type != detail::type::custom_type)) | ||||
|     }; | ||||
|   }; | ||||
|  | ||||
|   template <typename T> | ||||
|   using stored_type = conditional_t< | ||||
|       std::is_convertible<T, std::basic_string<char_type>>::value && | ||||
|           !detail::is_reference_wrapper<T>::value, | ||||
|       std::basic_string<char_type>, T>; | ||||
|  | ||||
|   // Storage of basic_format_arg must be contiguous. | ||||
|   std::vector<basic_format_arg<Context>> data_; | ||||
|   std::vector<detail::named_arg_info<char_type>> named_info_; | ||||
|  | ||||
|   // Storage of arguments not fitting into basic_format_arg must grow | ||||
|   // without relocation because items in data_ refer to it. | ||||
|   detail::dynamic_arg_list dynamic_args_; | ||||
|  | ||||
|   friend class basic_format_args<Context>; | ||||
|  | ||||
|   auto get_types() const -> unsigned long long { | ||||
|     return detail::is_unpacked_bit | data_.size() | | ||||
|            (named_info_.empty() | ||||
|                 ? 0ULL | ||||
|                 : static_cast<unsigned long long>(detail::has_named_args_bit)); | ||||
|   } | ||||
|  | ||||
|   auto data() const -> const basic_format_arg<Context>* { | ||||
|     return named_info_.empty() ? data_.data() : data_.data() + 1; | ||||
|   } | ||||
|  | ||||
|   template <typename T> void emplace_arg(const T& arg) { | ||||
|     data_.emplace_back(detail::make_arg<Context>(arg)); | ||||
|   } | ||||
|  | ||||
|   template <typename T> | ||||
|   void emplace_arg(const detail::named_arg<char_type, T>& arg) { | ||||
|     if (named_info_.empty()) { | ||||
|       constexpr const detail::named_arg_info<char_type>* zero_ptr{nullptr}; | ||||
|       data_.insert(data_.begin(), {zero_ptr, 0}); | ||||
|     } | ||||
|     data_.emplace_back(detail::make_arg<Context>(detail::unwrap(arg.value))); | ||||
|     auto pop_one = [](std::vector<basic_format_arg<Context>>* data) { | ||||
|       data->pop_back(); | ||||
|     }; | ||||
|     std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)> | ||||
|         guard{&data_, pop_one}; | ||||
|     named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)}); | ||||
|     data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; | ||||
|     guard.release(); | ||||
|   } | ||||
|  | ||||
|  public: | ||||
|   constexpr dynamic_format_arg_store() = default; | ||||
|  | ||||
|   /** | ||||
|     \rst | ||||
|     Adds an argument into the dynamic store for later passing to a formatting | ||||
|     function. | ||||
|  | ||||
|     Note that custom types and string types (but not string views) are copied | ||||
|     into the store dynamically allocating memory if necessary. | ||||
|  | ||||
|     **Example**:: | ||||
|  | ||||
|       fmt::dynamic_format_arg_store<fmt::format_context> store; | ||||
|       store.push_back(42); | ||||
|       store.push_back("abc"); | ||||
|       store.push_back(1.5f); | ||||
|       std::string result = fmt::vformat("{} and {} and {}", store); | ||||
|     \endrst | ||||
|   */ | ||||
|   template <typename T> void push_back(const T& arg) { | ||||
|     if (detail::const_check(need_copy<T>::value)) | ||||
|       emplace_arg(dynamic_args_.push<stored_type<T>>(arg)); | ||||
|     else | ||||
|       emplace_arg(detail::unwrap(arg)); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|     \rst | ||||
|     Adds a reference to the argument into the dynamic store for later passing to | ||||
|     a formatting function. | ||||
|  | ||||
|     **Example**:: | ||||
|  | ||||
|       fmt::dynamic_format_arg_store<fmt::format_context> store; | ||||
|       char band[] = "Rolling Stones"; | ||||
|       store.push_back(std::cref(band)); | ||||
|       band[9] = 'c'; // Changing str affects the output. | ||||
|       std::string result = fmt::vformat("{}", store); | ||||
|       // result == "Rolling Scones" | ||||
|     \endrst | ||||
|   */ | ||||
|   template <typename T> void push_back(std::reference_wrapper<T> arg) { | ||||
|     static_assert( | ||||
|         need_copy<T>::value, | ||||
|         "objects of built-in types and string views are always copied"); | ||||
|     emplace_arg(arg.get()); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|     Adds named argument into the dynamic store for later passing to a formatting | ||||
|     function. ``std::reference_wrapper`` is supported to avoid copying of the | ||||
|     argument. The name is always copied into the store. | ||||
|   */ | ||||
|   template <typename T> | ||||
|   void push_back(const detail::named_arg<char_type, T>& arg) { | ||||
|     const char_type* arg_name = | ||||
|         dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str(); | ||||
|     if (detail::const_check(need_copy<T>::value)) { | ||||
|       emplace_arg( | ||||
|           fmt::arg(arg_name, dynamic_args_.push<stored_type<T>>(arg.value))); | ||||
|     } else { | ||||
|       emplace_arg(fmt::arg(arg_name, arg.value)); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** Erase all elements from the store */ | ||||
|   void clear() { | ||||
|     data_.clear(); | ||||
|     named_info_.clear(); | ||||
|     dynamic_args_ = detail::dynamic_arg_list(); | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|     \rst | ||||
|     Reserves space to store at least *new_cap* arguments including | ||||
|     *new_cap_named* named arguments. | ||||
|     \endrst | ||||
|   */ | ||||
|   void reserve(size_t new_cap, size_t new_cap_named) { | ||||
|     FMT_ASSERT(new_cap >= new_cap_named, | ||||
|                "Set of arguments includes set of named arguments"); | ||||
|     data_.reserve(new_cap); | ||||
|     named_info_.reserve(new_cap_named); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| FMT_END_NAMESPACE | ||||
|  | ||||
| #endif  // FMT_ARGS_H_ | ||||
							
								
								
									
										2240
									
								
								dep/fmt/include/fmt/chrono.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2240
									
								
								dep/fmt/include/fmt/chrono.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										643
									
								
								dep/fmt/include/fmt/color.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										643
									
								
								dep/fmt/include/fmt/color.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,643 @@ | ||||
| // Formatting library for C++ - color support | ||||
| // | ||||
| // Copyright (c) 2018 - present, Victor Zverovich and fmt contributors | ||||
| // All rights reserved. | ||||
| // | ||||
| // For the license information refer to format.h. | ||||
|  | ||||
| #ifndef FMT_COLOR_H_ | ||||
| #define FMT_COLOR_H_ | ||||
|  | ||||
| #include "format.h" | ||||
|  | ||||
| FMT_BEGIN_NAMESPACE | ||||
| FMT_BEGIN_EXPORT | ||||
|  | ||||
| enum class color : uint32_t { | ||||
|   alice_blue = 0xF0F8FF,               // rgb(240,248,255) | ||||
|   antique_white = 0xFAEBD7,            // rgb(250,235,215) | ||||
|   aqua = 0x00FFFF,                     // rgb(0,255,255) | ||||
|   aquamarine = 0x7FFFD4,               // rgb(127,255,212) | ||||
|   azure = 0xF0FFFF,                    // rgb(240,255,255) | ||||
|   beige = 0xF5F5DC,                    // rgb(245,245,220) | ||||
|   bisque = 0xFFE4C4,                   // rgb(255,228,196) | ||||
|   black = 0x000000,                    // rgb(0,0,0) | ||||
|   blanched_almond = 0xFFEBCD,          // rgb(255,235,205) | ||||
|   blue = 0x0000FF,                     // rgb(0,0,255) | ||||
|   blue_violet = 0x8A2BE2,              // rgb(138,43,226) | ||||
|   brown = 0xA52A2A,                    // rgb(165,42,42) | ||||
|   burly_wood = 0xDEB887,               // rgb(222,184,135) | ||||
|   cadet_blue = 0x5F9EA0,               // rgb(95,158,160) | ||||
|   chartreuse = 0x7FFF00,               // rgb(127,255,0) | ||||
|   chocolate = 0xD2691E,                // rgb(210,105,30) | ||||
|   coral = 0xFF7F50,                    // rgb(255,127,80) | ||||
|   cornflower_blue = 0x6495ED,          // rgb(100,149,237) | ||||
|   cornsilk = 0xFFF8DC,                 // rgb(255,248,220) | ||||
|   crimson = 0xDC143C,                  // rgb(220,20,60) | ||||
|   cyan = 0x00FFFF,                     // rgb(0,255,255) | ||||
|   dark_blue = 0x00008B,                // rgb(0,0,139) | ||||
|   dark_cyan = 0x008B8B,                // rgb(0,139,139) | ||||
|   dark_golden_rod = 0xB8860B,          // rgb(184,134,11) | ||||
|   dark_gray = 0xA9A9A9,                // rgb(169,169,169) | ||||
|   dark_green = 0x006400,               // rgb(0,100,0) | ||||
|   dark_khaki = 0xBDB76B,               // rgb(189,183,107) | ||||
|   dark_magenta = 0x8B008B,             // rgb(139,0,139) | ||||
|   dark_olive_green = 0x556B2F,         // rgb(85,107,47) | ||||
|   dark_orange = 0xFF8C00,              // rgb(255,140,0) | ||||
|   dark_orchid = 0x9932CC,              // rgb(153,50,204) | ||||
|   dark_red = 0x8B0000,                 // rgb(139,0,0) | ||||
|   dark_salmon = 0xE9967A,              // rgb(233,150,122) | ||||
|   dark_sea_green = 0x8FBC8F,           // rgb(143,188,143) | ||||
|   dark_slate_blue = 0x483D8B,          // rgb(72,61,139) | ||||
|   dark_slate_gray = 0x2F4F4F,          // rgb(47,79,79) | ||||
|   dark_turquoise = 0x00CED1,           // rgb(0,206,209) | ||||
|   dark_violet = 0x9400D3,              // rgb(148,0,211) | ||||
|   deep_pink = 0xFF1493,                // rgb(255,20,147) | ||||
|   deep_sky_blue = 0x00BFFF,            // rgb(0,191,255) | ||||
|   dim_gray = 0x696969,                 // rgb(105,105,105) | ||||
|   dodger_blue = 0x1E90FF,              // rgb(30,144,255) | ||||
|   fire_brick = 0xB22222,               // rgb(178,34,34) | ||||
|   floral_white = 0xFFFAF0,             // rgb(255,250,240) | ||||
|   forest_green = 0x228B22,             // rgb(34,139,34) | ||||
|   fuchsia = 0xFF00FF,                  // rgb(255,0,255) | ||||
|   gainsboro = 0xDCDCDC,                // rgb(220,220,220) | ||||
|   ghost_white = 0xF8F8FF,              // rgb(248,248,255) | ||||
|   gold = 0xFFD700,                     // rgb(255,215,0) | ||||
|   golden_rod = 0xDAA520,               // rgb(218,165,32) | ||||
|   gray = 0x808080,                     // rgb(128,128,128) | ||||
|   green = 0x008000,                    // rgb(0,128,0) | ||||
|   green_yellow = 0xADFF2F,             // rgb(173,255,47) | ||||
|   honey_dew = 0xF0FFF0,                // rgb(240,255,240) | ||||
|   hot_pink = 0xFF69B4,                 // rgb(255,105,180) | ||||
|   indian_red = 0xCD5C5C,               // rgb(205,92,92) | ||||
|   indigo = 0x4B0082,                   // rgb(75,0,130) | ||||
|   ivory = 0xFFFFF0,                    // rgb(255,255,240) | ||||
|   khaki = 0xF0E68C,                    // rgb(240,230,140) | ||||
|   lavender = 0xE6E6FA,                 // rgb(230,230,250) | ||||
|   lavender_blush = 0xFFF0F5,           // rgb(255,240,245) | ||||
|   lawn_green = 0x7CFC00,               // rgb(124,252,0) | ||||
|   lemon_chiffon = 0xFFFACD,            // rgb(255,250,205) | ||||
|   light_blue = 0xADD8E6,               // rgb(173,216,230) | ||||
|   light_coral = 0xF08080,              // rgb(240,128,128) | ||||
|   light_cyan = 0xE0FFFF,               // rgb(224,255,255) | ||||
|   light_golden_rod_yellow = 0xFAFAD2,  // rgb(250,250,210) | ||||
|   light_gray = 0xD3D3D3,               // rgb(211,211,211) | ||||
|   light_green = 0x90EE90,              // rgb(144,238,144) | ||||
|   light_pink = 0xFFB6C1,               // rgb(255,182,193) | ||||
|   light_salmon = 0xFFA07A,             // rgb(255,160,122) | ||||
|   light_sea_green = 0x20B2AA,          // rgb(32,178,170) | ||||
|   light_sky_blue = 0x87CEFA,           // rgb(135,206,250) | ||||
|   light_slate_gray = 0x778899,         // rgb(119,136,153) | ||||
|   light_steel_blue = 0xB0C4DE,         // rgb(176,196,222) | ||||
|   light_yellow = 0xFFFFE0,             // rgb(255,255,224) | ||||
|   lime = 0x00FF00,                     // rgb(0,255,0) | ||||
|   lime_green = 0x32CD32,               // rgb(50,205,50) | ||||
|   linen = 0xFAF0E6,                    // rgb(250,240,230) | ||||
|   magenta = 0xFF00FF,                  // rgb(255,0,255) | ||||
|   maroon = 0x800000,                   // rgb(128,0,0) | ||||
|   medium_aquamarine = 0x66CDAA,        // rgb(102,205,170) | ||||
|   medium_blue = 0x0000CD,              // rgb(0,0,205) | ||||
|   medium_orchid = 0xBA55D3,            // rgb(186,85,211) | ||||
|   medium_purple = 0x9370DB,            // rgb(147,112,219) | ||||
|   medium_sea_green = 0x3CB371,         // rgb(60,179,113) | ||||
|   medium_slate_blue = 0x7B68EE,        // rgb(123,104,238) | ||||
|   medium_spring_green = 0x00FA9A,      // rgb(0,250,154) | ||||
|   medium_turquoise = 0x48D1CC,         // rgb(72,209,204) | ||||
|   medium_violet_red = 0xC71585,        // rgb(199,21,133) | ||||
|   midnight_blue = 0x191970,            // rgb(25,25,112) | ||||
|   mint_cream = 0xF5FFFA,               // rgb(245,255,250) | ||||
|   misty_rose = 0xFFE4E1,               // rgb(255,228,225) | ||||
|   moccasin = 0xFFE4B5,                 // rgb(255,228,181) | ||||
|   navajo_white = 0xFFDEAD,             // rgb(255,222,173) | ||||
|   navy = 0x000080,                     // rgb(0,0,128) | ||||
|   old_lace = 0xFDF5E6,                 // rgb(253,245,230) | ||||
|   olive = 0x808000,                    // rgb(128,128,0) | ||||
|   olive_drab = 0x6B8E23,               // rgb(107,142,35) | ||||
|   orange = 0xFFA500,                   // rgb(255,165,0) | ||||
|   orange_red = 0xFF4500,               // rgb(255,69,0) | ||||
|   orchid = 0xDA70D6,                   // rgb(218,112,214) | ||||
|   pale_golden_rod = 0xEEE8AA,          // rgb(238,232,170) | ||||
|   pale_green = 0x98FB98,               // rgb(152,251,152) | ||||
|   pale_turquoise = 0xAFEEEE,           // rgb(175,238,238) | ||||
|   pale_violet_red = 0xDB7093,          // rgb(219,112,147) | ||||
|   papaya_whip = 0xFFEFD5,              // rgb(255,239,213) | ||||
|   peach_puff = 0xFFDAB9,               // rgb(255,218,185) | ||||
|   peru = 0xCD853F,                     // rgb(205,133,63) | ||||
|   pink = 0xFFC0CB,                     // rgb(255,192,203) | ||||
|   plum = 0xDDA0DD,                     // rgb(221,160,221) | ||||
|   powder_blue = 0xB0E0E6,              // rgb(176,224,230) | ||||
|   purple = 0x800080,                   // rgb(128,0,128) | ||||
|   rebecca_purple = 0x663399,           // rgb(102,51,153) | ||||
|   red = 0xFF0000,                      // rgb(255,0,0) | ||||
|   rosy_brown = 0xBC8F8F,               // rgb(188,143,143) | ||||
|   royal_blue = 0x4169E1,               // rgb(65,105,225) | ||||
|   saddle_brown = 0x8B4513,             // rgb(139,69,19) | ||||
|   salmon = 0xFA8072,                   // rgb(250,128,114) | ||||
|   sandy_brown = 0xF4A460,              // rgb(244,164,96) | ||||
|   sea_green = 0x2E8B57,                // rgb(46,139,87) | ||||
|   sea_shell = 0xFFF5EE,                // rgb(255,245,238) | ||||
|   sienna = 0xA0522D,                   // rgb(160,82,45) | ||||
|   silver = 0xC0C0C0,                   // rgb(192,192,192) | ||||
|   sky_blue = 0x87CEEB,                 // rgb(135,206,235) | ||||
|   slate_blue = 0x6A5ACD,               // rgb(106,90,205) | ||||
|   slate_gray = 0x708090,               // rgb(112,128,144) | ||||
|   snow = 0xFFFAFA,                     // rgb(255,250,250) | ||||
|   spring_green = 0x00FF7F,             // rgb(0,255,127) | ||||
|   steel_blue = 0x4682B4,               // rgb(70,130,180) | ||||
|   tan = 0xD2B48C,                      // rgb(210,180,140) | ||||
|   teal = 0x008080,                     // rgb(0,128,128) | ||||
|   thistle = 0xD8BFD8,                  // rgb(216,191,216) | ||||
|   tomato = 0xFF6347,                   // rgb(255,99,71) | ||||
|   turquoise = 0x40E0D0,                // rgb(64,224,208) | ||||
|   violet = 0xEE82EE,                   // rgb(238,130,238) | ||||
|   wheat = 0xF5DEB3,                    // rgb(245,222,179) | ||||
|   white = 0xFFFFFF,                    // rgb(255,255,255) | ||||
|   white_smoke = 0xF5F5F5,              // rgb(245,245,245) | ||||
|   yellow = 0xFFFF00,                   // rgb(255,255,0) | ||||
|   yellow_green = 0x9ACD32              // rgb(154,205,50) | ||||
| };                                     // enum class color | ||||
|  | ||||
| enum class terminal_color : uint8_t { | ||||
|   black = 30, | ||||
|   red, | ||||
|   green, | ||||
|   yellow, | ||||
|   blue, | ||||
|   magenta, | ||||
|   cyan, | ||||
|   white, | ||||
|   bright_black = 90, | ||||
|   bright_red, | ||||
|   bright_green, | ||||
|   bright_yellow, | ||||
|   bright_blue, | ||||
|   bright_magenta, | ||||
|   bright_cyan, | ||||
|   bright_white | ||||
| }; | ||||
|  | ||||
| enum class emphasis : uint8_t { | ||||
|   bold = 1, | ||||
|   faint = 1 << 1, | ||||
|   italic = 1 << 2, | ||||
|   underline = 1 << 3, | ||||
|   blink = 1 << 4, | ||||
|   reverse = 1 << 5, | ||||
|   conceal = 1 << 6, | ||||
|   strikethrough = 1 << 7, | ||||
| }; | ||||
|  | ||||
| // rgb is a struct for red, green and blue colors. | ||||
| // Using the name "rgb" makes some editors show the color in a tooltip. | ||||
| struct rgb { | ||||
|   FMT_CONSTEXPR rgb() : r(0), g(0), b(0) {} | ||||
|   FMT_CONSTEXPR rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {} | ||||
|   FMT_CONSTEXPR rgb(uint32_t hex) | ||||
|       : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {} | ||||
|   FMT_CONSTEXPR rgb(color hex) | ||||
|       : r((uint32_t(hex) >> 16) & 0xFF), | ||||
|         g((uint32_t(hex) >> 8) & 0xFF), | ||||
|         b(uint32_t(hex) & 0xFF) {} | ||||
|   uint8_t r; | ||||
|   uint8_t g; | ||||
|   uint8_t b; | ||||
| }; | ||||
|  | ||||
| namespace detail { | ||||
|  | ||||
| // color is a struct of either a rgb color or a terminal color. | ||||
| struct color_type { | ||||
|   FMT_CONSTEXPR color_type() noexcept : is_rgb(), value{} {} | ||||
|   FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} { | ||||
|     value.rgb_color = static_cast<uint32_t>(rgb_color); | ||||
|   } | ||||
|   FMT_CONSTEXPR color_type(rgb rgb_color) noexcept : is_rgb(true), value{} { | ||||
|     value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) | | ||||
|                       (static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b; | ||||
|   } | ||||
|   FMT_CONSTEXPR color_type(terminal_color term_color) noexcept | ||||
|       : is_rgb(), value{} { | ||||
|     value.term_color = static_cast<uint8_t>(term_color); | ||||
|   } | ||||
|   bool is_rgb; | ||||
|   union color_union { | ||||
|     uint8_t term_color; | ||||
|     uint32_t rgb_color; | ||||
|   } value; | ||||
| }; | ||||
| }  // namespace detail | ||||
|  | ||||
| /** A text style consisting of foreground and background colors and emphasis. */ | ||||
| class text_style { | ||||
|  public: | ||||
|   FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept | ||||
|       : set_foreground_color(), set_background_color(), ems(em) {} | ||||
|  | ||||
|   FMT_CONSTEXPR auto operator|=(const text_style& rhs) -> text_style& { | ||||
|     if (!set_foreground_color) { | ||||
|       set_foreground_color = rhs.set_foreground_color; | ||||
|       foreground_color = rhs.foreground_color; | ||||
|     } else if (rhs.set_foreground_color) { | ||||
|       if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) | ||||
|         FMT_THROW(format_error("can't OR a terminal color")); | ||||
|       foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color; | ||||
|     } | ||||
|  | ||||
|     if (!set_background_color) { | ||||
|       set_background_color = rhs.set_background_color; | ||||
|       background_color = rhs.background_color; | ||||
|     } else if (rhs.set_background_color) { | ||||
|       if (!background_color.is_rgb || !rhs.background_color.is_rgb) | ||||
|         FMT_THROW(format_error("can't OR a terminal color")); | ||||
|       background_color.value.rgb_color |= rhs.background_color.value.rgb_color; | ||||
|     } | ||||
|  | ||||
|     ems = static_cast<emphasis>(static_cast<uint8_t>(ems) | | ||||
|                                 static_cast<uint8_t>(rhs.ems)); | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   friend FMT_CONSTEXPR auto operator|(text_style lhs, const text_style& rhs) | ||||
|       -> text_style { | ||||
|     return lhs |= rhs; | ||||
|   } | ||||
|  | ||||
|   FMT_CONSTEXPR auto has_foreground() const noexcept -> bool { | ||||
|     return set_foreground_color; | ||||
|   } | ||||
|   FMT_CONSTEXPR auto has_background() const noexcept -> bool { | ||||
|     return set_background_color; | ||||
|   } | ||||
|   FMT_CONSTEXPR auto has_emphasis() const noexcept -> bool { | ||||
|     return static_cast<uint8_t>(ems) != 0; | ||||
|   } | ||||
|   FMT_CONSTEXPR auto get_foreground() const noexcept -> detail::color_type { | ||||
|     FMT_ASSERT(has_foreground(), "no foreground specified for this style"); | ||||
|     return foreground_color; | ||||
|   } | ||||
|   FMT_CONSTEXPR auto get_background() const noexcept -> detail::color_type { | ||||
|     FMT_ASSERT(has_background(), "no background specified for this style"); | ||||
|     return background_color; | ||||
|   } | ||||
|   FMT_CONSTEXPR auto get_emphasis() const noexcept -> emphasis { | ||||
|     FMT_ASSERT(has_emphasis(), "no emphasis specified for this style"); | ||||
|     return ems; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   FMT_CONSTEXPR text_style(bool is_foreground, | ||||
|                            detail::color_type text_color) noexcept | ||||
|       : set_foreground_color(), set_background_color(), ems() { | ||||
|     if (is_foreground) { | ||||
|       foreground_color = text_color; | ||||
|       set_foreground_color = true; | ||||
|     } else { | ||||
|       background_color = text_color; | ||||
|       set_background_color = true; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   friend FMT_CONSTEXPR auto fg(detail::color_type foreground) noexcept | ||||
|       -> text_style; | ||||
|  | ||||
|   friend FMT_CONSTEXPR auto bg(detail::color_type background) noexcept | ||||
|       -> text_style; | ||||
|  | ||||
|   detail::color_type foreground_color; | ||||
|   detail::color_type background_color; | ||||
|   bool set_foreground_color; | ||||
|   bool set_background_color; | ||||
|   emphasis ems; | ||||
| }; | ||||
|  | ||||
| /** Creates a text style from the foreground (text) color. */ | ||||
| FMT_CONSTEXPR inline auto fg(detail::color_type foreground) noexcept | ||||
|     -> text_style { | ||||
|   return text_style(true, foreground); | ||||
| } | ||||
|  | ||||
| /** Creates a text style from the background color. */ | ||||
| FMT_CONSTEXPR inline auto bg(detail::color_type background) noexcept | ||||
|     -> text_style { | ||||
|   return text_style(false, background); | ||||
| } | ||||
|  | ||||
| FMT_CONSTEXPR inline auto operator|(emphasis lhs, emphasis rhs) noexcept | ||||
|     -> text_style { | ||||
|   return text_style(lhs) | rhs; | ||||
| } | ||||
|  | ||||
| namespace detail { | ||||
|  | ||||
| template <typename Char> struct ansi_color_escape { | ||||
|   FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color, | ||||
|                                   const char* esc) noexcept { | ||||
|     // If we have a terminal color, we need to output another escape code | ||||
|     // sequence. | ||||
|     if (!text_color.is_rgb) { | ||||
|       bool is_background = esc == string_view("\x1b[48;2;"); | ||||
|       uint32_t value = text_color.value.term_color; | ||||
|       // Background ASCII codes are the same as the foreground ones but with | ||||
|       // 10 more. | ||||
|       if (is_background) value += 10u; | ||||
|  | ||||
|       size_t index = 0; | ||||
|       buffer[index++] = static_cast<Char>('\x1b'); | ||||
|       buffer[index++] = static_cast<Char>('['); | ||||
|  | ||||
|       if (value >= 100u) { | ||||
|         buffer[index++] = static_cast<Char>('1'); | ||||
|         value %= 100u; | ||||
|       } | ||||
|       buffer[index++] = static_cast<Char>('0' + value / 10u); | ||||
|       buffer[index++] = static_cast<Char>('0' + value % 10u); | ||||
|  | ||||
|       buffer[index++] = static_cast<Char>('m'); | ||||
|       buffer[index++] = static_cast<Char>('\0'); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < 7; i++) { | ||||
|       buffer[i] = static_cast<Char>(esc[i]); | ||||
|     } | ||||
|     rgb color(text_color.value.rgb_color); | ||||
|     to_esc(color.r, buffer + 7, ';'); | ||||
|     to_esc(color.g, buffer + 11, ';'); | ||||
|     to_esc(color.b, buffer + 15, 'm'); | ||||
|     buffer[19] = static_cast<Char>(0); | ||||
|   } | ||||
|   FMT_CONSTEXPR ansi_color_escape(emphasis em) noexcept { | ||||
|     uint8_t em_codes[num_emphases] = {}; | ||||
|     if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1; | ||||
|     if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2; | ||||
|     if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3; | ||||
|     if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4; | ||||
|     if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5; | ||||
|     if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7; | ||||
|     if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8; | ||||
|     if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9; | ||||
|  | ||||
|     size_t index = 0; | ||||
|     for (size_t i = 0; i < num_emphases; ++i) { | ||||
|       if (!em_codes[i]) continue; | ||||
|       buffer[index++] = static_cast<Char>('\x1b'); | ||||
|       buffer[index++] = static_cast<Char>('['); | ||||
|       buffer[index++] = static_cast<Char>('0' + em_codes[i]); | ||||
|       buffer[index++] = static_cast<Char>('m'); | ||||
|     } | ||||
|     buffer[index++] = static_cast<Char>(0); | ||||
|   } | ||||
|   FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; } | ||||
|  | ||||
|   FMT_CONSTEXPR auto begin() const noexcept -> const Char* { return buffer; } | ||||
|   FMT_CONSTEXPR_CHAR_TRAITS auto end() const noexcept -> const Char* { | ||||
|     return buffer + std::char_traits<Char>::length(buffer); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   static constexpr size_t num_emphases = 8; | ||||
|   Char buffer[7u + 3u * num_emphases + 1u]; | ||||
|  | ||||
|   static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out, | ||||
|                                    char delimiter) noexcept { | ||||
|     out[0] = static_cast<Char>('0' + c / 100); | ||||
|     out[1] = static_cast<Char>('0' + c / 10 % 10); | ||||
|     out[2] = static_cast<Char>('0' + c % 10); | ||||
|     out[3] = static_cast<Char>(delimiter); | ||||
|   } | ||||
|   static FMT_CONSTEXPR auto has_emphasis(emphasis em, emphasis mask) noexcept | ||||
|       -> bool { | ||||
|     return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename Char> | ||||
| FMT_CONSTEXPR auto make_foreground_color(detail::color_type foreground) noexcept | ||||
|     -> ansi_color_escape<Char> { | ||||
|   return ansi_color_escape<Char>(foreground, "\x1b[38;2;"); | ||||
| } | ||||
|  | ||||
| template <typename Char> | ||||
| FMT_CONSTEXPR auto make_background_color(detail::color_type background) noexcept | ||||
|     -> ansi_color_escape<Char> { | ||||
|   return ansi_color_escape<Char>(background, "\x1b[48;2;"); | ||||
| } | ||||
|  | ||||
| template <typename Char> | ||||
| FMT_CONSTEXPR auto make_emphasis(emphasis em) noexcept | ||||
|     -> ansi_color_escape<Char> { | ||||
|   return ansi_color_escape<Char>(em); | ||||
| } | ||||
|  | ||||
| template <typename Char> inline void reset_color(buffer<Char>& buffer) { | ||||
|   auto reset_color = string_view("\x1b[0m"); | ||||
|   buffer.append(reset_color.begin(), reset_color.end()); | ||||
| } | ||||
|  | ||||
| template <typename T> struct styled_arg : detail::view { | ||||
|   const T& value; | ||||
|   text_style style; | ||||
|   styled_arg(const T& v, text_style s) : value(v), style(s) {} | ||||
| }; | ||||
|  | ||||
| template <typename Char> | ||||
| void vformat_to(buffer<Char>& buf, const text_style& ts, | ||||
|                 basic_string_view<Char> format_str, | ||||
|                 basic_format_args<buffer_context<type_identity_t<Char>>> args) { | ||||
|   bool has_style = false; | ||||
|   if (ts.has_emphasis()) { | ||||
|     has_style = true; | ||||
|     auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis()); | ||||
|     buf.append(emphasis.begin(), emphasis.end()); | ||||
|   } | ||||
|   if (ts.has_foreground()) { | ||||
|     has_style = true; | ||||
|     auto foreground = detail::make_foreground_color<Char>(ts.get_foreground()); | ||||
|     buf.append(foreground.begin(), foreground.end()); | ||||
|   } | ||||
|   if (ts.has_background()) { | ||||
|     has_style = true; | ||||
|     auto background = detail::make_background_color<Char>(ts.get_background()); | ||||
|     buf.append(background.begin(), background.end()); | ||||
|   } | ||||
|   detail::vformat_to(buf, format_str, args, {}); | ||||
|   if (has_style) detail::reset_color<Char>(buf); | ||||
| } | ||||
|  | ||||
| }  // namespace detail | ||||
|  | ||||
| inline void vprint(std::FILE* f, const text_style& ts, string_view fmt, | ||||
|                    format_args args) { | ||||
|   // Legacy wide streams are not supported. | ||||
|   auto buf = memory_buffer(); | ||||
|   detail::vformat_to(buf, ts, fmt, args); | ||||
|   if (detail::is_utf8()) { | ||||
|     detail::print(f, string_view(buf.begin(), buf.size())); | ||||
|     return; | ||||
|   } | ||||
|   buf.push_back('\0'); | ||||
|   int result = std::fputs(buf.data(), f); | ||||
|   if (result < 0) | ||||
|     FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); | ||||
| } | ||||
|  | ||||
| /** | ||||
|   \rst | ||||
|   Formats a string and prints it to the specified file stream using ANSI | ||||
|   escape sequences to specify text formatting. | ||||
|  | ||||
|   **Example**:: | ||||
|  | ||||
|     fmt::print(fmt::emphasis::bold | fg(fmt::color::red), | ||||
|                "Elapsed time: {0:.2f} seconds", 1.23); | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_string<S>::value)> | ||||
| void print(std::FILE* f, const text_style& ts, const S& format_str, | ||||
|            const Args&... args) { | ||||
|   vprint(f, ts, format_str, | ||||
|          fmt::make_format_args<buffer_context<char_t<S>>>(args...)); | ||||
| } | ||||
|  | ||||
| /** | ||||
|   \rst | ||||
|   Formats a string and prints it to stdout using ANSI escape sequences to | ||||
|   specify text formatting. | ||||
|  | ||||
|   **Example**:: | ||||
|  | ||||
|     fmt::print(fmt::emphasis::bold | fg(fmt::color::red), | ||||
|                "Elapsed time: {0:.2f} seconds", 1.23); | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_string<S>::value)> | ||||
| void print(const text_style& ts, const S& format_str, const Args&... args) { | ||||
|   return print(stdout, ts, format_str, args...); | ||||
| } | ||||
|  | ||||
| template <typename S, typename Char = char_t<S>> | ||||
| inline auto vformat( | ||||
|     const text_style& ts, const S& format_str, | ||||
|     basic_format_args<buffer_context<type_identity_t<Char>>> args) | ||||
|     -> std::basic_string<Char> { | ||||
|   basic_memory_buffer<Char> buf; | ||||
|   detail::vformat_to(buf, ts, detail::to_string_view(format_str), args); | ||||
|   return fmt::to_string(buf); | ||||
| } | ||||
|  | ||||
| /** | ||||
|   \rst | ||||
|   Formats arguments and returns the result as a string using ANSI | ||||
|   escape sequences to specify text formatting. | ||||
|  | ||||
|   **Example**:: | ||||
|  | ||||
|     #include <fmt/color.h> | ||||
|     std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red), | ||||
|                                       "The answer is {}", 42); | ||||
|   \endrst | ||||
| */ | ||||
| template <typename S, typename... Args, typename Char = char_t<S>> | ||||
| inline auto format(const text_style& ts, const S& format_str, | ||||
|                    const Args&... args) -> std::basic_string<Char> { | ||||
|   return fmt::vformat(ts, detail::to_string_view(format_str), | ||||
|                       fmt::make_format_args<buffer_context<Char>>(args...)); | ||||
| } | ||||
|  | ||||
| /** | ||||
|   Formats a string with the given text_style and writes the output to ``out``. | ||||
|  */ | ||||
| template <typename OutputIt, typename Char, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)> | ||||
| auto vformat_to(OutputIt out, const text_style& ts, | ||||
|                 basic_string_view<Char> format_str, | ||||
|                 basic_format_args<buffer_context<type_identity_t<Char>>> args) | ||||
|     -> OutputIt { | ||||
|   auto&& buf = detail::get_buffer<Char>(out); | ||||
|   detail::vformat_to(buf, ts, format_str, args); | ||||
|   return detail::get_iterator(buf, out); | ||||
| } | ||||
|  | ||||
| /** | ||||
|   \rst | ||||
|   Formats arguments with the given text_style, writes the result to the output | ||||
|   iterator ``out`` and returns the iterator past the end of the output range. | ||||
|  | ||||
|   **Example**:: | ||||
|  | ||||
|     std::vector<char> out; | ||||
|     fmt::format_to(std::back_inserter(out), | ||||
|                    fmt::emphasis::bold | fg(fmt::color::red), "{}", 42); | ||||
|   \endrst | ||||
| */ | ||||
| template < | ||||
|     typename OutputIt, typename S, typename... Args, | ||||
|     bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value && | ||||
|                   detail::is_string<S>::value> | ||||
| inline auto format_to(OutputIt out, const text_style& ts, const S& format_str, | ||||
|                       Args&&... args) -> | ||||
|     typename std::enable_if<enable, OutputIt>::type { | ||||
|   return vformat_to(out, ts, detail::to_string_view(format_str), | ||||
|                     fmt::make_format_args<buffer_context<char_t<S>>>(args...)); | ||||
| } | ||||
|  | ||||
| template <typename T, typename Char> | ||||
| struct formatter<detail::styled_arg<T>, Char> : formatter<T, Char> { | ||||
|   template <typename FormatContext> | ||||
|   auto format(const detail::styled_arg<T>& arg, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     const auto& ts = arg.style; | ||||
|     const auto& value = arg.value; | ||||
|     auto out = ctx.out(); | ||||
|  | ||||
|     bool has_style = false; | ||||
|     if (ts.has_emphasis()) { | ||||
|       has_style = true; | ||||
|       auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis()); | ||||
|       out = std::copy(emphasis.begin(), emphasis.end(), out); | ||||
|     } | ||||
|     if (ts.has_foreground()) { | ||||
|       has_style = true; | ||||
|       auto foreground = | ||||
|           detail::make_foreground_color<Char>(ts.get_foreground()); | ||||
|       out = std::copy(foreground.begin(), foreground.end(), out); | ||||
|     } | ||||
|     if (ts.has_background()) { | ||||
|       has_style = true; | ||||
|       auto background = | ||||
|           detail::make_background_color<Char>(ts.get_background()); | ||||
|       out = std::copy(background.begin(), background.end(), out); | ||||
|     } | ||||
|     out = formatter<T, Char>::format(value, ctx); | ||||
|     if (has_style) { | ||||
|       auto reset_color = string_view("\x1b[0m"); | ||||
|       out = std::copy(reset_color.begin(), reset_color.end(), out); | ||||
|     } | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| /** | ||||
|   \rst | ||||
|   Returns an argument that will be formatted using ANSI escape sequences, | ||||
|   to be used in a formatting function. | ||||
|  | ||||
|   **Example**:: | ||||
|  | ||||
|     fmt::print("Elapsed time: {0:.2f} seconds", | ||||
|                fmt::styled(1.23, fmt::fg(fmt::color::green) | | ||||
|                                  fmt::bg(fmt::color::blue))); | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename T> | ||||
| FMT_CONSTEXPR auto styled(const T& value, text_style ts) | ||||
|     -> detail::styled_arg<remove_cvref_t<T>> { | ||||
|   return detail::styled_arg<remove_cvref_t<T>>{value, ts}; | ||||
| } | ||||
|  | ||||
| FMT_END_EXPORT | ||||
| FMT_END_NAMESPACE | ||||
|  | ||||
| #endif  // FMT_COLOR_H_ | ||||
							
								
								
									
										535
									
								
								dep/fmt/include/fmt/compile.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										535
									
								
								dep/fmt/include/fmt/compile.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,535 @@ | ||||
| // Formatting library for C++ - experimental format string compilation | ||||
| // | ||||
| // Copyright (c) 2012 - present, Victor Zverovich and fmt contributors | ||||
| // All rights reserved. | ||||
| // | ||||
| // For the license information refer to format.h. | ||||
|  | ||||
| #ifndef FMT_COMPILE_H_ | ||||
| #define FMT_COMPILE_H_ | ||||
|  | ||||
| #include "format.h" | ||||
|  | ||||
| FMT_BEGIN_NAMESPACE | ||||
| namespace detail { | ||||
|  | ||||
| template <typename Char, typename InputIt> | ||||
| FMT_CONSTEXPR inline auto copy_str(InputIt begin, InputIt end, | ||||
|                                    counting_iterator it) -> counting_iterator { | ||||
|   return it + (end - begin); | ||||
| } | ||||
|  | ||||
| // A compile-time string which is compiled into fast formatting code. | ||||
| class compiled_string {}; | ||||
|  | ||||
| template <typename S> | ||||
| struct is_compiled_string : std::is_base_of<compiled_string, S> {}; | ||||
|  | ||||
| /** | ||||
|   \rst | ||||
|   Converts a string literal *s* into a format string that will be parsed at | ||||
|   compile time and converted into efficient formatting code. Requires C++17 | ||||
|   ``constexpr if`` compiler support. | ||||
|  | ||||
|   **Example**:: | ||||
|  | ||||
|     // Converts 42 into std::string using the most efficient method and no | ||||
|     // runtime format string processing. | ||||
|     std::string s = fmt::format(FMT_COMPILE("{}"), 42); | ||||
|   \endrst | ||||
|  */ | ||||
| #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) | ||||
| #  define FMT_COMPILE(s) \ | ||||
|     FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit) | ||||
| #else | ||||
| #  define FMT_COMPILE(s) FMT_STRING(s) | ||||
| #endif | ||||
|  | ||||
| #if FMT_USE_NONTYPE_TEMPLATE_ARGS | ||||
| template <typename Char, size_t N, | ||||
|           fmt::detail_exported::fixed_string<Char, N> Str> | ||||
| struct udl_compiled_string : compiled_string { | ||||
|   using char_type = Char; | ||||
|   explicit constexpr operator basic_string_view<char_type>() const { | ||||
|     return {Str.data, N - 1}; | ||||
|   } | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| template <typename T, typename... Tail> | ||||
| auto first(const T& value, const Tail&...) -> const T& { | ||||
|   return value; | ||||
| } | ||||
|  | ||||
| #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) | ||||
| template <typename... Args> struct type_list {}; | ||||
|  | ||||
| // Returns a reference to the argument at index N from [first, rest...]. | ||||
| template <int N, typename T, typename... Args> | ||||
| constexpr const auto& get([[maybe_unused]] const T& first, | ||||
|                           [[maybe_unused]] const Args&... rest) { | ||||
|   static_assert(N < 1 + sizeof...(Args), "index is out of bounds"); | ||||
|   if constexpr (N == 0) | ||||
|     return first; | ||||
|   else | ||||
|     return detail::get<N - 1>(rest...); | ||||
| } | ||||
|  | ||||
| template <typename Char, typename... Args> | ||||
| constexpr int get_arg_index_by_name(basic_string_view<Char> name, | ||||
|                                     type_list<Args...>) { | ||||
|   return get_arg_index_by_name<Args...>(name); | ||||
| } | ||||
|  | ||||
| template <int N, typename> struct get_type_impl; | ||||
|  | ||||
| template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> { | ||||
|   using type = | ||||
|       remove_cvref_t<decltype(detail::get<N>(std::declval<Args>()...))>; | ||||
| }; | ||||
|  | ||||
| template <int N, typename T> | ||||
| using get_type = typename get_type_impl<N, T>::type; | ||||
|  | ||||
| template <typename T> struct is_compiled_format : std::false_type {}; | ||||
|  | ||||
| template <typename Char> struct text { | ||||
|   basic_string_view<Char> data; | ||||
|   using char_type = Char; | ||||
|  | ||||
|   template <typename OutputIt, typename... Args> | ||||
|   constexpr OutputIt format(OutputIt out, const Args&...) const { | ||||
|     return write<Char>(out, data); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename Char> | ||||
| struct is_compiled_format<text<Char>> : std::true_type {}; | ||||
|  | ||||
| template <typename Char> | ||||
| constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos, | ||||
|                                size_t size) { | ||||
|   return {{&s[pos], size}}; | ||||
| } | ||||
|  | ||||
| template <typename Char> struct code_unit { | ||||
|   Char value; | ||||
|   using char_type = Char; | ||||
|  | ||||
|   template <typename OutputIt, typename... Args> | ||||
|   constexpr OutputIt format(OutputIt out, const Args&...) const { | ||||
|     *out++ = value; | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| // This ensures that the argument type is convertible to `const T&`. | ||||
| template <typename T, int N, typename... Args> | ||||
| constexpr const T& get_arg_checked(const Args&... args) { | ||||
|   const auto& arg = detail::get<N>(args...); | ||||
|   if constexpr (detail::is_named_arg<remove_cvref_t<decltype(arg)>>()) { | ||||
|     return arg.value; | ||||
|   } else { | ||||
|     return arg; | ||||
|   } | ||||
| } | ||||
|  | ||||
| template <typename Char> | ||||
| struct is_compiled_format<code_unit<Char>> : std::true_type {}; | ||||
|  | ||||
| // A replacement field that refers to argument N. | ||||
| template <typename Char, typename T, int N> struct field { | ||||
|   using char_type = Char; | ||||
|  | ||||
|   template <typename OutputIt, typename... Args> | ||||
|   constexpr OutputIt format(OutputIt out, const Args&... args) const { | ||||
|     const T& arg = get_arg_checked<T, N>(args...); | ||||
|     if constexpr (std::is_convertible_v<T, basic_string_view<Char>>) { | ||||
|       auto s = basic_string_view<Char>(arg); | ||||
|       return copy_str<Char>(s.begin(), s.end(), out); | ||||
|     } | ||||
|     return write<Char>(out, arg); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename Char, typename T, int N> | ||||
| struct is_compiled_format<field<Char, T, N>> : std::true_type {}; | ||||
|  | ||||
| // A replacement field that refers to argument with name. | ||||
| template <typename Char> struct runtime_named_field { | ||||
|   using char_type = Char; | ||||
|   basic_string_view<Char> name; | ||||
|  | ||||
|   template <typename OutputIt, typename T> | ||||
|   constexpr static bool try_format_argument( | ||||
|       OutputIt& out, | ||||
|       // [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9 | ||||
|       [[maybe_unused]] basic_string_view<Char> arg_name, const T& arg) { | ||||
|     if constexpr (is_named_arg<typename std::remove_cv<T>::type>::value) { | ||||
|       if (arg_name == arg.name) { | ||||
|         out = write<Char>(out, arg.value); | ||||
|         return true; | ||||
|       } | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   template <typename OutputIt, typename... Args> | ||||
|   constexpr OutputIt format(OutputIt out, const Args&... args) const { | ||||
|     bool found = (try_format_argument(out, name, args) || ...); | ||||
|     if (!found) { | ||||
|       FMT_THROW(format_error("argument with specified name is not found")); | ||||
|     } | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename Char> | ||||
| struct is_compiled_format<runtime_named_field<Char>> : std::true_type {}; | ||||
|  | ||||
| // A replacement field that refers to argument N and has format specifiers. | ||||
| template <typename Char, typename T, int N> struct spec_field { | ||||
|   using char_type = Char; | ||||
|   formatter<T, Char> fmt; | ||||
|  | ||||
|   template <typename OutputIt, typename... Args> | ||||
|   constexpr FMT_INLINE OutputIt format(OutputIt out, | ||||
|                                        const Args&... args) const { | ||||
|     const auto& vargs = | ||||
|         fmt::make_format_args<basic_format_context<OutputIt, Char>>(args...); | ||||
|     basic_format_context<OutputIt, Char> ctx(out, vargs); | ||||
|     return fmt.format(get_arg_checked<T, N>(args...), ctx); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename Char, typename T, int N> | ||||
| struct is_compiled_format<spec_field<Char, T, N>> : std::true_type {}; | ||||
|  | ||||
| template <typename L, typename R> struct concat { | ||||
|   L lhs; | ||||
|   R rhs; | ||||
|   using char_type = typename L::char_type; | ||||
|  | ||||
|   template <typename OutputIt, typename... Args> | ||||
|   constexpr OutputIt format(OutputIt out, const Args&... args) const { | ||||
|     out = lhs.format(out, args...); | ||||
|     return rhs.format(out, args...); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename L, typename R> | ||||
| struct is_compiled_format<concat<L, R>> : std::true_type {}; | ||||
|  | ||||
| template <typename L, typename R> | ||||
| constexpr concat<L, R> make_concat(L lhs, R rhs) { | ||||
|   return {lhs, rhs}; | ||||
| } | ||||
|  | ||||
| struct unknown_format {}; | ||||
|  | ||||
| template <typename Char> | ||||
| constexpr size_t parse_text(basic_string_view<Char> str, size_t pos) { | ||||
|   for (size_t size = str.size(); pos != size; ++pos) { | ||||
|     if (str[pos] == '{' || str[pos] == '}') break; | ||||
|   } | ||||
|   return pos; | ||||
| } | ||||
|  | ||||
| template <typename Args, size_t POS, int ID, typename S> | ||||
| constexpr auto compile_format_string(S format_str); | ||||
|  | ||||
| template <typename Args, size_t POS, int ID, typename T, typename S> | ||||
| constexpr auto parse_tail(T head, S format_str) { | ||||
|   if constexpr (POS != | ||||
|                 basic_string_view<typename S::char_type>(format_str).size()) { | ||||
|     constexpr auto tail = compile_format_string<Args, POS, ID>(format_str); | ||||
|     if constexpr (std::is_same<remove_cvref_t<decltype(tail)>, | ||||
|                                unknown_format>()) | ||||
|       return tail; | ||||
|     else | ||||
|       return make_concat(head, tail); | ||||
|   } else { | ||||
|     return head; | ||||
|   } | ||||
| } | ||||
|  | ||||
| template <typename T, typename Char> struct parse_specs_result { | ||||
|   formatter<T, Char> fmt; | ||||
|   size_t end; | ||||
|   int next_arg_id; | ||||
| }; | ||||
|  | ||||
| enum { manual_indexing_id = -1 }; | ||||
|  | ||||
| template <typename T, typename Char> | ||||
| constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str, | ||||
|                                                   size_t pos, int next_arg_id) { | ||||
|   str.remove_prefix(pos); | ||||
|   auto ctx = | ||||
|       compile_parse_context<Char>(str, max_value<int>(), nullptr, next_arg_id); | ||||
|   auto f = formatter<T, Char>(); | ||||
|   auto end = f.parse(ctx); | ||||
|   return {f, pos + fmt::detail::to_unsigned(end - str.data()), | ||||
|           next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()}; | ||||
| } | ||||
|  | ||||
| template <typename Char> struct arg_id_handler { | ||||
|   arg_ref<Char> arg_id; | ||||
|  | ||||
|   constexpr int on_auto() { | ||||
|     FMT_ASSERT(false, "handler cannot be used with automatic indexing"); | ||||
|     return 0; | ||||
|   } | ||||
|   constexpr int on_index(int id) { | ||||
|     arg_id = arg_ref<Char>(id); | ||||
|     return 0; | ||||
|   } | ||||
|   constexpr int on_name(basic_string_view<Char> id) { | ||||
|     arg_id = arg_ref<Char>(id); | ||||
|     return 0; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename Char> struct parse_arg_id_result { | ||||
|   arg_ref<Char> arg_id; | ||||
|   const Char* arg_id_end; | ||||
| }; | ||||
|  | ||||
| template <int ID, typename Char> | ||||
| constexpr auto parse_arg_id(const Char* begin, const Char* end) { | ||||
|   auto handler = arg_id_handler<Char>{arg_ref<Char>{}}; | ||||
|   auto arg_id_end = parse_arg_id(begin, end, handler); | ||||
|   return parse_arg_id_result<Char>{handler.arg_id, arg_id_end}; | ||||
| } | ||||
|  | ||||
| template <typename T, typename Enable = void> struct field_type { | ||||
|   using type = remove_cvref_t<T>; | ||||
| }; | ||||
|  | ||||
| template <typename T> | ||||
| struct field_type<T, enable_if_t<detail::is_named_arg<T>::value>> { | ||||
|   using type = remove_cvref_t<decltype(T::value)>; | ||||
| }; | ||||
|  | ||||
| template <typename T, typename Args, size_t END_POS, int ARG_INDEX, int NEXT_ID, | ||||
|           typename S> | ||||
| constexpr auto parse_replacement_field_then_tail(S format_str) { | ||||
|   using char_type = typename S::char_type; | ||||
|   constexpr auto str = basic_string_view<char_type>(format_str); | ||||
|   constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type(); | ||||
|   if constexpr (c == '}') { | ||||
|     return parse_tail<Args, END_POS + 1, NEXT_ID>( | ||||
|         field<char_type, typename field_type<T>::type, ARG_INDEX>(), | ||||
|         format_str); | ||||
|   } else if constexpr (c != ':') { | ||||
|     FMT_THROW(format_error("expected ':'")); | ||||
|   } else { | ||||
|     constexpr auto result = parse_specs<typename field_type<T>::type>( | ||||
|         str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID); | ||||
|     if constexpr (result.end >= str.size() || str[result.end] != '}') { | ||||
|       FMT_THROW(format_error("expected '}'")); | ||||
|       return 0; | ||||
|     } else { | ||||
|       return parse_tail<Args, result.end + 1, result.next_arg_id>( | ||||
|           spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{ | ||||
|               result.fmt}, | ||||
|           format_str); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Compiles a non-empty format string and returns the compiled representation | ||||
| // or unknown_format() on unrecognized input. | ||||
| template <typename Args, size_t POS, int ID, typename S> | ||||
| constexpr auto compile_format_string(S format_str) { | ||||
|   using char_type = typename S::char_type; | ||||
|   constexpr auto str = basic_string_view<char_type>(format_str); | ||||
|   if constexpr (str[POS] == '{') { | ||||
|     if constexpr (POS + 1 == str.size()) | ||||
|       FMT_THROW(format_error("unmatched '{' in format string")); | ||||
|     if constexpr (str[POS + 1] == '{') { | ||||
|       return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str); | ||||
|     } else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') { | ||||
|       static_assert(ID != manual_indexing_id, | ||||
|                     "cannot switch from manual to automatic argument indexing"); | ||||
|       constexpr auto next_id = | ||||
|           ID != manual_indexing_id ? ID + 1 : manual_indexing_id; | ||||
|       return parse_replacement_field_then_tail<get_type<ID, Args>, Args, | ||||
|                                                POS + 1, ID, next_id>( | ||||
|           format_str); | ||||
|     } else { | ||||
|       constexpr auto arg_id_result = | ||||
|           parse_arg_id<ID>(str.data() + POS + 1, str.data() + str.size()); | ||||
|       constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data(); | ||||
|       constexpr char_type c = | ||||
|           arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type(); | ||||
|       static_assert(c == '}' || c == ':', "missing '}' in format string"); | ||||
|       if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) { | ||||
|         static_assert( | ||||
|             ID == manual_indexing_id || ID == 0, | ||||
|             "cannot switch from automatic to manual argument indexing"); | ||||
|         constexpr auto arg_index = arg_id_result.arg_id.val.index; | ||||
|         return parse_replacement_field_then_tail<get_type<arg_index, Args>, | ||||
|                                                  Args, arg_id_end_pos, | ||||
|                                                  arg_index, manual_indexing_id>( | ||||
|             format_str); | ||||
|       } else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) { | ||||
|         constexpr auto arg_index = | ||||
|             get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{}); | ||||
|         if constexpr (arg_index >= 0) { | ||||
|           constexpr auto next_id = | ||||
|               ID != manual_indexing_id ? ID + 1 : manual_indexing_id; | ||||
|           return parse_replacement_field_then_tail< | ||||
|               decltype(get_type<arg_index, Args>::value), Args, arg_id_end_pos, | ||||
|               arg_index, next_id>(format_str); | ||||
|         } else if constexpr (c == '}') { | ||||
|           return parse_tail<Args, arg_id_end_pos + 1, ID>( | ||||
|               runtime_named_field<char_type>{arg_id_result.arg_id.val.name}, | ||||
|               format_str); | ||||
|         } else if constexpr (c == ':') { | ||||
|           return unknown_format();  // no type info for specs parsing | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } else if constexpr (str[POS] == '}') { | ||||
|     if constexpr (POS + 1 == str.size()) | ||||
|       FMT_THROW(format_error("unmatched '}' in format string")); | ||||
|     return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str); | ||||
|   } else { | ||||
|     constexpr auto end = parse_text(str, POS + 1); | ||||
|     if constexpr (end - POS > 1) { | ||||
|       return parse_tail<Args, end, ID>(make_text(str, POS, end - POS), | ||||
|                                        format_str); | ||||
|     } else { | ||||
|       return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]}, | ||||
|                                        format_str); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| template <typename... Args, typename S, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> | ||||
| constexpr auto compile(S format_str) { | ||||
|   constexpr auto str = basic_string_view<typename S::char_type>(format_str); | ||||
|   if constexpr (str.size() == 0) { | ||||
|     return detail::make_text(str, 0, 0); | ||||
|   } else { | ||||
|     constexpr auto result = | ||||
|         detail::compile_format_string<detail::type_list<Args...>, 0, 0>( | ||||
|             format_str); | ||||
|     return result; | ||||
|   } | ||||
| } | ||||
| #endif  // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) | ||||
| }  // namespace detail | ||||
|  | ||||
| FMT_BEGIN_EXPORT | ||||
|  | ||||
| #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) | ||||
|  | ||||
| template <typename CompiledFormat, typename... Args, | ||||
|           typename Char = typename CompiledFormat::char_type, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)> | ||||
| FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf, | ||||
|                                           const Args&... args) { | ||||
|   auto s = std::basic_string<Char>(); | ||||
|   cf.format(std::back_inserter(s), args...); | ||||
|   return s; | ||||
| } | ||||
|  | ||||
| template <typename OutputIt, typename CompiledFormat, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)> | ||||
| constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf, | ||||
|                                         const Args&... args) { | ||||
|   return cf.format(out, args...); | ||||
| } | ||||
|  | ||||
| template <typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> | ||||
| FMT_INLINE std::basic_string<typename S::char_type> format(const S&, | ||||
|                                                            Args&&... args) { | ||||
|   if constexpr (std::is_same<typename S::char_type, char>::value) { | ||||
|     constexpr auto str = basic_string_view<typename S::char_type>(S()); | ||||
|     if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') { | ||||
|       const auto& first = detail::first(args...); | ||||
|       if constexpr (detail::is_named_arg< | ||||
|                         remove_cvref_t<decltype(first)>>::value) { | ||||
|         return fmt::to_string(first.value); | ||||
|       } else { | ||||
|         return fmt::to_string(first); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   constexpr auto compiled = detail::compile<Args...>(S()); | ||||
|   if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>, | ||||
|                              detail::unknown_format>()) { | ||||
|     return fmt::format( | ||||
|         static_cast<basic_string_view<typename S::char_type>>(S()), | ||||
|         std::forward<Args>(args)...); | ||||
|   } else { | ||||
|     return fmt::format(compiled, std::forward<Args>(args)...); | ||||
|   } | ||||
| } | ||||
|  | ||||
| template <typename OutputIt, typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> | ||||
| FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) { | ||||
|   constexpr auto compiled = detail::compile<Args...>(S()); | ||||
|   if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>, | ||||
|                              detail::unknown_format>()) { | ||||
|     return fmt::format_to( | ||||
|         out, static_cast<basic_string_view<typename S::char_type>>(S()), | ||||
|         std::forward<Args>(args)...); | ||||
|   } else { | ||||
|     return fmt::format_to(out, compiled, std::forward<Args>(args)...); | ||||
|   } | ||||
| } | ||||
| #endif | ||||
|  | ||||
| template <typename OutputIt, typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> | ||||
| auto format_to_n(OutputIt out, size_t n, const S& format_str, Args&&... args) | ||||
|     -> format_to_n_result<OutputIt> { | ||||
|   using traits = detail::fixed_buffer_traits; | ||||
|   auto buf = detail::iterator_buffer<OutputIt, char, traits>(out, n); | ||||
|   fmt::format_to(std::back_inserter(buf), format_str, | ||||
|                  std::forward<Args>(args)...); | ||||
|   return {buf.out(), buf.count()}; | ||||
| } | ||||
|  | ||||
| template <typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> | ||||
| FMT_CONSTEXPR20 auto formatted_size(const S& format_str, const Args&... args) | ||||
|     -> size_t { | ||||
|   return fmt::format_to(detail::counting_iterator(), format_str, args...) | ||||
|       .count(); | ||||
| } | ||||
|  | ||||
| template <typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> | ||||
| void print(std::FILE* f, const S& format_str, const Args&... args) { | ||||
|   memory_buffer buffer; | ||||
|   fmt::format_to(std::back_inserter(buffer), format_str, args...); | ||||
|   detail::print(f, {buffer.data(), buffer.size()}); | ||||
| } | ||||
|  | ||||
| template <typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> | ||||
| void print(const S& format_str, const Args&... args) { | ||||
|   print(stdout, format_str, args...); | ||||
| } | ||||
|  | ||||
| #if FMT_USE_NONTYPE_TEMPLATE_ARGS | ||||
| inline namespace literals { | ||||
| template <detail_exported::fixed_string Str> constexpr auto operator""_cf() { | ||||
|   using char_t = remove_cvref_t<decltype(Str.data[0])>; | ||||
|   return detail::udl_compiled_string<char_t, sizeof(Str.data) / sizeof(char_t), | ||||
|                                      Str>(); | ||||
| } | ||||
| }  // namespace literals | ||||
| #endif | ||||
|  | ||||
| FMT_END_EXPORT | ||||
| FMT_END_NAMESPACE | ||||
|  | ||||
| #endif  // FMT_COMPILE_H_ | ||||
							
								
								
									
										2969
									
								
								dep/fmt/include/fmt/core.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2969
									
								
								dep/fmt/include/fmt/core.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1678
									
								
								dep/fmt/include/fmt/format-inl.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1678
									
								
								dep/fmt/include/fmt/format-inl.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										4535
									
								
								dep/fmt/include/fmt/format.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4535
									
								
								dep/fmt/include/fmt/format.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										455
									
								
								dep/fmt/include/fmt/os.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										455
									
								
								dep/fmt/include/fmt/os.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,455 @@ | ||||
| // Formatting library for C++ - optional OS-specific functionality | ||||
| // | ||||
| // Copyright (c) 2012 - present, Victor Zverovich | ||||
| // All rights reserved. | ||||
| // | ||||
| // For the license information refer to format.h. | ||||
|  | ||||
| #ifndef FMT_OS_H_ | ||||
| #define FMT_OS_H_ | ||||
|  | ||||
| #include <cerrno> | ||||
| #include <cstddef> | ||||
| #include <cstdio> | ||||
| #include <system_error>  // std::system_error | ||||
|  | ||||
| #include "format.h" | ||||
|  | ||||
| #if defined __APPLE__ || defined(__FreeBSD__) | ||||
| #  if FMT_HAS_INCLUDE(<xlocale.h>) | ||||
| #    include <xlocale.h>  // for LC_NUMERIC_MASK on OS X | ||||
| #  endif | ||||
| #endif | ||||
|  | ||||
| #ifndef FMT_USE_FCNTL | ||||
| // UWP doesn't provide _pipe. | ||||
| #  if FMT_HAS_INCLUDE("winapifamily.h") | ||||
| #    include <winapifamily.h> | ||||
| #  endif | ||||
| #  if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \ | ||||
|        defined(__linux__)) &&                              \ | ||||
|       (!defined(WINAPI_FAMILY) ||                          \ | ||||
|        (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) | ||||
| #    include <fcntl.h>  // for O_RDONLY | ||||
| #    define FMT_USE_FCNTL 1 | ||||
| #  else | ||||
| #    define FMT_USE_FCNTL 0 | ||||
| #  endif | ||||
| #endif | ||||
|  | ||||
| #ifndef FMT_POSIX | ||||
| #  if defined(_WIN32) && !defined(__MINGW32__) | ||||
| // Fix warnings about deprecated symbols. | ||||
| #    define FMT_POSIX(call) _##call | ||||
| #  else | ||||
| #    define FMT_POSIX(call) call | ||||
| #  endif | ||||
| #endif | ||||
|  | ||||
| // Calls to system functions are wrapped in FMT_SYSTEM for testability. | ||||
| #ifdef FMT_SYSTEM | ||||
| #  define FMT_HAS_SYSTEM | ||||
| #  define FMT_POSIX_CALL(call) FMT_SYSTEM(call) | ||||
| #else | ||||
| #  define FMT_SYSTEM(call) ::call | ||||
| #  ifdef _WIN32 | ||||
| // Fix warnings about deprecated symbols. | ||||
| #    define FMT_POSIX_CALL(call) ::_##call | ||||
| #  else | ||||
| #    define FMT_POSIX_CALL(call) ::call | ||||
| #  endif | ||||
| #endif | ||||
|  | ||||
| // Retries the expression while it evaluates to error_result and errno | ||||
| // equals to EINTR. | ||||
| #ifndef _WIN32 | ||||
| #  define FMT_RETRY_VAL(result, expression, error_result) \ | ||||
|     do {                                                  \ | ||||
|       (result) = (expression);                            \ | ||||
|     } while ((result) == (error_result) && errno == EINTR) | ||||
| #else | ||||
| #  define FMT_RETRY_VAL(result, expression, error_result) result = (expression) | ||||
| #endif | ||||
|  | ||||
| #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) | ||||
|  | ||||
| FMT_BEGIN_NAMESPACE | ||||
| FMT_BEGIN_EXPORT | ||||
|  | ||||
| /** | ||||
|   \rst | ||||
|   A reference to a null-terminated string. It can be constructed from a C | ||||
|   string or ``std::string``. | ||||
|  | ||||
|   You can use one of the following type aliases for common character types: | ||||
|  | ||||
|   +---------------+-----------------------------+ | ||||
|   | Type          | Definition                  | | ||||
|   +===============+=============================+ | ||||
|   | cstring_view  | basic_cstring_view<char>    | | ||||
|   +---------------+-----------------------------+ | ||||
|   | wcstring_view | basic_cstring_view<wchar_t> | | ||||
|   +---------------+-----------------------------+ | ||||
|  | ||||
|   This class is most useful as a parameter type to allow passing | ||||
|   different types of strings to a function, for example:: | ||||
|  | ||||
|     template <typename... Args> | ||||
|     std::string format(cstring_view format_str, const Args & ... args); | ||||
|  | ||||
|     format("{}", 42); | ||||
|     format(std::string("{}"), 42); | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename Char> class basic_cstring_view { | ||||
|  private: | ||||
|   const Char* data_; | ||||
|  | ||||
|  public: | ||||
|   /** Constructs a string reference object from a C string. */ | ||||
|   basic_cstring_view(const Char* s) : data_(s) {} | ||||
|  | ||||
|   /** | ||||
|     \rst | ||||
|     Constructs a string reference from an ``std::string`` object. | ||||
|     \endrst | ||||
|    */ | ||||
|   basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {} | ||||
|  | ||||
|   /** Returns the pointer to a C string. */ | ||||
|   auto c_str() const -> const Char* { return data_; } | ||||
| }; | ||||
|  | ||||
| using cstring_view = basic_cstring_view<char>; | ||||
| using wcstring_view = basic_cstring_view<wchar_t>; | ||||
|  | ||||
| #ifdef _WIN32 | ||||
| FMT_API const std::error_category& system_category() noexcept; | ||||
|  | ||||
| namespace detail { | ||||
| FMT_API void format_windows_error(buffer<char>& out, int error_code, | ||||
|                                   const char* message) noexcept; | ||||
| } | ||||
|  | ||||
| FMT_API std::system_error vwindows_error(int error_code, string_view format_str, | ||||
|                                          format_args args); | ||||
|  | ||||
| /** | ||||
|  \rst | ||||
|  Constructs a :class:`std::system_error` object with the description | ||||
|  of the form | ||||
|  | ||||
|  .. parsed-literal:: | ||||
|    *<message>*: *<system-message>* | ||||
|  | ||||
|  where *<message>* is the formatted message and *<system-message>* is the | ||||
|  system message corresponding to the error code. | ||||
|  *error_code* is a Windows error code as given by ``GetLastError``. | ||||
|  If *error_code* is not a valid error code such as -1, the system message | ||||
|  will look like "error -1". | ||||
|  | ||||
|  **Example**:: | ||||
|  | ||||
|    // This throws a system_error with the description | ||||
|    //   cannot open file 'madeup': The system cannot find the file specified. | ||||
|    // or similar (system message may vary). | ||||
|    const char *filename = "madeup"; | ||||
|    LPOFSTRUCT of = LPOFSTRUCT(); | ||||
|    HFILE file = OpenFile(filename, &of, OF_READ); | ||||
|    if (file == HFILE_ERROR) { | ||||
|      throw fmt::windows_error(GetLastError(), | ||||
|                               "cannot open file '{}'", filename); | ||||
|    } | ||||
|  \endrst | ||||
| */ | ||||
| template <typename... Args> | ||||
| std::system_error windows_error(int error_code, string_view message, | ||||
|                                 const Args&... args) { | ||||
|   return vwindows_error(error_code, message, fmt::make_format_args(args...)); | ||||
| } | ||||
|  | ||||
| // Reports a Windows error without throwing an exception. | ||||
| // Can be used to report errors from destructors. | ||||
| FMT_API void report_windows_error(int error_code, const char* message) noexcept; | ||||
| #else | ||||
| inline auto system_category() noexcept -> const std::error_category& { | ||||
|   return std::system_category(); | ||||
| } | ||||
| #endif  // _WIN32 | ||||
|  | ||||
| // std::system is not available on some platforms such as iOS (#2248). | ||||
| #ifdef __OSX__ | ||||
| template <typename S, typename... Args, typename Char = char_t<S>> | ||||
| void say(const S& format_str, Args&&... args) { | ||||
|   std::system(format("say \"{}\"", format(format_str, args...)).c_str()); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| // A buffered file. | ||||
| class buffered_file { | ||||
|  private: | ||||
|   FILE* file_; | ||||
|  | ||||
|   friend class file; | ||||
|  | ||||
|   explicit buffered_file(FILE* f) : file_(f) {} | ||||
|  | ||||
|  public: | ||||
|   buffered_file(const buffered_file&) = delete; | ||||
|   void operator=(const buffered_file&) = delete; | ||||
|  | ||||
|   // Constructs a buffered_file object which doesn't represent any file. | ||||
|   buffered_file() noexcept : file_(nullptr) {} | ||||
|  | ||||
|   // Destroys the object closing the file it represents if any. | ||||
|   FMT_API ~buffered_file() noexcept; | ||||
|  | ||||
|  public: | ||||
|   buffered_file(buffered_file&& other) noexcept : file_(other.file_) { | ||||
|     other.file_ = nullptr; | ||||
|   } | ||||
|  | ||||
|   auto operator=(buffered_file&& other) -> buffered_file& { | ||||
|     close(); | ||||
|     file_ = other.file_; | ||||
|     other.file_ = nullptr; | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   // Opens a file. | ||||
|   FMT_API buffered_file(cstring_view filename, cstring_view mode); | ||||
|  | ||||
|   // Closes the file. | ||||
|   FMT_API void close(); | ||||
|  | ||||
|   // Returns the pointer to a FILE object representing this file. | ||||
|   auto get() const noexcept -> FILE* { return file_; } | ||||
|  | ||||
|   FMT_API auto descriptor() const -> int; | ||||
|  | ||||
|   void vprint(string_view format_str, format_args args) { | ||||
|     fmt::vprint(file_, format_str, args); | ||||
|   } | ||||
|  | ||||
|   template <typename... Args> | ||||
|   inline void print(string_view format_str, const Args&... args) { | ||||
|     vprint(format_str, fmt::make_format_args(args...)); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| #if FMT_USE_FCNTL | ||||
| // A file. Closed file is represented by a file object with descriptor -1. | ||||
| // Methods that are not declared with noexcept may throw | ||||
| // fmt::system_error in case of failure. Note that some errors such as | ||||
| // closing the file multiple times will cause a crash on Windows rather | ||||
| // than an exception. You can get standard behavior by overriding the | ||||
| // invalid parameter handler with _set_invalid_parameter_handler. | ||||
| class FMT_API file { | ||||
|  private: | ||||
|   int fd_;  // File descriptor. | ||||
|  | ||||
|   // Constructs a file object with a given descriptor. | ||||
|   explicit file(int fd) : fd_(fd) {} | ||||
|  | ||||
|  public: | ||||
|   // Possible values for the oflag argument to the constructor. | ||||
|   enum { | ||||
|     RDONLY = FMT_POSIX(O_RDONLY),  // Open for reading only. | ||||
|     WRONLY = FMT_POSIX(O_WRONLY),  // Open for writing only. | ||||
|     RDWR = FMT_POSIX(O_RDWR),      // Open for reading and writing. | ||||
|     CREATE = FMT_POSIX(O_CREAT),   // Create if the file doesn't exist. | ||||
|     APPEND = FMT_POSIX(O_APPEND),  // Open in append mode. | ||||
|     TRUNC = FMT_POSIX(O_TRUNC)     // Truncate the content of the file. | ||||
|   }; | ||||
|  | ||||
|   // Constructs a file object which doesn't represent any file. | ||||
|   file() noexcept : fd_(-1) {} | ||||
|  | ||||
|   // Opens a file and constructs a file object representing this file. | ||||
|   file(cstring_view path, int oflag); | ||||
|  | ||||
|  public: | ||||
|   file(const file&) = delete; | ||||
|   void operator=(const file&) = delete; | ||||
|  | ||||
|   file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; } | ||||
|  | ||||
|   // Move assignment is not noexcept because close may throw. | ||||
|   auto operator=(file&& other) -> file& { | ||||
|     close(); | ||||
|     fd_ = other.fd_; | ||||
|     other.fd_ = -1; | ||||
|     return *this; | ||||
|   } | ||||
|  | ||||
|   // Destroys the object closing the file it represents if any. | ||||
|   ~file() noexcept; | ||||
|  | ||||
|   // Returns the file descriptor. | ||||
|   auto descriptor() const noexcept -> int { return fd_; } | ||||
|  | ||||
|   // Closes the file. | ||||
|   void close(); | ||||
|  | ||||
|   // Returns the file size. The size has signed type for consistency with | ||||
|   // stat::st_size. | ||||
|   auto size() const -> long long; | ||||
|  | ||||
|   // Attempts to read count bytes from the file into the specified buffer. | ||||
|   auto read(void* buffer, size_t count) -> size_t; | ||||
|  | ||||
|   // Attempts to write count bytes from the specified buffer to the file. | ||||
|   auto write(const void* buffer, size_t count) -> size_t; | ||||
|  | ||||
|   // Duplicates a file descriptor with the dup function and returns | ||||
|   // the duplicate as a file object. | ||||
|   static auto dup(int fd) -> file; | ||||
|  | ||||
|   // Makes fd be the copy of this file descriptor, closing fd first if | ||||
|   // necessary. | ||||
|   void dup2(int fd); | ||||
|  | ||||
|   // Makes fd be the copy of this file descriptor, closing fd first if | ||||
|   // necessary. | ||||
|   void dup2(int fd, std::error_code& ec) noexcept; | ||||
|  | ||||
|   // Creates a pipe setting up read_end and write_end file objects for reading | ||||
|   // and writing respectively. | ||||
|   // DEPRECATED! Taking files as out parameters is deprecated. | ||||
|   static void pipe(file& read_end, file& write_end); | ||||
|  | ||||
|   // Creates a buffered_file object associated with this file and detaches | ||||
|   // this file object from the file. | ||||
|   auto fdopen(const char* mode) -> buffered_file; | ||||
|  | ||||
| #  if defined(_WIN32) && !defined(__MINGW32__) | ||||
|   // Opens a file and constructs a file object representing this file by | ||||
|   // wcstring_view filename. Windows only. | ||||
|   static file open_windows_file(wcstring_view path, int oflag); | ||||
| #  endif | ||||
| }; | ||||
|  | ||||
| // Returns the memory page size. | ||||
| auto getpagesize() -> long; | ||||
|  | ||||
| namespace detail { | ||||
|  | ||||
| struct buffer_size { | ||||
|   buffer_size() = default; | ||||
|   size_t value = 0; | ||||
|   auto operator=(size_t val) const -> buffer_size { | ||||
|     auto bs = buffer_size(); | ||||
|     bs.value = val; | ||||
|     return bs; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| struct ostream_params { | ||||
|   int oflag = file::WRONLY | file::CREATE | file::TRUNC; | ||||
|   size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768; | ||||
|  | ||||
|   ostream_params() {} | ||||
|  | ||||
|   template <typename... T> | ||||
|   ostream_params(T... params, int new_oflag) : ostream_params(params...) { | ||||
|     oflag = new_oflag; | ||||
|   } | ||||
|  | ||||
|   template <typename... T> | ||||
|   ostream_params(T... params, detail::buffer_size bs) | ||||
|       : ostream_params(params...) { | ||||
|     this->buffer_size = bs.value; | ||||
|   } | ||||
|  | ||||
| // Intel has a bug that results in failure to deduce a constructor | ||||
| // for empty parameter packs. | ||||
| #  if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000 | ||||
|   ostream_params(int new_oflag) : oflag(new_oflag) {} | ||||
|   ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {} | ||||
| #  endif | ||||
| }; | ||||
|  | ||||
| class file_buffer final : public buffer<char> { | ||||
|   file file_; | ||||
|  | ||||
|   FMT_API void grow(size_t) override; | ||||
|  | ||||
|  public: | ||||
|   FMT_API file_buffer(cstring_view path, const ostream_params& params); | ||||
|   FMT_API file_buffer(file_buffer&& other); | ||||
|   FMT_API ~file_buffer(); | ||||
|  | ||||
|   void flush() { | ||||
|     if (size() == 0) return; | ||||
|     file_.write(data(), size() * sizeof(data()[0])); | ||||
|     clear(); | ||||
|   } | ||||
|  | ||||
|   void close() { | ||||
|     flush(); | ||||
|     file_.close(); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| }  // namespace detail | ||||
|  | ||||
| // Added {} below to work around default constructor error known to | ||||
| // occur in Xcode versions 7.2.1 and 8.2.1. | ||||
| constexpr detail::buffer_size buffer_size{}; | ||||
|  | ||||
| /** A fast output stream which is not thread-safe. */ | ||||
| class FMT_API ostream { | ||||
|  private: | ||||
|   FMT_MSC_WARNING(suppress : 4251) | ||||
|   detail::file_buffer buffer_; | ||||
|  | ||||
|   ostream(cstring_view path, const detail::ostream_params& params) | ||||
|       : buffer_(path, params) {} | ||||
|  | ||||
|  public: | ||||
|   ostream(ostream&& other) : buffer_(std::move(other.buffer_)) {} | ||||
|  | ||||
|   ~ostream(); | ||||
|  | ||||
|   void flush() { buffer_.flush(); } | ||||
|  | ||||
|   template <typename... T> | ||||
|   friend auto output_file(cstring_view path, T... params) -> ostream; | ||||
|  | ||||
|   void close() { buffer_.close(); } | ||||
|  | ||||
|   /** | ||||
|     Formats ``args`` according to specifications in ``fmt`` and writes the | ||||
|     output to the file. | ||||
|    */ | ||||
|   template <typename... T> void print(format_string<T...> fmt, T&&... args) { | ||||
|     vformat_to(std::back_inserter(buffer_), fmt, | ||||
|                fmt::make_format_args(args...)); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| /** | ||||
|   \rst | ||||
|   Opens a file for writing. Supported parameters passed in *params*: | ||||
|  | ||||
|   * ``<integer>``: Flags passed to `open | ||||
|     <https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_ | ||||
|     (``file::WRONLY | file::CREATE | file::TRUNC`` by default) | ||||
|   * ``buffer_size=<integer>``: Output buffer size | ||||
|  | ||||
|   **Example**:: | ||||
|  | ||||
|     auto out = fmt::output_file("guide.txt"); | ||||
|     out.print("Don't {}", "Panic"); | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename... T> | ||||
| inline auto output_file(cstring_view path, T... params) -> ostream { | ||||
|   return {path, detail::ostream_params(params...)}; | ||||
| } | ||||
| #endif  // FMT_USE_FCNTL | ||||
|  | ||||
| FMT_END_EXPORT | ||||
| FMT_END_NAMESPACE | ||||
|  | ||||
| #endif  // FMT_OS_H_ | ||||
							
								
								
									
										245
									
								
								dep/fmt/include/fmt/ostream.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										245
									
								
								dep/fmt/include/fmt/ostream.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,245 @@ | ||||
| // Formatting library for C++ - std::ostream support | ||||
| // | ||||
| // Copyright (c) 2012 - present, Victor Zverovich | ||||
| // All rights reserved. | ||||
| // | ||||
| // For the license information refer to format.h. | ||||
|  | ||||
| #ifndef FMT_OSTREAM_H_ | ||||
| #define FMT_OSTREAM_H_ | ||||
|  | ||||
| #include <fstream>  // std::filebuf | ||||
|  | ||||
| #ifdef _WIN32 | ||||
| #  ifdef __GLIBCXX__ | ||||
| #    include <ext/stdio_filebuf.h> | ||||
| #    include <ext/stdio_sync_filebuf.h> | ||||
| #  endif | ||||
| #  include <io.h> | ||||
| #endif | ||||
|  | ||||
| #include "format.h" | ||||
|  | ||||
| FMT_BEGIN_NAMESPACE | ||||
| namespace detail { | ||||
|  | ||||
| template <typename Streambuf> class formatbuf : public Streambuf { | ||||
|  private: | ||||
|   using char_type = typename Streambuf::char_type; | ||||
|   using streamsize = decltype(std::declval<Streambuf>().sputn(nullptr, 0)); | ||||
|   using int_type = typename Streambuf::int_type; | ||||
|   using traits_type = typename Streambuf::traits_type; | ||||
|  | ||||
|   buffer<char_type>& buffer_; | ||||
|  | ||||
|  public: | ||||
|   explicit formatbuf(buffer<char_type>& buf) : buffer_(buf) {} | ||||
|  | ||||
|  protected: | ||||
|   // The put area is always empty. This makes the implementation simpler and has | ||||
|   // the advantage that the streambuf and the buffer are always in sync and | ||||
|   // sputc never writes into uninitialized memory. A disadvantage is that each | ||||
|   // call to sputc always results in a (virtual) call to overflow. There is no | ||||
|   // disadvantage here for sputn since this always results in a call to xsputn. | ||||
|  | ||||
|   auto overflow(int_type ch) -> int_type override { | ||||
|     if (!traits_type::eq_int_type(ch, traits_type::eof())) | ||||
|       buffer_.push_back(static_cast<char_type>(ch)); | ||||
|     return ch; | ||||
|   } | ||||
|  | ||||
|   auto xsputn(const char_type* s, streamsize count) -> streamsize override { | ||||
|     buffer_.append(s, s + count); | ||||
|     return count; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| // Generate a unique explicit instantion in every translation unit using a tag | ||||
| // type in an anonymous namespace. | ||||
| namespace { | ||||
| struct file_access_tag {}; | ||||
| }  // namespace | ||||
| template <typename Tag, typename BufType, FILE* BufType::*FileMemberPtr> | ||||
| class file_access { | ||||
|   friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; } | ||||
| }; | ||||
|  | ||||
| #if FMT_MSC_VERSION | ||||
| template class file_access<file_access_tag, std::filebuf, | ||||
|                            &std::filebuf::_Myfile>; | ||||
| auto get_file(std::filebuf&) -> FILE*; | ||||
| #endif | ||||
|  | ||||
| inline auto write_ostream_unicode(std::ostream& os, fmt::string_view data) | ||||
|     -> bool { | ||||
|   FILE* f = nullptr; | ||||
| #if FMT_MSC_VERSION | ||||
|   if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf())) | ||||
|     f = get_file(*buf); | ||||
|   else | ||||
|     return false; | ||||
| #elif defined(_WIN32) && defined(__GLIBCXX__) | ||||
|   auto* rdbuf = os.rdbuf(); | ||||
|   if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf)) | ||||
|     f = sfbuf->file(); | ||||
|   else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf)) | ||||
|     f = fbuf->file(); | ||||
|   else | ||||
|     return false; | ||||
| #else | ||||
|   ignore_unused(os, data, f); | ||||
| #endif | ||||
| #ifdef _WIN32 | ||||
|   if (f) { | ||||
|     int fd = _fileno(f); | ||||
|     if (_isatty(fd)) { | ||||
|       os.flush(); | ||||
|       return write_console(fd, data); | ||||
|     } | ||||
|   } | ||||
| #endif | ||||
|   return false; | ||||
| } | ||||
| inline auto write_ostream_unicode(std::wostream&, | ||||
|                                   fmt::basic_string_view<wchar_t>) -> bool { | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| // Write the content of buf to os. | ||||
| // It is a separate function rather than a part of vprint to simplify testing. | ||||
| template <typename Char> | ||||
| void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) { | ||||
|   const Char* buf_data = buf.data(); | ||||
|   using unsigned_streamsize = std::make_unsigned<std::streamsize>::type; | ||||
|   unsigned_streamsize size = buf.size(); | ||||
|   unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>()); | ||||
|   do { | ||||
|     unsigned_streamsize n = size <= max_size ? size : max_size; | ||||
|     os.write(buf_data, static_cast<std::streamsize>(n)); | ||||
|     buf_data += n; | ||||
|     size -= n; | ||||
|   } while (size != 0); | ||||
| } | ||||
|  | ||||
| template <typename Char, typename T> | ||||
| void format_value(buffer<Char>& buf, const T& value) { | ||||
|   auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf); | ||||
|   auto&& output = std::basic_ostream<Char>(&format_buf); | ||||
| #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) | ||||
|   output.imbue(std::locale::classic());  // The default is always unlocalized. | ||||
| #endif | ||||
|   output << value; | ||||
|   output.exceptions(std::ios_base::failbit | std::ios_base::badbit); | ||||
| } | ||||
|  | ||||
| template <typename T> struct streamed_view { | ||||
|   const T& value; | ||||
| }; | ||||
|  | ||||
| }  // namespace detail | ||||
|  | ||||
| // Formats an object of type T that has an overloaded ostream operator<<. | ||||
| template <typename Char> | ||||
| struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> { | ||||
|   void set_debug_format() = delete; | ||||
|  | ||||
|   template <typename T, typename OutputIt> | ||||
|   auto format(const T& value, basic_format_context<OutputIt, Char>& ctx) const | ||||
|       -> OutputIt { | ||||
|     auto buffer = basic_memory_buffer<Char>(); | ||||
|     detail::format_value(buffer, value); | ||||
|     return formatter<basic_string_view<Char>, Char>::format( | ||||
|         {buffer.data(), buffer.size()}, ctx); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| using ostream_formatter = basic_ostream_formatter<char>; | ||||
|  | ||||
| template <typename T, typename Char> | ||||
| struct formatter<detail::streamed_view<T>, Char> | ||||
|     : basic_ostream_formatter<Char> { | ||||
|   template <typename OutputIt> | ||||
|   auto format(detail::streamed_view<T> view, | ||||
|               basic_format_context<OutputIt, Char>& ctx) const -> OutputIt { | ||||
|     return basic_ostream_formatter<Char>::format(view.value, ctx); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| /** | ||||
|   \rst | ||||
|   Returns a view that formats `value` via an ostream ``operator<<``. | ||||
|  | ||||
|   **Example**:: | ||||
|  | ||||
|     fmt::print("Current thread id: {}\n", | ||||
|                fmt::streamed(std::this_thread::get_id())); | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename T> | ||||
| constexpr auto streamed(const T& value) -> detail::streamed_view<T> { | ||||
|   return {value}; | ||||
| } | ||||
|  | ||||
| namespace detail { | ||||
|  | ||||
| inline void vprint_directly(std::ostream& os, string_view format_str, | ||||
|                             format_args args) { | ||||
|   auto buffer = memory_buffer(); | ||||
|   detail::vformat_to(buffer, format_str, args); | ||||
|   detail::write_buffer(os, buffer); | ||||
| } | ||||
|  | ||||
| }  // namespace detail | ||||
|  | ||||
| FMT_EXPORT template <typename Char> | ||||
| void vprint(std::basic_ostream<Char>& os, | ||||
|             basic_string_view<type_identity_t<Char>> format_str, | ||||
|             basic_format_args<buffer_context<type_identity_t<Char>>> args) { | ||||
|   auto buffer = basic_memory_buffer<Char>(); | ||||
|   detail::vformat_to(buffer, format_str, args); | ||||
|   if (detail::write_ostream_unicode(os, {buffer.data(), buffer.size()})) return; | ||||
|   detail::write_buffer(os, buffer); | ||||
| } | ||||
|  | ||||
| /** | ||||
|   \rst | ||||
|   Prints formatted data to the stream *os*. | ||||
|  | ||||
|   **Example**:: | ||||
|  | ||||
|     fmt::print(cerr, "Don't {}!", "panic"); | ||||
|   \endrst | ||||
|  */ | ||||
| FMT_EXPORT template <typename... T> | ||||
| void print(std::ostream& os, format_string<T...> fmt, T&&... args) { | ||||
|   const auto& vargs = fmt::make_format_args(args...); | ||||
|   if (detail::is_utf8()) | ||||
|     vprint(os, fmt, vargs); | ||||
|   else | ||||
|     detail::vprint_directly(os, fmt, vargs); | ||||
| } | ||||
|  | ||||
| FMT_EXPORT | ||||
| template <typename... Args> | ||||
| void print(std::wostream& os, | ||||
|            basic_format_string<wchar_t, type_identity_t<Args>...> fmt, | ||||
|            Args&&... args) { | ||||
|   vprint(os, fmt, fmt::make_format_args<buffer_context<wchar_t>>(args...)); | ||||
| } | ||||
|  | ||||
| FMT_EXPORT template <typename... T> | ||||
| void println(std::ostream& os, format_string<T...> fmt, T&&... args) { | ||||
|   fmt::print(os, "{}\n", fmt::format(fmt, std::forward<T>(args)...)); | ||||
| } | ||||
|  | ||||
| FMT_EXPORT | ||||
| template <typename... Args> | ||||
| void println(std::wostream& os, | ||||
|              basic_format_string<wchar_t, type_identity_t<Args>...> fmt, | ||||
|              Args&&... args) { | ||||
|   print(os, L"{}\n", fmt::format(fmt, std::forward<Args>(args)...)); | ||||
| } | ||||
|  | ||||
| FMT_END_NAMESPACE | ||||
|  | ||||
| #endif  // FMT_OSTREAM_H_ | ||||
							
								
								
									
										675
									
								
								dep/fmt/include/fmt/printf.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										675
									
								
								dep/fmt/include/fmt/printf.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,675 @@ | ||||
| // Formatting library for C++ - legacy printf implementation | ||||
| // | ||||
| // Copyright (c) 2012 - 2016, Victor Zverovich | ||||
| // All rights reserved. | ||||
| // | ||||
| // For the license information refer to format.h. | ||||
|  | ||||
| #ifndef FMT_PRINTF_H_ | ||||
| #define FMT_PRINTF_H_ | ||||
|  | ||||
| #include <algorithm>  // std::max | ||||
| #include <limits>     // std::numeric_limits | ||||
|  | ||||
| #include "format.h" | ||||
|  | ||||
| FMT_BEGIN_NAMESPACE | ||||
| FMT_BEGIN_EXPORT | ||||
|  | ||||
| template <typename T> struct printf_formatter { | ||||
|   printf_formatter() = delete; | ||||
| }; | ||||
|  | ||||
| template <typename Char> class basic_printf_context { | ||||
|  private: | ||||
|   detail::buffer_appender<Char> out_; | ||||
|   basic_format_args<basic_printf_context> args_; | ||||
|  | ||||
|   static_assert(std::is_same<Char, char>::value || | ||||
|                     std::is_same<Char, wchar_t>::value, | ||||
|                 "Unsupported code unit type."); | ||||
|  | ||||
|  public: | ||||
|   using char_type = Char; | ||||
|   using parse_context_type = basic_format_parse_context<Char>; | ||||
|   template <typename T> using formatter_type = printf_formatter<T>; | ||||
|  | ||||
|   /** | ||||
|     \rst | ||||
|     Constructs a ``printf_context`` object. References to the arguments are | ||||
|     stored in the context object so make sure they have appropriate lifetimes. | ||||
|     \endrst | ||||
|    */ | ||||
|   basic_printf_context(detail::buffer_appender<Char> out, | ||||
|                        basic_format_args<basic_printf_context> args) | ||||
|       : out_(out), args_(args) {} | ||||
|  | ||||
|   auto out() -> detail::buffer_appender<Char> { return out_; } | ||||
|   void advance_to(detail::buffer_appender<Char>) {} | ||||
|  | ||||
|   auto locale() -> detail::locale_ref { return {}; } | ||||
|  | ||||
|   auto arg(int id) const -> basic_format_arg<basic_printf_context> { | ||||
|     return args_.get(id); | ||||
|   } | ||||
|  | ||||
|   FMT_CONSTEXPR void on_error(const char* message) { | ||||
|     detail::error_handler().on_error(message); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| namespace detail { | ||||
|  | ||||
| // Checks if a value fits in int - used to avoid warnings about comparing | ||||
| // signed and unsigned integers. | ||||
| template <bool IsSigned> struct int_checker { | ||||
|   template <typename T> static auto fits_in_int(T value) -> bool { | ||||
|     unsigned max = max_value<int>(); | ||||
|     return value <= max; | ||||
|   } | ||||
|   static auto fits_in_int(bool) -> bool { return true; } | ||||
| }; | ||||
|  | ||||
| template <> struct int_checker<true> { | ||||
|   template <typename T> static auto fits_in_int(T value) -> bool { | ||||
|     return value >= (std::numeric_limits<int>::min)() && | ||||
|            value <= max_value<int>(); | ||||
|   } | ||||
|   static auto fits_in_int(int) -> bool { return true; } | ||||
| }; | ||||
|  | ||||
| struct printf_precision_handler { | ||||
|   template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> | ||||
|   auto operator()(T value) -> int { | ||||
|     if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) | ||||
|       throw_format_error("number is too big"); | ||||
|     return (std::max)(static_cast<int>(value), 0); | ||||
|   } | ||||
|  | ||||
|   template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> | ||||
|   auto operator()(T) -> int { | ||||
|     throw_format_error("precision is not integer"); | ||||
|     return 0; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| // An argument visitor that returns true iff arg is a zero integer. | ||||
| struct is_zero_int { | ||||
|   template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> | ||||
|   auto operator()(T value) -> bool { | ||||
|     return value == 0; | ||||
|   } | ||||
|  | ||||
|   template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> | ||||
|   auto operator()(T) -> bool { | ||||
|     return false; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename T> struct make_unsigned_or_bool : std::make_unsigned<T> {}; | ||||
|  | ||||
| template <> struct make_unsigned_or_bool<bool> { | ||||
|   using type = bool; | ||||
| }; | ||||
|  | ||||
| template <typename T, typename Context> class arg_converter { | ||||
|  private: | ||||
|   using char_type = typename Context::char_type; | ||||
|  | ||||
|   basic_format_arg<Context>& arg_; | ||||
|   char_type type_; | ||||
|  | ||||
|  public: | ||||
|   arg_converter(basic_format_arg<Context>& arg, char_type type) | ||||
|       : arg_(arg), type_(type) {} | ||||
|  | ||||
|   void operator()(bool value) { | ||||
|     if (type_ != 's') operator()<bool>(value); | ||||
|   } | ||||
|  | ||||
|   template <typename U, FMT_ENABLE_IF(std::is_integral<U>::value)> | ||||
|   void operator()(U value) { | ||||
|     bool is_signed = type_ == 'd' || type_ == 'i'; | ||||
|     using target_type = conditional_t<std::is_same<T, void>::value, U, T>; | ||||
|     if (const_check(sizeof(target_type) <= sizeof(int))) { | ||||
|       // Extra casts are used to silence warnings. | ||||
|       if (is_signed) { | ||||
|         auto n = static_cast<int>(static_cast<target_type>(value)); | ||||
|         arg_ = detail::make_arg<Context>(n); | ||||
|       } else { | ||||
|         using unsigned_type = typename make_unsigned_or_bool<target_type>::type; | ||||
|         auto n = static_cast<unsigned>(static_cast<unsigned_type>(value)); | ||||
|         arg_ = detail::make_arg<Context>(n); | ||||
|       } | ||||
|     } else { | ||||
|       if (is_signed) { | ||||
|         // glibc's printf doesn't sign extend arguments of smaller types: | ||||
|         //   std::printf("%lld", -42);  // prints "4294967254" | ||||
|         // but we don't have to do the same because it's a UB. | ||||
|         auto n = static_cast<long long>(value); | ||||
|         arg_ = detail::make_arg<Context>(n); | ||||
|       } else { | ||||
|         auto n = static_cast<typename make_unsigned_or_bool<U>::type>(value); | ||||
|         arg_ = detail::make_arg<Context>(n); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   template <typename U, FMT_ENABLE_IF(!std::is_integral<U>::value)> | ||||
|   void operator()(U) {}  // No conversion needed for non-integral types. | ||||
| }; | ||||
|  | ||||
| // Converts an integer argument to T for printf, if T is an integral type. | ||||
| // If T is void, the argument is converted to corresponding signed or unsigned | ||||
| // type depending on the type specifier: 'd' and 'i' - signed, other - | ||||
| // unsigned). | ||||
| template <typename T, typename Context, typename Char> | ||||
| void convert_arg(basic_format_arg<Context>& arg, Char type) { | ||||
|   visit_format_arg(arg_converter<T, Context>(arg, type), arg); | ||||
| } | ||||
|  | ||||
| // Converts an integer argument to char for printf. | ||||
| template <typename Context> class char_converter { | ||||
|  private: | ||||
|   basic_format_arg<Context>& arg_; | ||||
|  | ||||
|  public: | ||||
|   explicit char_converter(basic_format_arg<Context>& arg) : arg_(arg) {} | ||||
|  | ||||
|   template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> | ||||
|   void operator()(T value) { | ||||
|     auto c = static_cast<typename Context::char_type>(value); | ||||
|     arg_ = detail::make_arg<Context>(c); | ||||
|   } | ||||
|  | ||||
|   template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> | ||||
|   void operator()(T) {}  // No conversion needed for non-integral types. | ||||
| }; | ||||
|  | ||||
| // An argument visitor that return a pointer to a C string if argument is a | ||||
| // string or null otherwise. | ||||
| template <typename Char> struct get_cstring { | ||||
|   template <typename T> auto operator()(T) -> const Char* { return nullptr; } | ||||
|   auto operator()(const Char* s) -> const Char* { return s; } | ||||
| }; | ||||
|  | ||||
| // Checks if an argument is a valid printf width specifier and sets | ||||
| // left alignment if it is negative. | ||||
| template <typename Char> class printf_width_handler { | ||||
|  private: | ||||
|   format_specs<Char>& specs_; | ||||
|  | ||||
|  public: | ||||
|   explicit printf_width_handler(format_specs<Char>& specs) : specs_(specs) {} | ||||
|  | ||||
|   template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> | ||||
|   auto operator()(T value) -> unsigned { | ||||
|     auto width = static_cast<uint32_or_64_or_128_t<T>>(value); | ||||
|     if (detail::is_negative(value)) { | ||||
|       specs_.align = align::left; | ||||
|       width = 0 - width; | ||||
|     } | ||||
|     unsigned int_max = max_value<int>(); | ||||
|     if (width > int_max) throw_format_error("number is too big"); | ||||
|     return static_cast<unsigned>(width); | ||||
|   } | ||||
|  | ||||
|   template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> | ||||
|   auto operator()(T) -> unsigned { | ||||
|     throw_format_error("width is not integer"); | ||||
|     return 0; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| // Workaround for a bug with the XL compiler when initializing | ||||
| // printf_arg_formatter's base class. | ||||
| template <typename Char> | ||||
| auto make_arg_formatter(buffer_appender<Char> iter, format_specs<Char>& s) | ||||
|     -> arg_formatter<Char> { | ||||
|   return {iter, s, locale_ref()}; | ||||
| } | ||||
|  | ||||
| // The ``printf`` argument formatter. | ||||
| template <typename Char> | ||||
| class printf_arg_formatter : public arg_formatter<Char> { | ||||
|  private: | ||||
|   using base = arg_formatter<Char>; | ||||
|   using context_type = basic_printf_context<Char>; | ||||
|  | ||||
|   context_type& context_; | ||||
|  | ||||
|   void write_null_pointer(bool is_string = false) { | ||||
|     auto s = this->specs; | ||||
|     s.type = presentation_type::none; | ||||
|     write_bytes(this->out, is_string ? "(null)" : "(nil)", s); | ||||
|   } | ||||
|  | ||||
|  public: | ||||
|   printf_arg_formatter(buffer_appender<Char> iter, format_specs<Char>& s, | ||||
|                        context_type& ctx) | ||||
|       : base(make_arg_formatter(iter, s)), context_(ctx) {} | ||||
|  | ||||
|   void operator()(monostate value) { base::operator()(value); } | ||||
|  | ||||
|   template <typename T, FMT_ENABLE_IF(detail::is_integral<T>::value)> | ||||
|   void operator()(T value) { | ||||
|     // MSVC2013 fails to compile separate overloads for bool and Char so use | ||||
|     // std::is_same instead. | ||||
|     if (!std::is_same<T, Char>::value) { | ||||
|       base::operator()(value); | ||||
|       return; | ||||
|     } | ||||
|     format_specs<Char> fmt_specs = this->specs; | ||||
|     if (fmt_specs.type != presentation_type::none && | ||||
|         fmt_specs.type != presentation_type::chr) { | ||||
|       return (*this)(static_cast<int>(value)); | ||||
|     } | ||||
|     fmt_specs.sign = sign::none; | ||||
|     fmt_specs.alt = false; | ||||
|     fmt_specs.fill[0] = ' ';  // Ignore '0' flag for char types. | ||||
|     // align::numeric needs to be overwritten here since the '0' flag is | ||||
|     // ignored for non-numeric types | ||||
|     if (fmt_specs.align == align::none || fmt_specs.align == align::numeric) | ||||
|       fmt_specs.align = align::right; | ||||
|     write<Char>(this->out, static_cast<Char>(value), fmt_specs); | ||||
|   } | ||||
|  | ||||
|   template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)> | ||||
|   void operator()(T value) { | ||||
|     base::operator()(value); | ||||
|   } | ||||
|  | ||||
|   /** Formats a null-terminated C string. */ | ||||
|   void operator()(const char* value) { | ||||
|     if (value) | ||||
|       base::operator()(value); | ||||
|     else | ||||
|       write_null_pointer(this->specs.type != presentation_type::pointer); | ||||
|   } | ||||
|  | ||||
|   /** Formats a null-terminated wide C string. */ | ||||
|   void operator()(const wchar_t* value) { | ||||
|     if (value) | ||||
|       base::operator()(value); | ||||
|     else | ||||
|       write_null_pointer(this->specs.type != presentation_type::pointer); | ||||
|   } | ||||
|  | ||||
|   void operator()(basic_string_view<Char> value) { base::operator()(value); } | ||||
|  | ||||
|   /** Formats a pointer. */ | ||||
|   void operator()(const void* value) { | ||||
|     if (value) | ||||
|       base::operator()(value); | ||||
|     else | ||||
|       write_null_pointer(); | ||||
|   } | ||||
|  | ||||
|   /** Formats an argument of a custom (user-defined) type. */ | ||||
|   void operator()(typename basic_format_arg<context_type>::handle handle) { | ||||
|     auto parse_ctx = basic_format_parse_context<Char>({}); | ||||
|     handle.format(parse_ctx, context_); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename Char> | ||||
| void parse_flags(format_specs<Char>& specs, const Char*& it, const Char* end) { | ||||
|   for (; it != end; ++it) { | ||||
|     switch (*it) { | ||||
|     case '-': | ||||
|       specs.align = align::left; | ||||
|       break; | ||||
|     case '+': | ||||
|       specs.sign = sign::plus; | ||||
|       break; | ||||
|     case '0': | ||||
|       specs.fill[0] = '0'; | ||||
|       break; | ||||
|     case ' ': | ||||
|       if (specs.sign != sign::plus) specs.sign = sign::space; | ||||
|       break; | ||||
|     case '#': | ||||
|       specs.alt = true; | ||||
|       break; | ||||
|     default: | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| template <typename Char, typename GetArg> | ||||
| auto parse_header(const Char*& it, const Char* end, format_specs<Char>& specs, | ||||
|                   GetArg get_arg) -> int { | ||||
|   int arg_index = -1; | ||||
|   Char c = *it; | ||||
|   if (c >= '0' && c <= '9') { | ||||
|     // Parse an argument index (if followed by '$') or a width possibly | ||||
|     // preceded with '0' flag(s). | ||||
|     int value = parse_nonnegative_int(it, end, -1); | ||||
|     if (it != end && *it == '$') {  // value is an argument index | ||||
|       ++it; | ||||
|       arg_index = value != -1 ? value : max_value<int>(); | ||||
|     } else { | ||||
|       if (c == '0') specs.fill[0] = '0'; | ||||
|       if (value != 0) { | ||||
|         // Nonzero value means that we parsed width and don't need to | ||||
|         // parse it or flags again, so return now. | ||||
|         if (value == -1) throw_format_error("number is too big"); | ||||
|         specs.width = value; | ||||
|         return arg_index; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   parse_flags(specs, it, end); | ||||
|   // Parse width. | ||||
|   if (it != end) { | ||||
|     if (*it >= '0' && *it <= '9') { | ||||
|       specs.width = parse_nonnegative_int(it, end, -1); | ||||
|       if (specs.width == -1) throw_format_error("number is too big"); | ||||
|     } else if (*it == '*') { | ||||
|       ++it; | ||||
|       specs.width = static_cast<int>(visit_format_arg( | ||||
|           detail::printf_width_handler<Char>(specs), get_arg(-1))); | ||||
|     } | ||||
|   } | ||||
|   return arg_index; | ||||
| } | ||||
|  | ||||
| inline auto parse_printf_presentation_type(char c, type t) | ||||
|     -> presentation_type { | ||||
|   using pt = presentation_type; | ||||
|   constexpr auto integral_set = sint_set | uint_set | bool_set | char_set; | ||||
|   switch (c) { | ||||
|   case 'd': | ||||
|     return in(t, integral_set) ? pt::dec : pt::none; | ||||
|   case 'o': | ||||
|     return in(t, integral_set) ? pt::oct : pt::none; | ||||
|   case 'x': | ||||
|     return in(t, integral_set) ? pt::hex_lower : pt::none; | ||||
|   case 'X': | ||||
|     return in(t, integral_set) ? pt::hex_upper : pt::none; | ||||
|   case 'a': | ||||
|     return in(t, float_set) ? pt::hexfloat_lower : pt::none; | ||||
|   case 'A': | ||||
|     return in(t, float_set) ? pt::hexfloat_upper : pt::none; | ||||
|   case 'e': | ||||
|     return in(t, float_set) ? pt::exp_lower : pt::none; | ||||
|   case 'E': | ||||
|     return in(t, float_set) ? pt::exp_upper : pt::none; | ||||
|   case 'f': | ||||
|     return in(t, float_set) ? pt::fixed_lower : pt::none; | ||||
|   case 'F': | ||||
|     return in(t, float_set) ? pt::fixed_upper : pt::none; | ||||
|   case 'g': | ||||
|     return in(t, float_set) ? pt::general_lower : pt::none; | ||||
|   case 'G': | ||||
|     return in(t, float_set) ? pt::general_upper : pt::none; | ||||
|   case 'c': | ||||
|     return in(t, integral_set) ? pt::chr : pt::none; | ||||
|   case 's': | ||||
|     return in(t, string_set | cstring_set) ? pt::string : pt::none; | ||||
|   case 'p': | ||||
|     return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none; | ||||
|   default: | ||||
|     return pt::none; | ||||
|   } | ||||
| } | ||||
|  | ||||
| template <typename Char, typename Context> | ||||
| void vprintf(buffer<Char>& buf, basic_string_view<Char> format, | ||||
|              basic_format_args<Context> args) { | ||||
|   using iterator = buffer_appender<Char>; | ||||
|   auto out = iterator(buf); | ||||
|   auto context = basic_printf_context<Char>(out, args); | ||||
|   auto parse_ctx = basic_format_parse_context<Char>(format); | ||||
|  | ||||
|   // Returns the argument with specified index or, if arg_index is -1, the next | ||||
|   // argument. | ||||
|   auto get_arg = [&](int arg_index) { | ||||
|     if (arg_index < 0) | ||||
|       arg_index = parse_ctx.next_arg_id(); | ||||
|     else | ||||
|       parse_ctx.check_arg_id(--arg_index); | ||||
|     return detail::get_arg(context, arg_index); | ||||
|   }; | ||||
|  | ||||
|   const Char* start = parse_ctx.begin(); | ||||
|   const Char* end = parse_ctx.end(); | ||||
|   auto it = start; | ||||
|   while (it != end) { | ||||
|     if (!find<false, Char>(it, end, '%', it)) { | ||||
|       it = end;  // find leaves it == nullptr if it doesn't find '%'. | ||||
|       break; | ||||
|     } | ||||
|     Char c = *it++; | ||||
|     if (it != end && *it == c) { | ||||
|       write(out, basic_string_view<Char>(start, to_unsigned(it - start))); | ||||
|       start = ++it; | ||||
|       continue; | ||||
|     } | ||||
|     write(out, basic_string_view<Char>(start, to_unsigned(it - 1 - start))); | ||||
|  | ||||
|     auto specs = format_specs<Char>(); | ||||
|     specs.align = align::right; | ||||
|  | ||||
|     // Parse argument index, flags and width. | ||||
|     int arg_index = parse_header(it, end, specs, get_arg); | ||||
|     if (arg_index == 0) throw_format_error("argument not found"); | ||||
|  | ||||
|     // Parse precision. | ||||
|     if (it != end && *it == '.') { | ||||
|       ++it; | ||||
|       c = it != end ? *it : 0; | ||||
|       if ('0' <= c && c <= '9') { | ||||
|         specs.precision = parse_nonnegative_int(it, end, 0); | ||||
|       } else if (c == '*') { | ||||
|         ++it; | ||||
|         specs.precision = static_cast<int>( | ||||
|             visit_format_arg(printf_precision_handler(), get_arg(-1))); | ||||
|       } else { | ||||
|         specs.precision = 0; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     auto arg = get_arg(arg_index); | ||||
|     // For d, i, o, u, x, and X conversion specifiers, if a precision is | ||||
|     // specified, the '0' flag is ignored | ||||
|     if (specs.precision >= 0 && arg.is_integral()) { | ||||
|       // Ignore '0' for non-numeric types or if '-' present. | ||||
|       specs.fill[0] = ' '; | ||||
|     } | ||||
|     if (specs.precision >= 0 && arg.type() == type::cstring_type) { | ||||
|       auto str = visit_format_arg(get_cstring<Char>(), arg); | ||||
|       auto str_end = str + specs.precision; | ||||
|       auto nul = std::find(str, str_end, Char()); | ||||
|       auto sv = basic_string_view<Char>( | ||||
|           str, to_unsigned(nul != str_end ? nul - str : specs.precision)); | ||||
|       arg = make_arg<basic_printf_context<Char>>(sv); | ||||
|     } | ||||
|     if (specs.alt && visit_format_arg(is_zero_int(), arg)) specs.alt = false; | ||||
|     if (specs.fill[0] == '0') { | ||||
|       if (arg.is_arithmetic() && specs.align != align::left) | ||||
|         specs.align = align::numeric; | ||||
|       else | ||||
|         specs.fill[0] = ' ';  // Ignore '0' flag for non-numeric types or if '-' | ||||
|                               // flag is also present. | ||||
|     } | ||||
|  | ||||
|     // Parse length and convert the argument to the required type. | ||||
|     c = it != end ? *it++ : 0; | ||||
|     Char t = it != end ? *it : 0; | ||||
|     switch (c) { | ||||
|     case 'h': | ||||
|       if (t == 'h') { | ||||
|         ++it; | ||||
|         t = it != end ? *it : 0; | ||||
|         convert_arg<signed char>(arg, t); | ||||
|       } else { | ||||
|         convert_arg<short>(arg, t); | ||||
|       } | ||||
|       break; | ||||
|     case 'l': | ||||
|       if (t == 'l') { | ||||
|         ++it; | ||||
|         t = it != end ? *it : 0; | ||||
|         convert_arg<long long>(arg, t); | ||||
|       } else { | ||||
|         convert_arg<long>(arg, t); | ||||
|       } | ||||
|       break; | ||||
|     case 'j': | ||||
|       convert_arg<intmax_t>(arg, t); | ||||
|       break; | ||||
|     case 'z': | ||||
|       convert_arg<size_t>(arg, t); | ||||
|       break; | ||||
|     case 't': | ||||
|       convert_arg<std::ptrdiff_t>(arg, t); | ||||
|       break; | ||||
|     case 'L': | ||||
|       // printf produces garbage when 'L' is omitted for long double, no | ||||
|       // need to do the same. | ||||
|       break; | ||||
|     default: | ||||
|       --it; | ||||
|       convert_arg<void>(arg, c); | ||||
|     } | ||||
|  | ||||
|     // Parse type. | ||||
|     if (it == end) throw_format_error("invalid format string"); | ||||
|     char type = static_cast<char>(*it++); | ||||
|     if (arg.is_integral()) { | ||||
|       // Normalize type. | ||||
|       switch (type) { | ||||
|       case 'i': | ||||
|       case 'u': | ||||
|         type = 'd'; | ||||
|         break; | ||||
|       case 'c': | ||||
|         visit_format_arg(char_converter<basic_printf_context<Char>>(arg), arg); | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|     specs.type = parse_printf_presentation_type(type, arg.type()); | ||||
|     if (specs.type == presentation_type::none) | ||||
|       throw_format_error("invalid format specifier"); | ||||
|  | ||||
|     start = it; | ||||
|  | ||||
|     // Format argument. | ||||
|     visit_format_arg(printf_arg_formatter<Char>(out, specs, context), arg); | ||||
|   } | ||||
|   write(out, basic_string_view<Char>(start, to_unsigned(it - start))); | ||||
| } | ||||
| }  // namespace detail | ||||
|  | ||||
| using printf_context = basic_printf_context<char>; | ||||
| using wprintf_context = basic_printf_context<wchar_t>; | ||||
|  | ||||
| using printf_args = basic_format_args<printf_context>; | ||||
| using wprintf_args = basic_format_args<wprintf_context>; | ||||
|  | ||||
| /** | ||||
|   \rst | ||||
|   Constructs an `~fmt::format_arg_store` object that contains references to | ||||
|   arguments and can be implicitly converted to `~fmt::printf_args`. | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename... T> | ||||
| inline auto make_printf_args(const T&... args) | ||||
|     -> format_arg_store<printf_context, T...> { | ||||
|   return {args...}; | ||||
| } | ||||
|  | ||||
| // DEPRECATED! | ||||
| template <typename... T> | ||||
| inline auto make_wprintf_args(const T&... args) | ||||
|     -> format_arg_store<wprintf_context, T...> { | ||||
|   return {args...}; | ||||
| } | ||||
|  | ||||
| template <typename Char> | ||||
| inline auto vsprintf( | ||||
|     basic_string_view<Char> fmt, | ||||
|     basic_format_args<basic_printf_context<type_identity_t<Char>>> args) | ||||
|     -> std::basic_string<Char> { | ||||
|   auto buf = basic_memory_buffer<Char>(); | ||||
|   detail::vprintf(buf, fmt, args); | ||||
|   return to_string(buf); | ||||
| } | ||||
|  | ||||
| /** | ||||
|   \rst | ||||
|   Formats arguments and returns the result as a string. | ||||
|  | ||||
|   **Example**:: | ||||
|  | ||||
|     std::string message = fmt::sprintf("The answer is %d", 42); | ||||
|   \endrst | ||||
| */ | ||||
| template <typename S, typename... T, | ||||
|           typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>> | ||||
| inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> { | ||||
|   return vsprintf(detail::to_string_view(fmt), | ||||
|                   fmt::make_format_args<basic_printf_context<Char>>(args...)); | ||||
| } | ||||
|  | ||||
| template <typename Char> | ||||
| inline auto vfprintf( | ||||
|     std::FILE* f, basic_string_view<Char> fmt, | ||||
|     basic_format_args<basic_printf_context<type_identity_t<Char>>> args) | ||||
|     -> int { | ||||
|   auto buf = basic_memory_buffer<Char>(); | ||||
|   detail::vprintf(buf, fmt, args); | ||||
|   size_t size = buf.size(); | ||||
|   return std::fwrite(buf.data(), sizeof(Char), size, f) < size | ||||
|              ? -1 | ||||
|              : static_cast<int>(size); | ||||
| } | ||||
|  | ||||
| /** | ||||
|   \rst | ||||
|   Prints formatted data to the file *f*. | ||||
|  | ||||
|   **Example**:: | ||||
|  | ||||
|     fmt::fprintf(stderr, "Don't %s!", "panic"); | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename S, typename... T, typename Char = char_t<S>> | ||||
| inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int { | ||||
|   return vfprintf(f, detail::to_string_view(fmt), | ||||
|                   fmt::make_format_args<basic_printf_context<Char>>(args...)); | ||||
| } | ||||
|  | ||||
| template <typename Char> | ||||
| FMT_DEPRECATED inline auto vprintf( | ||||
|     basic_string_view<Char> fmt, | ||||
|     basic_format_args<basic_printf_context<type_identity_t<Char>>> args) | ||||
|     -> int { | ||||
|   return vfprintf(stdout, fmt, args); | ||||
| } | ||||
|  | ||||
| /** | ||||
|   \rst | ||||
|   Prints formatted data to ``stdout``. | ||||
|  | ||||
|   **Example**:: | ||||
|  | ||||
|     fmt::printf("Elapsed time: %.2f seconds", 1.23); | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename... T> | ||||
| inline auto printf(string_view fmt, const T&... args) -> int { | ||||
|   return vfprintf(stdout, fmt, make_printf_args(args...)); | ||||
| } | ||||
| template <typename... T> | ||||
| FMT_DEPRECATED inline auto printf(basic_string_view<wchar_t> fmt, | ||||
|                                   const T&... args) -> int { | ||||
|   return vfprintf(stdout, fmt, make_wprintf_args(args...)); | ||||
| } | ||||
|  | ||||
| FMT_END_EXPORT | ||||
| FMT_END_NAMESPACE | ||||
|  | ||||
| #endif  // FMT_PRINTF_H_ | ||||
							
								
								
									
										738
									
								
								dep/fmt/include/fmt/ranges.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										738
									
								
								dep/fmt/include/fmt/ranges.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,738 @@ | ||||
| // Formatting library for C++ - range and tuple support | ||||
| // | ||||
| // Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors | ||||
| // All rights reserved. | ||||
| // | ||||
| // For the license information refer to format.h. | ||||
|  | ||||
| #ifndef FMT_RANGES_H_ | ||||
| #define FMT_RANGES_H_ | ||||
|  | ||||
| #include <initializer_list> | ||||
| #include <tuple> | ||||
| #include <type_traits> | ||||
|  | ||||
| #include "format.h" | ||||
|  | ||||
| FMT_BEGIN_NAMESPACE | ||||
|  | ||||
| namespace detail { | ||||
|  | ||||
| template <typename Range, typename OutputIt> | ||||
| auto copy(const Range& range, OutputIt out) -> OutputIt { | ||||
|   for (auto it = range.begin(), end = range.end(); it != end; ++it) | ||||
|     *out++ = *it; | ||||
|   return out; | ||||
| } | ||||
|  | ||||
| template <typename OutputIt> | ||||
| auto copy(const char* str, OutputIt out) -> OutputIt { | ||||
|   while (*str) *out++ = *str++; | ||||
|   return out; | ||||
| } | ||||
|  | ||||
| template <typename OutputIt> auto copy(char ch, OutputIt out) -> OutputIt { | ||||
|   *out++ = ch; | ||||
|   return out; | ||||
| } | ||||
|  | ||||
| template <typename OutputIt> auto copy(wchar_t ch, OutputIt out) -> OutputIt { | ||||
|   *out++ = ch; | ||||
|   return out; | ||||
| } | ||||
|  | ||||
| // Returns true if T has a std::string-like interface, like std::string_view. | ||||
| template <typename T> class is_std_string_like { | ||||
|   template <typename U> | ||||
|   static auto check(U* p) | ||||
|       -> decltype((void)p->find('a'), p->length(), (void)p->data(), int()); | ||||
|   template <typename> static void check(...); | ||||
|  | ||||
|  public: | ||||
|   static constexpr const bool value = | ||||
|       is_string<T>::value || | ||||
|       std::is_convertible<T, std_string_view<char>>::value || | ||||
|       !std::is_void<decltype(check<T>(nullptr))>::value; | ||||
| }; | ||||
|  | ||||
| template <typename Char> | ||||
| struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {}; | ||||
|  | ||||
| template <typename T> class is_map { | ||||
|   template <typename U> static auto check(U*) -> typename U::mapped_type; | ||||
|   template <typename> static void check(...); | ||||
|  | ||||
|  public: | ||||
| #ifdef FMT_FORMAT_MAP_AS_LIST  // DEPRECATED! | ||||
|   static constexpr const bool value = false; | ||||
| #else | ||||
|   static constexpr const bool value = | ||||
|       !std::is_void<decltype(check<T>(nullptr))>::value; | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| template <typename T> class is_set { | ||||
|   template <typename U> static auto check(U*) -> typename U::key_type; | ||||
|   template <typename> static void check(...); | ||||
|  | ||||
|  public: | ||||
| #ifdef FMT_FORMAT_SET_AS_LIST  // DEPRECATED! | ||||
|   static constexpr const bool value = false; | ||||
| #else | ||||
|   static constexpr const bool value = | ||||
|       !std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value; | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| template <typename... Ts> struct conditional_helper {}; | ||||
|  | ||||
| template <typename T, typename _ = void> struct is_range_ : std::false_type {}; | ||||
|  | ||||
| #if !FMT_MSC_VERSION || FMT_MSC_VERSION > 1800 | ||||
|  | ||||
| #  define FMT_DECLTYPE_RETURN(val)  \ | ||||
|     ->decltype(val) { return val; } \ | ||||
|     static_assert(                  \ | ||||
|         true, "")  // This makes it so that a semicolon is required after the | ||||
|                    // macro, which helps clang-format handle the formatting. | ||||
|  | ||||
| // C array overload | ||||
| template <typename T, std::size_t N> | ||||
| auto range_begin(const T (&arr)[N]) -> const T* { | ||||
|   return arr; | ||||
| } | ||||
| template <typename T, std::size_t N> | ||||
| auto range_end(const T (&arr)[N]) -> const T* { | ||||
|   return arr + N; | ||||
| } | ||||
|  | ||||
| template <typename T, typename Enable = void> | ||||
| struct has_member_fn_begin_end_t : std::false_type {}; | ||||
|  | ||||
| template <typename T> | ||||
| struct has_member_fn_begin_end_t<T, void_t<decltype(std::declval<T>().begin()), | ||||
|                                            decltype(std::declval<T>().end())>> | ||||
|     : std::true_type {}; | ||||
|  | ||||
| // Member function overload | ||||
| template <typename T> | ||||
| auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).begin()); | ||||
| template <typename T> | ||||
| auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).end()); | ||||
|  | ||||
| // ADL overload. Only participates in overload resolution if member functions | ||||
| // are not found. | ||||
| template <typename T> | ||||
| auto range_begin(T&& rng) | ||||
|     -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value, | ||||
|                    decltype(begin(static_cast<T&&>(rng)))> { | ||||
|   return begin(static_cast<T&&>(rng)); | ||||
| } | ||||
| template <typename T> | ||||
| auto range_end(T&& rng) -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value, | ||||
|                                        decltype(end(static_cast<T&&>(rng)))> { | ||||
|   return end(static_cast<T&&>(rng)); | ||||
| } | ||||
|  | ||||
| template <typename T, typename Enable = void> | ||||
| struct has_const_begin_end : std::false_type {}; | ||||
| template <typename T, typename Enable = void> | ||||
| struct has_mutable_begin_end : std::false_type {}; | ||||
|  | ||||
| template <typename T> | ||||
| struct has_const_begin_end< | ||||
|     T, | ||||
|     void_t< | ||||
|         decltype(detail::range_begin(std::declval<const remove_cvref_t<T>&>())), | ||||
|         decltype(detail::range_end(std::declval<const remove_cvref_t<T>&>()))>> | ||||
|     : std::true_type {}; | ||||
|  | ||||
| template <typename T> | ||||
| struct has_mutable_begin_end< | ||||
|     T, void_t<decltype(detail::range_begin(std::declval<T>())), | ||||
|               decltype(detail::range_end(std::declval<T>())), | ||||
|               // the extra int here is because older versions of MSVC don't | ||||
|               // SFINAE properly unless there are distinct types | ||||
|               int>> : std::true_type {}; | ||||
|  | ||||
| template <typename T> | ||||
| struct is_range_<T, void> | ||||
|     : std::integral_constant<bool, (has_const_begin_end<T>::value || | ||||
|                                     has_mutable_begin_end<T>::value)> {}; | ||||
| #  undef FMT_DECLTYPE_RETURN | ||||
| #endif | ||||
|  | ||||
| // tuple_size and tuple_element check. | ||||
| template <typename T> class is_tuple_like_ { | ||||
|   template <typename U> | ||||
|   static auto check(U* p) -> decltype(std::tuple_size<U>::value, int()); | ||||
|   template <typename> static void check(...); | ||||
|  | ||||
|  public: | ||||
|   static constexpr const bool value = | ||||
|       !std::is_void<decltype(check<T>(nullptr))>::value; | ||||
| }; | ||||
|  | ||||
| // Check for integer_sequence | ||||
| #if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900 | ||||
| template <typename T, T... N> | ||||
| using integer_sequence = std::integer_sequence<T, N...>; | ||||
| template <size_t... N> using index_sequence = std::index_sequence<N...>; | ||||
| template <size_t N> using make_index_sequence = std::make_index_sequence<N>; | ||||
| #else | ||||
| template <typename T, T... N> struct integer_sequence { | ||||
|   using value_type = T; | ||||
|  | ||||
|   static FMT_CONSTEXPR auto size() -> size_t { return sizeof...(N); } | ||||
| }; | ||||
|  | ||||
| template <size_t... N> using index_sequence = integer_sequence<size_t, N...>; | ||||
|  | ||||
| template <typename T, size_t N, T... Ns> | ||||
| struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {}; | ||||
| template <typename T, T... Ns> | ||||
| struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {}; | ||||
|  | ||||
| template <size_t N> | ||||
| using make_index_sequence = make_integer_sequence<size_t, N>; | ||||
| #endif | ||||
|  | ||||
| template <typename T> | ||||
| using tuple_index_sequence = make_index_sequence<std::tuple_size<T>::value>; | ||||
|  | ||||
| template <typename T, typename C, bool = is_tuple_like_<T>::value> | ||||
| class is_tuple_formattable_ { | ||||
|  public: | ||||
|   static constexpr const bool value = false; | ||||
| }; | ||||
| template <typename T, typename C> class is_tuple_formattable_<T, C, true> { | ||||
|   template <std::size_t... Is> | ||||
|   static auto check2(index_sequence<Is...>, | ||||
|                      integer_sequence<bool, (Is == Is)...>) -> std::true_type; | ||||
|   static auto check2(...) -> std::false_type; | ||||
|   template <std::size_t... Is> | ||||
|   static auto check(index_sequence<Is...>) -> decltype(check2( | ||||
|       index_sequence<Is...>{}, | ||||
|       integer_sequence<bool, | ||||
|                        (is_formattable<typename std::tuple_element<Is, T>::type, | ||||
|                                        C>::value)...>{})); | ||||
|  | ||||
|  public: | ||||
|   static constexpr const bool value = | ||||
|       decltype(check(tuple_index_sequence<T>{}))::value; | ||||
| }; | ||||
|  | ||||
| template <typename Tuple, typename F, size_t... Is> | ||||
| FMT_CONSTEXPR void for_each(index_sequence<Is...>, Tuple&& t, F&& f) { | ||||
|   using std::get; | ||||
|   // Using a free function get<Is>(Tuple) now. | ||||
|   const int unused[] = {0, ((void)f(get<Is>(t)), 0)...}; | ||||
|   ignore_unused(unused); | ||||
| } | ||||
|  | ||||
| template <typename Tuple, typename F> | ||||
| FMT_CONSTEXPR void for_each(Tuple&& t, F&& f) { | ||||
|   for_each(tuple_index_sequence<remove_cvref_t<Tuple>>(), | ||||
|            std::forward<Tuple>(t), std::forward<F>(f)); | ||||
| } | ||||
|  | ||||
| template <typename Tuple1, typename Tuple2, typename F, size_t... Is> | ||||
| void for_each2(index_sequence<Is...>, Tuple1&& t1, Tuple2&& t2, F&& f) { | ||||
|   using std::get; | ||||
|   const int unused[] = {0, ((void)f(get<Is>(t1), get<Is>(t2)), 0)...}; | ||||
|   ignore_unused(unused); | ||||
| } | ||||
|  | ||||
| template <typename Tuple1, typename Tuple2, typename F> | ||||
| void for_each2(Tuple1&& t1, Tuple2&& t2, F&& f) { | ||||
|   for_each2(tuple_index_sequence<remove_cvref_t<Tuple1>>(), | ||||
|             std::forward<Tuple1>(t1), std::forward<Tuple2>(t2), | ||||
|             std::forward<F>(f)); | ||||
| } | ||||
|  | ||||
| namespace tuple { | ||||
| // Workaround a bug in MSVC 2019 (v140). | ||||
| template <typename Char, typename... T> | ||||
| using result_t = std::tuple<formatter<remove_cvref_t<T>, Char>...>; | ||||
|  | ||||
| using std::get; | ||||
| template <typename Tuple, typename Char, std::size_t... Is> | ||||
| auto get_formatters(index_sequence<Is...>) | ||||
|     -> result_t<Char, decltype(get<Is>(std::declval<Tuple>()))...>; | ||||
| }  // namespace tuple | ||||
|  | ||||
| #if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920 | ||||
| // Older MSVC doesn't get the reference type correctly for arrays. | ||||
| template <typename R> struct range_reference_type_impl { | ||||
|   using type = decltype(*detail::range_begin(std::declval<R&>())); | ||||
| }; | ||||
|  | ||||
| template <typename T, std::size_t N> struct range_reference_type_impl<T[N]> { | ||||
|   using type = T&; | ||||
| }; | ||||
|  | ||||
| template <typename T> | ||||
| using range_reference_type = typename range_reference_type_impl<T>::type; | ||||
| #else | ||||
| template <typename Range> | ||||
| using range_reference_type = | ||||
|     decltype(*detail::range_begin(std::declval<Range&>())); | ||||
| #endif | ||||
|  | ||||
| // We don't use the Range's value_type for anything, but we do need the Range's | ||||
| // reference type, with cv-ref stripped. | ||||
| template <typename Range> | ||||
| using uncvref_type = remove_cvref_t<range_reference_type<Range>>; | ||||
|  | ||||
| template <typename Formatter> | ||||
| FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set) | ||||
|     -> decltype(f.set_debug_format(set)) { | ||||
|   f.set_debug_format(set); | ||||
| } | ||||
| template <typename Formatter> | ||||
| FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {} | ||||
|  | ||||
| // These are not generic lambdas for compatibility with C++11. | ||||
| template <typename ParseContext> struct parse_empty_specs { | ||||
|   template <typename Formatter> FMT_CONSTEXPR void operator()(Formatter& f) { | ||||
|     f.parse(ctx); | ||||
|     detail::maybe_set_debug_format(f, true); | ||||
|   } | ||||
|   ParseContext& ctx; | ||||
| }; | ||||
| template <typename FormatContext> struct format_tuple_element { | ||||
|   using char_type = typename FormatContext::char_type; | ||||
|  | ||||
|   template <typename T> | ||||
|   void operator()(const formatter<T, char_type>& f, const T& v) { | ||||
|     if (i > 0) | ||||
|       ctx.advance_to(detail::copy_str<char_type>(separator, ctx.out())); | ||||
|     ctx.advance_to(f.format(v, ctx)); | ||||
|     ++i; | ||||
|   } | ||||
|  | ||||
|   int i; | ||||
|   FormatContext& ctx; | ||||
|   basic_string_view<char_type> separator; | ||||
| }; | ||||
|  | ||||
| }  // namespace detail | ||||
|  | ||||
| template <typename T> struct is_tuple_like { | ||||
|   static constexpr const bool value = | ||||
|       detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value; | ||||
| }; | ||||
|  | ||||
| template <typename T, typename C> struct is_tuple_formattable { | ||||
|   static constexpr const bool value = | ||||
|       detail::is_tuple_formattable_<T, C>::value; | ||||
| }; | ||||
|  | ||||
| template <typename Tuple, typename Char> | ||||
| struct formatter<Tuple, Char, | ||||
|                  enable_if_t<fmt::is_tuple_like<Tuple>::value && | ||||
|                              fmt::is_tuple_formattable<Tuple, Char>::value>> { | ||||
|  private: | ||||
|   decltype(detail::tuple::get_formatters<Tuple, Char>( | ||||
|       detail::tuple_index_sequence<Tuple>())) formatters_; | ||||
|  | ||||
|   basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{}; | ||||
|   basic_string_view<Char> opening_bracket_ = | ||||
|       detail::string_literal<Char, '('>{}; | ||||
|   basic_string_view<Char> closing_bracket_ = | ||||
|       detail::string_literal<Char, ')'>{}; | ||||
|  | ||||
|  public: | ||||
|   FMT_CONSTEXPR formatter() {} | ||||
|  | ||||
|   FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) { | ||||
|     separator_ = sep; | ||||
|   } | ||||
|  | ||||
|   FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open, | ||||
|                                   basic_string_view<Char> close) { | ||||
|     opening_bracket_ = open; | ||||
|     closing_bracket_ = close; | ||||
|   } | ||||
|  | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|     auto it = ctx.begin(); | ||||
|     if (it != ctx.end() && *it != '}') | ||||
|       FMT_THROW(format_error("invalid format specifier")); | ||||
|     detail::for_each(formatters_, detail::parse_empty_specs<ParseContext>{ctx}); | ||||
|     return it; | ||||
|   } | ||||
|  | ||||
|   template <typename FormatContext> | ||||
|   auto format(const Tuple& value, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     ctx.advance_to(detail::copy_str<Char>(opening_bracket_, ctx.out())); | ||||
|     detail::for_each2( | ||||
|         formatters_, value, | ||||
|         detail::format_tuple_element<FormatContext>{0, ctx, separator_}); | ||||
|     return detail::copy_str<Char>(closing_bracket_, ctx.out()); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename T, typename Char> struct is_range { | ||||
|   static constexpr const bool value = | ||||
|       detail::is_range_<T>::value && !detail::is_std_string_like<T>::value && | ||||
|       !std::is_convertible<T, std::basic_string<Char>>::value && | ||||
|       !std::is_convertible<T, detail::std_string_view<Char>>::value; | ||||
| }; | ||||
|  | ||||
| namespace detail { | ||||
| template <typename Context> struct range_mapper { | ||||
|   using mapper = arg_mapper<Context>; | ||||
|  | ||||
|   template <typename T, | ||||
|             FMT_ENABLE_IF(has_formatter<remove_cvref_t<T>, Context>::value)> | ||||
|   static auto map(T&& value) -> T&& { | ||||
|     return static_cast<T&&>(value); | ||||
|   } | ||||
|   template <typename T, | ||||
|             FMT_ENABLE_IF(!has_formatter<remove_cvref_t<T>, Context>::value)> | ||||
|   static auto map(T&& value) | ||||
|       -> decltype(mapper().map(static_cast<T&&>(value))) { | ||||
|     return mapper().map(static_cast<T&&>(value)); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| template <typename Char, typename Element> | ||||
| using range_formatter_type = | ||||
|     formatter<remove_cvref_t<decltype(range_mapper<buffer_context<Char>>{}.map( | ||||
|                   std::declval<Element>()))>, | ||||
|               Char>; | ||||
|  | ||||
| template <typename R> | ||||
| using maybe_const_range = | ||||
|     conditional_t<has_const_begin_end<R>::value, const R, R>; | ||||
|  | ||||
| // Workaround a bug in MSVC 2015 and earlier. | ||||
| #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910 | ||||
| template <typename R, typename Char> | ||||
| struct is_formattable_delayed | ||||
|     : is_formattable<uncvref_type<maybe_const_range<R>>, Char> {}; | ||||
| #endif | ||||
| }  // namespace detail | ||||
|  | ||||
| template <typename...> struct conjunction : std::true_type {}; | ||||
| template <typename P> struct conjunction<P> : P {}; | ||||
| template <typename P1, typename... Pn> | ||||
| struct conjunction<P1, Pn...> | ||||
|     : conditional_t<bool(P1::value), conjunction<Pn...>, P1> {}; | ||||
|  | ||||
| template <typename T, typename Char, typename Enable = void> | ||||
| struct range_formatter; | ||||
|  | ||||
| template <typename T, typename Char> | ||||
| struct range_formatter< | ||||
|     T, Char, | ||||
|     enable_if_t<conjunction<std::is_same<T, remove_cvref_t<T>>, | ||||
|                             is_formattable<T, Char>>::value>> { | ||||
|  private: | ||||
|   detail::range_formatter_type<Char, T> underlying_; | ||||
|   basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{}; | ||||
|   basic_string_view<Char> opening_bracket_ = | ||||
|       detail::string_literal<Char, '['>{}; | ||||
|   basic_string_view<Char> closing_bracket_ = | ||||
|       detail::string_literal<Char, ']'>{}; | ||||
|  | ||||
|  public: | ||||
|   FMT_CONSTEXPR range_formatter() {} | ||||
|  | ||||
|   FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type<Char, T>& { | ||||
|     return underlying_; | ||||
|   } | ||||
|  | ||||
|   FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) { | ||||
|     separator_ = sep; | ||||
|   } | ||||
|  | ||||
|   FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open, | ||||
|                                   basic_string_view<Char> close) { | ||||
|     opening_bracket_ = open; | ||||
|     closing_bracket_ = close; | ||||
|   } | ||||
|  | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|     auto it = ctx.begin(); | ||||
|     auto end = ctx.end(); | ||||
|  | ||||
|     if (it != end && *it == 'n') { | ||||
|       set_brackets({}, {}); | ||||
|       ++it; | ||||
|     } | ||||
|  | ||||
|     if (it != end && *it != '}') { | ||||
|       if (*it != ':') FMT_THROW(format_error("invalid format specifier")); | ||||
|       ++it; | ||||
|     } else { | ||||
|       detail::maybe_set_debug_format(underlying_, true); | ||||
|     } | ||||
|  | ||||
|     ctx.advance_to(it); | ||||
|     return underlying_.parse(ctx); | ||||
|   } | ||||
|  | ||||
|   template <typename R, typename FormatContext> | ||||
|   auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) { | ||||
|     detail::range_mapper<buffer_context<Char>> mapper; | ||||
|     auto out = ctx.out(); | ||||
|     out = detail::copy_str<Char>(opening_bracket_, out); | ||||
|     int i = 0; | ||||
|     auto it = detail::range_begin(range); | ||||
|     auto end = detail::range_end(range); | ||||
|     for (; it != end; ++it) { | ||||
|       if (i > 0) out = detail::copy_str<Char>(separator_, out); | ||||
|       ctx.advance_to(out); | ||||
|       auto&& item = *it; | ||||
|       out = underlying_.format(mapper.map(item), ctx); | ||||
|       ++i; | ||||
|     } | ||||
|     out = detail::copy_str<Char>(closing_bracket_, out); | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| enum class range_format { disabled, map, set, sequence, string, debug_string }; | ||||
|  | ||||
| namespace detail { | ||||
| template <typename T> | ||||
| struct range_format_kind_ | ||||
|     : std::integral_constant<range_format, | ||||
|                              std::is_same<uncvref_type<T>, T>::value | ||||
|                                  ? range_format::disabled | ||||
|                              : is_map<T>::value ? range_format::map | ||||
|                              : is_set<T>::value ? range_format::set | ||||
|                                                 : range_format::sequence> {}; | ||||
|  | ||||
| template <range_format K, typename R, typename Char, typename Enable = void> | ||||
| struct range_default_formatter; | ||||
|  | ||||
| template <range_format K> | ||||
| using range_format_constant = std::integral_constant<range_format, K>; | ||||
|  | ||||
| template <range_format K, typename R, typename Char> | ||||
| struct range_default_formatter< | ||||
|     K, R, Char, | ||||
|     enable_if_t<(K == range_format::sequence || K == range_format::map || | ||||
|                  K == range_format::set)>> { | ||||
|   using range_type = detail::maybe_const_range<R>; | ||||
|   range_formatter<detail::uncvref_type<range_type>, Char> underlying_; | ||||
|  | ||||
|   FMT_CONSTEXPR range_default_formatter() { init(range_format_constant<K>()); } | ||||
|  | ||||
|   FMT_CONSTEXPR void init(range_format_constant<range_format::set>) { | ||||
|     underlying_.set_brackets(detail::string_literal<Char, '{'>{}, | ||||
|                              detail::string_literal<Char, '}'>{}); | ||||
|   } | ||||
|  | ||||
|   FMT_CONSTEXPR void init(range_format_constant<range_format::map>) { | ||||
|     underlying_.set_brackets(detail::string_literal<Char, '{'>{}, | ||||
|                              detail::string_literal<Char, '}'>{}); | ||||
|     underlying_.underlying().set_brackets({}, {}); | ||||
|     underlying_.underlying().set_separator( | ||||
|         detail::string_literal<Char, ':', ' '>{}); | ||||
|   } | ||||
|  | ||||
|   FMT_CONSTEXPR void init(range_format_constant<range_format::sequence>) {} | ||||
|  | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|     return underlying_.parse(ctx); | ||||
|   } | ||||
|  | ||||
|   template <typename FormatContext> | ||||
|   auto format(range_type& range, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     return underlying_.format(range, ctx); | ||||
|   } | ||||
| }; | ||||
| }  // namespace detail | ||||
|  | ||||
| template <typename T, typename Char, typename Enable = void> | ||||
| struct range_format_kind | ||||
|     : conditional_t< | ||||
|           is_range<T, Char>::value, detail::range_format_kind_<T>, | ||||
|           std::integral_constant<range_format, range_format::disabled>> {}; | ||||
|  | ||||
| template <typename R, typename Char> | ||||
| struct formatter< | ||||
|     R, Char, | ||||
|     enable_if_t<conjunction<bool_constant<range_format_kind<R, Char>::value != | ||||
|                                           range_format::disabled> | ||||
| // Workaround a bug in MSVC 2015 and earlier. | ||||
| #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910 | ||||
|                             , | ||||
|                             detail::is_formattable_delayed<R, Char> | ||||
| #endif | ||||
|                             >::value>> | ||||
|     : detail::range_default_formatter<range_format_kind<R, Char>::value, R, | ||||
|                                       Char> { | ||||
| }; | ||||
|  | ||||
| template <typename Char, typename... T> struct tuple_join_view : detail::view { | ||||
|   const std::tuple<T...>& tuple; | ||||
|   basic_string_view<Char> sep; | ||||
|  | ||||
|   tuple_join_view(const std::tuple<T...>& t, basic_string_view<Char> s) | ||||
|       : tuple(t), sep{s} {} | ||||
| }; | ||||
|  | ||||
| // Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers | ||||
| // support in tuple_join. It is disabled by default because of issues with | ||||
| // the dynamic width and precision. | ||||
| #ifndef FMT_TUPLE_JOIN_SPECIFIERS | ||||
| #  define FMT_TUPLE_JOIN_SPECIFIERS 0 | ||||
| #endif | ||||
|  | ||||
| template <typename Char, typename... T> | ||||
| struct formatter<tuple_join_view<Char, T...>, Char> { | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|     return do_parse(ctx, std::integral_constant<size_t, sizeof...(T)>()); | ||||
|   } | ||||
|  | ||||
|   template <typename FormatContext> | ||||
|   auto format(const tuple_join_view<Char, T...>& value, | ||||
|               FormatContext& ctx) const -> typename FormatContext::iterator { | ||||
|     return do_format(value, ctx, | ||||
|                      std::integral_constant<size_t, sizeof...(T)>()); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   std::tuple<formatter<typename std::decay<T>::type, Char>...> formatters_; | ||||
|  | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto do_parse(ParseContext& ctx, | ||||
|                               std::integral_constant<size_t, 0>) | ||||
|       -> decltype(ctx.begin()) { | ||||
|     return ctx.begin(); | ||||
|   } | ||||
|  | ||||
|   template <typename ParseContext, size_t N> | ||||
|   FMT_CONSTEXPR auto do_parse(ParseContext& ctx, | ||||
|                               std::integral_constant<size_t, N>) | ||||
|       -> decltype(ctx.begin()) { | ||||
|     auto end = ctx.begin(); | ||||
| #if FMT_TUPLE_JOIN_SPECIFIERS | ||||
|     end = std::get<sizeof...(T) - N>(formatters_).parse(ctx); | ||||
|     if (N > 1) { | ||||
|       auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>()); | ||||
|       if (end != end1) | ||||
|         FMT_THROW(format_error("incompatible format specs for tuple elements")); | ||||
|     } | ||||
| #endif | ||||
|     return end; | ||||
|   } | ||||
|  | ||||
|   template <typename FormatContext> | ||||
|   auto do_format(const tuple_join_view<Char, T...>&, FormatContext& ctx, | ||||
|                  std::integral_constant<size_t, 0>) const -> | ||||
|       typename FormatContext::iterator { | ||||
|     return ctx.out(); | ||||
|   } | ||||
|  | ||||
|   template <typename FormatContext, size_t N> | ||||
|   auto do_format(const tuple_join_view<Char, T...>& value, FormatContext& ctx, | ||||
|                  std::integral_constant<size_t, N>) const -> | ||||
|       typename FormatContext::iterator { | ||||
|     auto out = std::get<sizeof...(T) - N>(formatters_) | ||||
|                    .format(std::get<sizeof...(T) - N>(value.tuple), ctx); | ||||
|     if (N > 1) { | ||||
|       out = std::copy(value.sep.begin(), value.sep.end(), out); | ||||
|       ctx.advance_to(out); | ||||
|       return do_format(value, ctx, std::integral_constant<size_t, N - 1>()); | ||||
|     } | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| namespace detail { | ||||
| // Check if T has an interface like a container adaptor (e.g. std::stack, | ||||
| // std::queue, std::priority_queue). | ||||
| template <typename T> class is_container_adaptor_like { | ||||
|   template <typename U> static auto check(U* p) -> typename U::container_type; | ||||
|   template <typename> static void check(...); | ||||
|  | ||||
|  public: | ||||
|   static constexpr const bool value = | ||||
|       !std::is_void<decltype(check<T>(nullptr))>::value; | ||||
| }; | ||||
|  | ||||
| template <typename Container> struct all { | ||||
|   const Container& c; | ||||
|   auto begin() const -> typename Container::const_iterator { return c.begin(); } | ||||
|   auto end() const -> typename Container::const_iterator { return c.end(); } | ||||
| }; | ||||
| }  // namespace detail | ||||
|  | ||||
| template <typename T, typename Char> | ||||
| struct formatter< | ||||
|     T, Char, | ||||
|     enable_if_t<conjunction<detail::is_container_adaptor_like<T>, | ||||
|                             bool_constant<range_format_kind<T, Char>::value == | ||||
|                                           range_format::disabled>>::value>> | ||||
|     : formatter<detail::all<typename T::container_type>, Char> { | ||||
|   using all = detail::all<typename T::container_type>; | ||||
|   template <typename FormatContext> | ||||
|   auto format(const T& t, FormatContext& ctx) const -> decltype(ctx.out()) { | ||||
|     struct getter : T { | ||||
|       static auto get(const T& t) -> all { | ||||
|         return {t.*(&getter::c)};  // Access c through the derived class. | ||||
|       } | ||||
|     }; | ||||
|     return formatter<all>::format(getter::get(t), ctx); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| FMT_BEGIN_EXPORT | ||||
|  | ||||
| /** | ||||
|   \rst | ||||
|   Returns an object that formats `tuple` with elements separated by `sep`. | ||||
|  | ||||
|   **Example**:: | ||||
|  | ||||
|     std::tuple<int, char> t = {1, 'a'}; | ||||
|     fmt::print("{}", fmt::join(t, ", ")); | ||||
|     // Output: "1, a" | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename... T> | ||||
| FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, string_view sep) | ||||
|     -> tuple_join_view<char, T...> { | ||||
|   return {tuple, sep}; | ||||
| } | ||||
|  | ||||
| template <typename... T> | ||||
| FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, | ||||
|                         basic_string_view<wchar_t> sep) | ||||
|     -> tuple_join_view<wchar_t, T...> { | ||||
|   return {tuple, sep}; | ||||
| } | ||||
|  | ||||
| /** | ||||
|   \rst | ||||
|   Returns an object that formats `initializer_list` with elements separated by | ||||
|   `sep`. | ||||
|  | ||||
|   **Example**:: | ||||
|  | ||||
|     fmt::print("{}", fmt::join({1, 2, 3}, ", ")); | ||||
|     // Output: "1, 2, 3" | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename T> | ||||
| auto join(std::initializer_list<T> list, string_view sep) | ||||
|     -> join_view<const T*, const T*> { | ||||
|   return join(std::begin(list), std::end(list), sep); | ||||
| } | ||||
|  | ||||
| FMT_END_EXPORT | ||||
| FMT_END_NAMESPACE | ||||
|  | ||||
| #endif  // FMT_RANGES_H_ | ||||
							
								
								
									
										537
									
								
								dep/fmt/include/fmt/std.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										537
									
								
								dep/fmt/include/fmt/std.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,537 @@ | ||||
| // Formatting library for C++ - formatters for standard library types | ||||
| // | ||||
| // Copyright (c) 2012 - present, Victor Zverovich | ||||
| // All rights reserved. | ||||
| // | ||||
| // For the license information refer to format.h. | ||||
|  | ||||
| #ifndef FMT_STD_H_ | ||||
| #define FMT_STD_H_ | ||||
|  | ||||
| #include <atomic> | ||||
| #include <bitset> | ||||
| #include <cstdlib> | ||||
| #include <exception> | ||||
| #include <memory> | ||||
| #include <thread> | ||||
| #include <type_traits> | ||||
| #include <typeinfo> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
|  | ||||
| #include "format.h" | ||||
| #include "ostream.h" | ||||
|  | ||||
| #if FMT_HAS_INCLUDE(<version>) | ||||
| #  include <version> | ||||
| #endif | ||||
| // Checking FMT_CPLUSPLUS for warning suppression in MSVC. | ||||
| #if FMT_CPLUSPLUS >= 201703L | ||||
| #  if FMT_HAS_INCLUDE(<filesystem>) | ||||
| #    include <filesystem> | ||||
| #  endif | ||||
| #  if FMT_HAS_INCLUDE(<variant>) | ||||
| #    include <variant> | ||||
| #  endif | ||||
| #  if FMT_HAS_INCLUDE(<optional>) | ||||
| #    include <optional> | ||||
| #  endif | ||||
| #endif | ||||
|  | ||||
| #if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE(<source_location>) | ||||
| #  include <source_location> | ||||
| #endif | ||||
|  | ||||
| // GCC 4 does not support FMT_HAS_INCLUDE. | ||||
| #if FMT_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__) | ||||
| #  include <cxxabi.h> | ||||
| // Android NDK with gabi++ library on some architectures does not implement | ||||
| // abi::__cxa_demangle(). | ||||
| #  ifndef __GABIXX_CXXABI_H__ | ||||
| #    define FMT_HAS_ABI_CXA_DEMANGLE | ||||
| #  endif | ||||
| #endif | ||||
|  | ||||
| // Check if typeid is available. | ||||
| #ifndef FMT_USE_TYPEID | ||||
| // __RTTI is for EDG compilers. In MSVC typeid is available without RTTI. | ||||
| #  if defined(__GXX_RTTI) || FMT_HAS_FEATURE(cxx_rtti) || FMT_MSC_VERSION || \ | ||||
|       defined(__INTEL_RTTI__) || defined(__RTTI) | ||||
| #    define FMT_USE_TYPEID 1 | ||||
| #  else | ||||
| #    define FMT_USE_TYPEID 0 | ||||
| #  endif | ||||
| #endif | ||||
|  | ||||
| // For older Xcode versions, __cpp_lib_xxx flags are inaccurately defined. | ||||
| #ifndef FMT_CPP_LIB_FILESYSTEM | ||||
| #  ifdef __cpp_lib_filesystem | ||||
| #    define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem | ||||
| #  else | ||||
| #    define FMT_CPP_LIB_FILESYSTEM 0 | ||||
| #  endif | ||||
| #endif | ||||
|  | ||||
| #ifndef FMT_CPP_LIB_VARIANT | ||||
| #  ifdef __cpp_lib_variant | ||||
| #    define FMT_CPP_LIB_VARIANT __cpp_lib_variant | ||||
| #  else | ||||
| #    define FMT_CPP_LIB_VARIANT 0 | ||||
| #  endif | ||||
| #endif | ||||
|  | ||||
| #if FMT_CPP_LIB_FILESYSTEM | ||||
| FMT_BEGIN_NAMESPACE | ||||
|  | ||||
| namespace detail { | ||||
|  | ||||
| template <typename Char, typename PathChar> | ||||
| auto get_path_string(const std::filesystem::path& p, | ||||
|                      const std::basic_string<PathChar>& native) { | ||||
|   if constexpr (std::is_same_v<Char, char> && std::is_same_v<PathChar, wchar_t>) | ||||
|     return to_utf8<wchar_t>(native, to_utf8_error_policy::replace); | ||||
|   else | ||||
|     return p.string<Char>(); | ||||
| } | ||||
|  | ||||
| template <typename Char, typename PathChar> | ||||
| void write_escaped_path(basic_memory_buffer<Char>& quoted, | ||||
|                         const std::filesystem::path& p, | ||||
|                         const std::basic_string<PathChar>& native) { | ||||
|   if constexpr (std::is_same_v<Char, char> && | ||||
|                 std::is_same_v<PathChar, wchar_t>) { | ||||
|     auto buf = basic_memory_buffer<wchar_t>(); | ||||
|     write_escaped_string<wchar_t>(std::back_inserter(buf), native); | ||||
|     bool valid = to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()}); | ||||
|     FMT_ASSERT(valid, "invalid utf16"); | ||||
|   } else if constexpr (std::is_same_v<Char, PathChar>) { | ||||
|     write_escaped_string<std::filesystem::path::value_type>( | ||||
|         std::back_inserter(quoted), native); | ||||
|   } else { | ||||
|     write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>()); | ||||
|   } | ||||
| } | ||||
|  | ||||
| }  // namespace detail | ||||
|  | ||||
| FMT_EXPORT | ||||
| template <typename Char> struct formatter<std::filesystem::path, Char> { | ||||
|  private: | ||||
|   format_specs<Char> specs_; | ||||
|   detail::arg_ref<Char> width_ref_; | ||||
|   bool debug_ = false; | ||||
|   char path_type_ = 0; | ||||
|  | ||||
|  public: | ||||
|   FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; } | ||||
|  | ||||
|   template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) { | ||||
|     auto it = ctx.begin(), end = ctx.end(); | ||||
|     if (it == end) return it; | ||||
|  | ||||
|     it = detail::parse_align(it, end, specs_); | ||||
|     if (it == end) return it; | ||||
|  | ||||
|     it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); | ||||
|     if (it != end && *it == '?') { | ||||
|       debug_ = true; | ||||
|       ++it; | ||||
|     } | ||||
|     if (it != end && (*it == 'g')) path_type_ = *it++; | ||||
|     return it; | ||||
|   } | ||||
|  | ||||
|   template <typename FormatContext> | ||||
|   auto format(const std::filesystem::path& p, FormatContext& ctx) const { | ||||
|     auto specs = specs_; | ||||
| #  ifdef _WIN32 | ||||
|     auto path_string = !path_type_ ? p.native() : p.generic_wstring(); | ||||
| #  else | ||||
|     auto path_string = !path_type_ ? p.native() : p.generic_string(); | ||||
| #  endif | ||||
|  | ||||
|     detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_, | ||||
|                                                        ctx); | ||||
|     if (!debug_) { | ||||
|       auto s = detail::get_path_string<Char>(p, path_string); | ||||
|       return detail::write(ctx.out(), basic_string_view<Char>(s), specs); | ||||
|     } | ||||
|     auto quoted = basic_memory_buffer<Char>(); | ||||
|     detail::write_escaped_path(quoted, p, path_string); | ||||
|     return detail::write(ctx.out(), | ||||
|                          basic_string_view<Char>(quoted.data(), quoted.size()), | ||||
|                          specs); | ||||
|   } | ||||
| }; | ||||
| FMT_END_NAMESPACE | ||||
| #endif  // FMT_CPP_LIB_FILESYSTEM | ||||
|  | ||||
| FMT_BEGIN_NAMESPACE | ||||
| FMT_EXPORT | ||||
| template <std::size_t N, typename Char> | ||||
| struct formatter<std::bitset<N>, Char> : nested_formatter<string_view> { | ||||
|  private: | ||||
|   // Functor because C++11 doesn't support generic lambdas. | ||||
|   struct writer { | ||||
|     const std::bitset<N>& bs; | ||||
|  | ||||
|     template <typename OutputIt> | ||||
|     FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt { | ||||
|       for (auto pos = N; pos > 0; --pos) { | ||||
|         out = detail::write<Char>(out, bs[pos - 1] ? Char('1') : Char('0')); | ||||
|       } | ||||
|  | ||||
|       return out; | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|  public: | ||||
|   template <typename FormatContext> | ||||
|   auto format(const std::bitset<N>& bs, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     return write_padded(ctx, writer{bs}); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| FMT_EXPORT | ||||
| template <typename Char> | ||||
| struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {}; | ||||
| FMT_END_NAMESPACE | ||||
|  | ||||
| #ifdef __cpp_lib_optional | ||||
| FMT_BEGIN_NAMESPACE | ||||
| FMT_EXPORT | ||||
| template <typename T, typename Char> | ||||
| struct formatter<std::optional<T>, Char, | ||||
|                  std::enable_if_t<is_formattable<T, Char>::value>> { | ||||
|  private: | ||||
|   formatter<T, Char> underlying_; | ||||
|   static constexpr basic_string_view<Char> optional = | ||||
|       detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l', | ||||
|                              '('>{}; | ||||
|   static constexpr basic_string_view<Char> none = | ||||
|       detail::string_literal<Char, 'n', 'o', 'n', 'e'>{}; | ||||
|  | ||||
|   template <class U> | ||||
|   FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set) | ||||
|       -> decltype(u.set_debug_format(set)) { | ||||
|     u.set_debug_format(set); | ||||
|   } | ||||
|  | ||||
|   template <class U> | ||||
|   FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {} | ||||
|  | ||||
|  public: | ||||
|   template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) { | ||||
|     maybe_set_debug_format(underlying_, true); | ||||
|     return underlying_.parse(ctx); | ||||
|   } | ||||
|  | ||||
|   template <typename FormatContext> | ||||
|   auto format(const std::optional<T>& opt, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     if (!opt) return detail::write<Char>(ctx.out(), none); | ||||
|  | ||||
|     auto out = ctx.out(); | ||||
|     out = detail::write<Char>(out, optional); | ||||
|     ctx.advance_to(out); | ||||
|     out = underlying_.format(*opt, ctx); | ||||
|     return detail::write(out, ')'); | ||||
|   } | ||||
| }; | ||||
| FMT_END_NAMESPACE | ||||
| #endif  // __cpp_lib_optional | ||||
|  | ||||
| #ifdef __cpp_lib_source_location | ||||
| FMT_BEGIN_NAMESPACE | ||||
| FMT_EXPORT | ||||
| template <> struct formatter<std::source_location> { | ||||
|   template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) { | ||||
|     return ctx.begin(); | ||||
|   } | ||||
|  | ||||
|   template <typename FormatContext> | ||||
|   auto format(const std::source_location& loc, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     auto out = ctx.out(); | ||||
|     out = detail::write(out, loc.file_name()); | ||||
|     out = detail::write(out, ':'); | ||||
|     out = detail::write<char>(out, loc.line()); | ||||
|     out = detail::write(out, ':'); | ||||
|     out = detail::write<char>(out, loc.column()); | ||||
|     out = detail::write(out, ": "); | ||||
|     out = detail::write(out, loc.function_name()); | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
| FMT_END_NAMESPACE | ||||
| #endif | ||||
|  | ||||
| #if FMT_CPP_LIB_VARIANT | ||||
| FMT_BEGIN_NAMESPACE | ||||
| namespace detail { | ||||
|  | ||||
| template <typename T> | ||||
| using variant_index_sequence = | ||||
|     std::make_index_sequence<std::variant_size<T>::value>; | ||||
|  | ||||
| template <typename> struct is_variant_like_ : std::false_type {}; | ||||
| template <typename... Types> | ||||
| struct is_variant_like_<std::variant<Types...>> : std::true_type {}; | ||||
|  | ||||
| // formattable element check. | ||||
| template <typename T, typename C> class is_variant_formattable_ { | ||||
|   template <std::size_t... Is> | ||||
|   static std::conjunction< | ||||
|       is_formattable<std::variant_alternative_t<Is, T>, C>...> | ||||
|       check(std::index_sequence<Is...>); | ||||
|  | ||||
|  public: | ||||
|   static constexpr const bool value = | ||||
|       decltype(check(variant_index_sequence<T>{}))::value; | ||||
| }; | ||||
|  | ||||
| template <typename Char, typename OutputIt, typename T> | ||||
| auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt { | ||||
|   if constexpr (is_string<T>::value) | ||||
|     return write_escaped_string<Char>(out, detail::to_string_view(v)); | ||||
|   else if constexpr (std::is_same_v<T, Char>) | ||||
|     return write_escaped_char(out, v); | ||||
|   else | ||||
|     return write<Char>(out, v); | ||||
| } | ||||
|  | ||||
| }  // namespace detail | ||||
|  | ||||
| template <typename T> struct is_variant_like { | ||||
|   static constexpr const bool value = detail::is_variant_like_<T>::value; | ||||
| }; | ||||
|  | ||||
| template <typename T, typename C> struct is_variant_formattable { | ||||
|   static constexpr const bool value = | ||||
|       detail::is_variant_formattable_<T, C>::value; | ||||
| }; | ||||
|  | ||||
| FMT_EXPORT | ||||
| template <typename Char> struct formatter<std::monostate, Char> { | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|     return ctx.begin(); | ||||
|   } | ||||
|  | ||||
|   template <typename FormatContext> | ||||
|   auto format(const std::monostate&, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     return detail::write<Char>(ctx.out(), "monostate"); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| FMT_EXPORT | ||||
| template <typename Variant, typename Char> | ||||
| struct formatter< | ||||
|     Variant, Char, | ||||
|     std::enable_if_t<std::conjunction_v< | ||||
|         is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> { | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|     return ctx.begin(); | ||||
|   } | ||||
|  | ||||
|   template <typename FormatContext> | ||||
|   auto format(const Variant& value, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     auto out = ctx.out(); | ||||
|  | ||||
|     out = detail::write<Char>(out, "variant("); | ||||
|     FMT_TRY { | ||||
|       std::visit( | ||||
|           [&](const auto& v) { | ||||
|             out = detail::write_variant_alternative<Char>(out, v); | ||||
|           }, | ||||
|           value); | ||||
|     } | ||||
|     FMT_CATCH(const std::bad_variant_access&) { | ||||
|       detail::write<Char>(out, "valueless by exception"); | ||||
|     } | ||||
|     *out++ = ')'; | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
| FMT_END_NAMESPACE | ||||
| #endif  // FMT_CPP_LIB_VARIANT | ||||
|  | ||||
| FMT_BEGIN_NAMESPACE | ||||
| FMT_EXPORT | ||||
| template <typename Char> struct formatter<std::error_code, Char> { | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|     return ctx.begin(); | ||||
|   } | ||||
|  | ||||
|   template <typename FormatContext> | ||||
|   FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     auto out = ctx.out(); | ||||
|     out = detail::write_bytes(out, ec.category().name(), format_specs<Char>()); | ||||
|     out = detail::write<Char>(out, Char(':')); | ||||
|     out = detail::write<Char>(out, ec.value()); | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| FMT_EXPORT | ||||
| template <typename T, typename Char> | ||||
| struct formatter< | ||||
|     T, Char,  // DEPRECATED! Mixing code unit types. | ||||
|     typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> { | ||||
|  private: | ||||
|   bool with_typename_ = false; | ||||
|  | ||||
|  public: | ||||
|   FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx) | ||||
|       -> decltype(ctx.begin()) { | ||||
|     auto it = ctx.begin(); | ||||
|     auto end = ctx.end(); | ||||
|     if (it == end || *it == '}') return it; | ||||
|     if (*it == 't') { | ||||
|       ++it; | ||||
|       with_typename_ = FMT_USE_TYPEID != 0; | ||||
|     } | ||||
|     return it; | ||||
|   } | ||||
|  | ||||
|   template <typename OutputIt> | ||||
|   auto format(const std::exception& ex, | ||||
|               basic_format_context<OutputIt, Char>& ctx) const -> OutputIt { | ||||
|     format_specs<Char> spec; | ||||
|     auto out = ctx.out(); | ||||
|     if (!with_typename_) | ||||
|       return detail::write_bytes(out, string_view(ex.what()), spec); | ||||
|  | ||||
| #if FMT_USE_TYPEID | ||||
|     const std::type_info& ti = typeid(ex); | ||||
| #  ifdef FMT_HAS_ABI_CXA_DEMANGLE | ||||
|     int status = 0; | ||||
|     std::size_t size = 0; | ||||
|     std::unique_ptr<char, void (*)(void*)> demangled_name_ptr( | ||||
|         abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free); | ||||
|  | ||||
|     string_view demangled_name_view; | ||||
|     if (demangled_name_ptr) { | ||||
|       demangled_name_view = demangled_name_ptr.get(); | ||||
|  | ||||
|       // Normalization of stdlib inline namespace names. | ||||
|       // libc++ inline namespaces. | ||||
|       //  std::__1::*       -> std::* | ||||
|       //  std::__1::__fs::* -> std::* | ||||
|       // libstdc++ inline namespaces. | ||||
|       //  std::__cxx11::*             -> std::* | ||||
|       //  std::filesystem::__cxx11::* -> std::filesystem::* | ||||
|       if (demangled_name_view.starts_with("std::")) { | ||||
|         char* begin = demangled_name_ptr.get(); | ||||
|         char* to = begin + 5;  // std:: | ||||
|         for (char *from = to, *end = begin + demangled_name_view.size(); | ||||
|              from < end;) { | ||||
|           // This is safe, because demangled_name is NUL-terminated. | ||||
|           if (from[0] == '_' && from[1] == '_') { | ||||
|             char* next = from + 1; | ||||
|             while (next < end && *next != ':') next++; | ||||
|             if (next[0] == ':' && next[1] == ':') { | ||||
|               from = next + 2; | ||||
|               continue; | ||||
|             } | ||||
|           } | ||||
|           *to++ = *from++; | ||||
|         } | ||||
|         demangled_name_view = {begin, detail::to_unsigned(to - begin)}; | ||||
|       } | ||||
|     } else { | ||||
|       demangled_name_view = string_view(ti.name()); | ||||
|     } | ||||
|     out = detail::write_bytes(out, demangled_name_view, spec); | ||||
| #  elif FMT_MSC_VERSION | ||||
|     string_view demangled_name_view(ti.name()); | ||||
|     if (demangled_name_view.starts_with("class ")) | ||||
|       demangled_name_view.remove_prefix(6); | ||||
|     else if (demangled_name_view.starts_with("struct ")) | ||||
|       demangled_name_view.remove_prefix(7); | ||||
|     out = detail::write_bytes(out, demangled_name_view, spec); | ||||
| #  else | ||||
|     out = detail::write_bytes(out, string_view(ti.name()), spec); | ||||
| #  endif | ||||
|     *out++ = ':'; | ||||
|     *out++ = ' '; | ||||
|     return detail::write_bytes(out, string_view(ex.what()), spec); | ||||
| #endif | ||||
|   } | ||||
| }; | ||||
|  | ||||
| namespace detail { | ||||
|  | ||||
| template <typename T, typename Enable = void> | ||||
| struct has_flip : std::false_type {}; | ||||
|  | ||||
| template <typename T> | ||||
| struct has_flip<T, void_t<decltype(std::declval<T>().flip())>> | ||||
|     : std::true_type {}; | ||||
|  | ||||
| template <typename T> struct is_bit_reference_like { | ||||
|   static constexpr const bool value = | ||||
|       std::is_convertible<T, bool>::value && | ||||
|       std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value; | ||||
| }; | ||||
|  | ||||
| #ifdef _LIBCPP_VERSION | ||||
|  | ||||
| // Workaround for libc++ incompatibility with C++ standard. | ||||
| // According to the Standard, `bitset::operator[] const` returns bool. | ||||
| template <typename C> | ||||
| struct is_bit_reference_like<std::__bit_const_reference<C>> { | ||||
|   static constexpr const bool value = true; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|  | ||||
| }  // namespace detail | ||||
|  | ||||
| // We can't use std::vector<bool, Allocator>::reference and | ||||
| // std::bitset<N>::reference because the compiler can't deduce Allocator and N | ||||
| // in partial specialization. | ||||
| FMT_EXPORT | ||||
| template <typename BitRef, typename Char> | ||||
| struct formatter<BitRef, Char, | ||||
|                  enable_if_t<detail::is_bit_reference_like<BitRef>::value>> | ||||
|     : formatter<bool, Char> { | ||||
|   template <typename FormatContext> | ||||
|   FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     return formatter<bool, Char>::format(v, ctx); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| FMT_EXPORT | ||||
| template <typename T, typename Char> | ||||
| struct formatter<std::atomic<T>, Char, | ||||
|                  enable_if_t<is_formattable<T, Char>::value>> | ||||
|     : formatter<T, Char> { | ||||
|   template <typename FormatContext> | ||||
|   auto format(const std::atomic<T>& v, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     return formatter<T, Char>::format(v.load(), ctx); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| #ifdef __cpp_lib_atomic_flag_test | ||||
| FMT_EXPORT | ||||
| template <typename Char> | ||||
| struct formatter<std::atomic_flag, Char> : formatter<bool, Char> { | ||||
|   template <typename FormatContext> | ||||
|   auto format(const std::atomic_flag& v, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     return formatter<bool, Char>::format(v.test(), ctx); | ||||
|   } | ||||
| }; | ||||
| #endif  // __cpp_lib_atomic_flag_test | ||||
|  | ||||
| FMT_END_NAMESPACE | ||||
| #endif  // FMT_STD_H_ | ||||
							
								
								
									
										259
									
								
								dep/fmt/include/fmt/xchar.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										259
									
								
								dep/fmt/include/fmt/xchar.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,259 @@ | ||||
| // Formatting library for C++ - optional wchar_t and exotic character support | ||||
| // | ||||
| // Copyright (c) 2012 - present, Victor Zverovich | ||||
| // All rights reserved. | ||||
| // | ||||
| // For the license information refer to format.h. | ||||
|  | ||||
| #ifndef FMT_XCHAR_H_ | ||||
| #define FMT_XCHAR_H_ | ||||
|  | ||||
| #include <cwchar> | ||||
|  | ||||
| #include "format.h" | ||||
|  | ||||
| #ifndef FMT_STATIC_THOUSANDS_SEPARATOR | ||||
| #  include <locale> | ||||
| #endif | ||||
|  | ||||
| FMT_BEGIN_NAMESPACE | ||||
| namespace detail { | ||||
|  | ||||
| template <typename T> | ||||
| using is_exotic_char = bool_constant<!std::is_same<T, char>::value>; | ||||
|  | ||||
| inline auto write_loc(std::back_insert_iterator<detail::buffer<wchar_t>> out, | ||||
|                       loc_value value, const format_specs<wchar_t>& specs, | ||||
|                       locale_ref loc) -> bool { | ||||
| #ifndef FMT_STATIC_THOUSANDS_SEPARATOR | ||||
|   auto& numpunct = | ||||
|       std::use_facet<std::numpunct<wchar_t>>(loc.get<std::locale>()); | ||||
|   auto separator = std::wstring(); | ||||
|   auto grouping = numpunct.grouping(); | ||||
|   if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep()); | ||||
|   return value.visit(loc_writer<wchar_t>{out, specs, separator, grouping, {}}); | ||||
| #endif | ||||
|   return false; | ||||
| } | ||||
| }  // namespace detail | ||||
|  | ||||
| FMT_BEGIN_EXPORT | ||||
|  | ||||
| using wstring_view = basic_string_view<wchar_t>; | ||||
| using wformat_parse_context = basic_format_parse_context<wchar_t>; | ||||
| using wformat_context = buffer_context<wchar_t>; | ||||
| using wformat_args = basic_format_args<wformat_context>; | ||||
| using wmemory_buffer = basic_memory_buffer<wchar_t>; | ||||
|  | ||||
| #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 | ||||
| // Workaround broken conversion on older gcc. | ||||
| template <typename... Args> using wformat_string = wstring_view; | ||||
| inline auto runtime(wstring_view s) -> wstring_view { return s; } | ||||
| #else | ||||
| template <typename... Args> | ||||
| using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>; | ||||
| inline auto runtime(wstring_view s) -> runtime_format_string<wchar_t> { | ||||
|   return {{s}}; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| template <> struct is_char<wchar_t> : std::true_type {}; | ||||
| template <> struct is_char<detail::char8_type> : std::true_type {}; | ||||
| template <> struct is_char<char16_t> : std::true_type {}; | ||||
| template <> struct is_char<char32_t> : std::true_type {}; | ||||
|  | ||||
| template <typename... T> | ||||
| constexpr auto make_wformat_args(const T&... args) | ||||
|     -> format_arg_store<wformat_context, T...> { | ||||
|   return {args...}; | ||||
| } | ||||
|  | ||||
| inline namespace literals { | ||||
| #if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS | ||||
| constexpr auto operator""_a(const wchar_t* s, size_t) | ||||
|     -> detail::udl_arg<wchar_t> { | ||||
|   return {s}; | ||||
| } | ||||
| #endif | ||||
| }  // namespace literals | ||||
|  | ||||
| template <typename It, typename Sentinel> | ||||
| auto join(It begin, Sentinel end, wstring_view sep) | ||||
|     -> join_view<It, Sentinel, wchar_t> { | ||||
|   return {begin, end, sep}; | ||||
| } | ||||
|  | ||||
| template <typename Range> | ||||
| auto join(Range&& range, wstring_view sep) | ||||
|     -> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>, | ||||
|                  wchar_t> { | ||||
|   return join(std::begin(range), std::end(range), sep); | ||||
| } | ||||
|  | ||||
| template <typename T> | ||||
| auto join(std::initializer_list<T> list, wstring_view sep) | ||||
|     -> join_view<const T*, const T*, wchar_t> { | ||||
|   return join(std::begin(list), std::end(list), sep); | ||||
| } | ||||
|  | ||||
| template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)> | ||||
| auto vformat(basic_string_view<Char> format_str, | ||||
|              basic_format_args<buffer_context<type_identity_t<Char>>> args) | ||||
|     -> std::basic_string<Char> { | ||||
|   auto buf = basic_memory_buffer<Char>(); | ||||
|   detail::vformat_to(buf, format_str, args); | ||||
|   return to_string(buf); | ||||
| } | ||||
|  | ||||
| template <typename... T> | ||||
| auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring { | ||||
|   return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...)); | ||||
| } | ||||
|  | ||||
| // Pass char_t as a default template parameter instead of using | ||||
| // std::basic_string<char_t<S>> to reduce the symbol size. | ||||
| template <typename S, typename... T, typename Char = char_t<S>, | ||||
|           FMT_ENABLE_IF(!std::is_same<Char, char>::value && | ||||
|                         !std::is_same<Char, wchar_t>::value)> | ||||
| auto format(const S& format_str, T&&... args) -> std::basic_string<Char> { | ||||
|   return vformat(detail::to_string_view(format_str), | ||||
|                  fmt::make_format_args<buffer_context<Char>>(args...)); | ||||
| } | ||||
|  | ||||
| template <typename Locale, typename S, typename Char = char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_locale<Locale>::value&& | ||||
|                             detail::is_exotic_char<Char>::value)> | ||||
| inline auto vformat( | ||||
|     const Locale& loc, const S& format_str, | ||||
|     basic_format_args<buffer_context<type_identity_t<Char>>> args) | ||||
|     -> std::basic_string<Char> { | ||||
|   return detail::vformat(loc, detail::to_string_view(format_str), args); | ||||
| } | ||||
|  | ||||
| template <typename Locale, typename S, typename... T, typename Char = char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_locale<Locale>::value&& | ||||
|                             detail::is_exotic_char<Char>::value)> | ||||
| inline auto format(const Locale& loc, const S& format_str, T&&... args) | ||||
|     -> std::basic_string<Char> { | ||||
|   return detail::vformat(loc, detail::to_string_view(format_str), | ||||
|                          fmt::make_format_args<buffer_context<Char>>(args...)); | ||||
| } | ||||
|  | ||||
| template <typename OutputIt, typename S, typename Char = char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& | ||||
|                             detail::is_exotic_char<Char>::value)> | ||||
| auto vformat_to(OutputIt out, const S& format_str, | ||||
|                 basic_format_args<buffer_context<type_identity_t<Char>>> args) | ||||
|     -> OutputIt { | ||||
|   auto&& buf = detail::get_buffer<Char>(out); | ||||
|   detail::vformat_to(buf, detail::to_string_view(format_str), args); | ||||
|   return detail::get_iterator(buf, out); | ||||
| } | ||||
|  | ||||
| template <typename OutputIt, typename S, typename... T, | ||||
|           typename Char = char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& | ||||
|                             detail::is_exotic_char<Char>::value)> | ||||
| inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt { | ||||
|   return vformat_to(out, detail::to_string_view(fmt), | ||||
|                     fmt::make_format_args<buffer_context<Char>>(args...)); | ||||
| } | ||||
|  | ||||
| template <typename Locale, typename S, typename OutputIt, typename... Args, | ||||
|           typename Char = char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& | ||||
|                             detail::is_locale<Locale>::value&& | ||||
|                                 detail::is_exotic_char<Char>::value)> | ||||
| inline auto vformat_to( | ||||
|     OutputIt out, const Locale& loc, const S& format_str, | ||||
|     basic_format_args<buffer_context<type_identity_t<Char>>> args) -> OutputIt { | ||||
|   auto&& buf = detail::get_buffer<Char>(out); | ||||
|   vformat_to(buf, detail::to_string_view(format_str), args, | ||||
|              detail::locale_ref(loc)); | ||||
|   return detail::get_iterator(buf, out); | ||||
| } | ||||
|  | ||||
| template <typename OutputIt, typename Locale, typename S, typename... T, | ||||
|           typename Char = char_t<S>, | ||||
|           bool enable = detail::is_output_iterator<OutputIt, Char>::value && | ||||
|                         detail::is_locale<Locale>::value && | ||||
|                         detail::is_exotic_char<Char>::value> | ||||
| inline auto format_to(OutputIt out, const Locale& loc, const S& format_str, | ||||
|                       T&&... args) -> | ||||
|     typename std::enable_if<enable, OutputIt>::type { | ||||
|   return vformat_to(out, loc, detail::to_string_view(format_str), | ||||
|                     fmt::make_format_args<buffer_context<Char>>(args...)); | ||||
| } | ||||
|  | ||||
| template <typename OutputIt, typename Char, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& | ||||
|                             detail::is_exotic_char<Char>::value)> | ||||
| inline auto vformat_to_n( | ||||
|     OutputIt out, size_t n, basic_string_view<Char> format_str, | ||||
|     basic_format_args<buffer_context<type_identity_t<Char>>> args) | ||||
|     -> format_to_n_result<OutputIt> { | ||||
|   using traits = detail::fixed_buffer_traits; | ||||
|   auto buf = detail::iterator_buffer<OutputIt, Char, traits>(out, n); | ||||
|   detail::vformat_to(buf, format_str, args); | ||||
|   return {buf.out(), buf.count()}; | ||||
| } | ||||
|  | ||||
| template <typename OutputIt, typename S, typename... T, | ||||
|           typename Char = char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& | ||||
|                             detail::is_exotic_char<Char>::value)> | ||||
| inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args) | ||||
|     -> format_to_n_result<OutputIt> { | ||||
|   return vformat_to_n(out, n, detail::to_string_view(fmt), | ||||
|                       fmt::make_format_args<buffer_context<Char>>(args...)); | ||||
| } | ||||
|  | ||||
| template <typename S, typename... T, typename Char = char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)> | ||||
| inline auto formatted_size(const S& fmt, T&&... args) -> size_t { | ||||
|   auto buf = detail::counting_buffer<Char>(); | ||||
|   detail::vformat_to(buf, detail::to_string_view(fmt), | ||||
|                      fmt::make_format_args<buffer_context<Char>>(args...)); | ||||
|   return buf.count(); | ||||
| } | ||||
|  | ||||
| inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) { | ||||
|   auto buf = wmemory_buffer(); | ||||
|   detail::vformat_to(buf, fmt, args); | ||||
|   buf.push_back(L'\0'); | ||||
|   if (std::fputws(buf.data(), f) == -1) | ||||
|     FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); | ||||
| } | ||||
|  | ||||
| inline void vprint(wstring_view fmt, wformat_args args) { | ||||
|   vprint(stdout, fmt, args); | ||||
| } | ||||
|  | ||||
| template <typename... T> | ||||
| void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) { | ||||
|   return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...)); | ||||
| } | ||||
|  | ||||
| template <typename... T> void print(wformat_string<T...> fmt, T&&... args) { | ||||
|   return vprint(wstring_view(fmt), fmt::make_wformat_args(args...)); | ||||
| } | ||||
|  | ||||
| template <typename... T> | ||||
| void println(std::FILE* f, wformat_string<T...> fmt, T&&... args) { | ||||
|   return print(f, L"{}\n", fmt::format(fmt, std::forward<T>(args)...)); | ||||
| } | ||||
|  | ||||
| template <typename... T> void println(wformat_string<T...> fmt, T&&... args) { | ||||
|   return print(L"{}\n", fmt::format(fmt, std::forward<T>(args)...)); | ||||
| } | ||||
|  | ||||
| /** | ||||
|   Converts *value* to ``std::wstring`` using the default format for type *T*. | ||||
|  */ | ||||
| template <typename T> inline auto to_wstring(const T& value) -> std::wstring { | ||||
|   return format(FMT_STRING(L"{}"), value); | ||||
| } | ||||
| FMT_END_EXPORT | ||||
| FMT_END_NAMESPACE | ||||
|  | ||||
| #endif  // FMT_XCHAR_H_ | ||||
							
								
								
									
										108
									
								
								dep/fmt/src/fmt.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								dep/fmt/src/fmt.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
| module; | ||||
|  | ||||
| // Put all implementation-provided headers into the global module fragment | ||||
| // to prevent attachment to this module. | ||||
| #include <algorithm> | ||||
| #include <cerrno> | ||||
| #include <chrono> | ||||
| #include <climits> | ||||
| #include <cmath> | ||||
| #include <cstddef> | ||||
| #include <cstdint> | ||||
| #include <cstdio> | ||||
| #include <cstdlib> | ||||
| #include <cstring> | ||||
| #include <ctime> | ||||
| #include <exception> | ||||
| #include <filesystem> | ||||
| #include <fstream> | ||||
| #include <functional> | ||||
| #include <iterator> | ||||
| #include <limits> | ||||
| #include <locale> | ||||
| #include <memory> | ||||
| #include <optional> | ||||
| #include <ostream> | ||||
| #include <stdexcept> | ||||
| #include <string> | ||||
| #include <string_view> | ||||
| #include <system_error> | ||||
| #include <thread> | ||||
| #include <type_traits> | ||||
| #include <typeinfo> | ||||
| #include <utility> | ||||
| #include <variant> | ||||
| #include <vector> | ||||
| #include <version> | ||||
|  | ||||
| #if __has_include(<cxxabi.h>) | ||||
| #  include <cxxabi.h> | ||||
| #endif | ||||
| #if defined(_MSC_VER) || defined(__MINGW32__) | ||||
| #  include <intrin.h> | ||||
| #endif | ||||
| #if defined __APPLE__ || defined(__FreeBSD__) | ||||
| #  include <xlocale.h> | ||||
| #endif | ||||
| #if __has_include(<winapifamily.h>) | ||||
| #  include <winapifamily.h> | ||||
| #endif | ||||
| #if (__has_include(<fcntl.h>) || defined(__APPLE__) || \ | ||||
|      defined(__linux__)) &&                            \ | ||||
|     (!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) | ||||
| #  include <fcntl.h> | ||||
| #  include <sys/stat.h> | ||||
| #  include <sys/types.h> | ||||
| #  ifndef _WIN32 | ||||
| #    include <unistd.h> | ||||
| #  else | ||||
| #    include <io.h> | ||||
| #  endif | ||||
| #endif | ||||
| #ifdef _WIN32 | ||||
| #  if defined(__GLIBCXX__) | ||||
| #    include <ext/stdio_filebuf.h> | ||||
| #    include <ext/stdio_sync_filebuf.h> | ||||
| #  endif | ||||
| #  define WIN32_LEAN_AND_MEAN | ||||
| #  include <windows.h> | ||||
| #endif | ||||
|  | ||||
| export module fmt; | ||||
|  | ||||
| #define FMT_EXPORT export | ||||
| #define FMT_BEGIN_EXPORT export { | ||||
| #define FMT_END_EXPORT } | ||||
|  | ||||
| // If you define FMT_ATTACH_TO_GLOBAL_MODULE | ||||
| //  - all declarations are detached from module 'fmt' | ||||
| //  - the module behaves like a traditional static library, too | ||||
| //  - all library symbols are mangled traditionally | ||||
| //  - you can mix TUs with either importing or #including the {fmt} API | ||||
| #ifdef FMT_ATTACH_TO_GLOBAL_MODULE | ||||
| extern "C++" { | ||||
| #endif | ||||
|  | ||||
| // All library-provided declarations and definitions must be in the module | ||||
| // purview to be exported. | ||||
| #include "fmt/args.h" | ||||
| #include "fmt/chrono.h" | ||||
| #include "fmt/color.h" | ||||
| #include "fmt/compile.h" | ||||
| #include "fmt/format.h" | ||||
| #include "fmt/os.h" | ||||
| #include "fmt/printf.h" | ||||
| #include "fmt/std.h" | ||||
| #include "fmt/xchar.h" | ||||
|  | ||||
| #ifdef FMT_ATTACH_TO_GLOBAL_MODULE | ||||
| } | ||||
| #endif | ||||
|  | ||||
| // gcc doesn't yet implement private module fragments | ||||
| #if !FMT_GCC_VERSION | ||||
| module :private; | ||||
| #endif | ||||
|  | ||||
| #include "format.cc" | ||||
| #include "os.cc" | ||||
							
								
								
									
										43
									
								
								dep/fmt/src/format.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								dep/fmt/src/format.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| // Formatting library for C++ | ||||
| // | ||||
| // Copyright (c) 2012 - 2016, Victor Zverovich | ||||
| // All rights reserved. | ||||
| // | ||||
| // For the license information refer to format.h. | ||||
|  | ||||
| #include "fmt/format-inl.h" | ||||
|  | ||||
| FMT_BEGIN_NAMESPACE | ||||
| namespace detail { | ||||
|  | ||||
| template FMT_API auto dragonbox::to_decimal(float x) noexcept | ||||
|     -> dragonbox::decimal_fp<float>; | ||||
| template FMT_API auto dragonbox::to_decimal(double x) noexcept | ||||
|     -> dragonbox::decimal_fp<double>; | ||||
|  | ||||
| #ifndef FMT_STATIC_THOUSANDS_SEPARATOR | ||||
| template FMT_API locale_ref::locale_ref(const std::locale& loc); | ||||
| template FMT_API auto locale_ref::get<std::locale>() const -> std::locale; | ||||
| #endif | ||||
|  | ||||
| // Explicit instantiations for char. | ||||
|  | ||||
| template FMT_API auto thousands_sep_impl(locale_ref) | ||||
|     -> thousands_sep_result<char>; | ||||
| template FMT_API auto decimal_point_impl(locale_ref) -> char; | ||||
|  | ||||
| template FMT_API void buffer<char>::append(const char*, const char*); | ||||
|  | ||||
| template FMT_API void vformat_to(buffer<char>&, string_view, | ||||
|                                  typename vformat_args<>::type, locale_ref); | ||||
|  | ||||
| // Explicit instantiations for wchar_t. | ||||
|  | ||||
| template FMT_API auto thousands_sep_impl(locale_ref) | ||||
|     -> thousands_sep_result<wchar_t>; | ||||
| template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t; | ||||
|  | ||||
| template FMT_API void buffer<wchar_t>::append(const wchar_t*, const wchar_t*); | ||||
|  | ||||
| }  // namespace detail | ||||
| FMT_END_NAMESPACE | ||||
							
								
								
									
										402
									
								
								dep/fmt/src/os.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										402
									
								
								dep/fmt/src/os.cc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,402 @@ | ||||
| // Formatting library for C++ - optional OS-specific functionality | ||||
| // | ||||
| // Copyright (c) 2012 - 2016, Victor Zverovich | ||||
| // All rights reserved. | ||||
| // | ||||
| // For the license information refer to format.h. | ||||
|  | ||||
| // Disable bogus MSVC warnings. | ||||
| #if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER) | ||||
| #  define _CRT_SECURE_NO_WARNINGS | ||||
| #endif | ||||
|  | ||||
| #include "fmt/os.h" | ||||
|  | ||||
| #include <climits> | ||||
|  | ||||
| #if FMT_USE_FCNTL | ||||
| #  include <sys/stat.h> | ||||
| #  include <sys/types.h> | ||||
|  | ||||
| #  ifdef _WRS_KERNEL    // VxWorks7 kernel | ||||
| #    include <ioLib.h>  // getpagesize | ||||
| #  endif | ||||
|  | ||||
| #  ifndef _WIN32 | ||||
| #    include <unistd.h> | ||||
| #  else | ||||
| #    ifndef WIN32_LEAN_AND_MEAN | ||||
| #      define WIN32_LEAN_AND_MEAN | ||||
| #    endif | ||||
| #    include <io.h> | ||||
|  | ||||
| #    ifndef S_IRUSR | ||||
| #      define S_IRUSR _S_IREAD | ||||
| #    endif | ||||
| #    ifndef S_IWUSR | ||||
| #      define S_IWUSR _S_IWRITE | ||||
| #    endif | ||||
| #    ifndef S_IRGRP | ||||
| #      define S_IRGRP 0 | ||||
| #    endif | ||||
| #    ifndef S_IWGRP | ||||
| #      define S_IWGRP 0 | ||||
| #    endif | ||||
| #    ifndef S_IROTH | ||||
| #      define S_IROTH 0 | ||||
| #    endif | ||||
| #    ifndef S_IWOTH | ||||
| #      define S_IWOTH 0 | ||||
| #    endif | ||||
| #  endif  // _WIN32 | ||||
| #endif    // FMT_USE_FCNTL | ||||
|  | ||||
| #ifdef _WIN32 | ||||
| #  include <windows.h> | ||||
| #endif | ||||
|  | ||||
| namespace { | ||||
| #ifdef _WIN32 | ||||
| // Return type of read and write functions. | ||||
| using rwresult = int; | ||||
|  | ||||
| // On Windows the count argument to read and write is unsigned, so convert | ||||
| // it from size_t preventing integer overflow. | ||||
| inline unsigned convert_rwcount(std::size_t count) { | ||||
|   return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX; | ||||
| } | ||||
| #elif FMT_USE_FCNTL | ||||
| // Return type of read and write functions. | ||||
| using rwresult = ssize_t; | ||||
|  | ||||
| inline std::size_t convert_rwcount(std::size_t count) { return count; } | ||||
| #endif | ||||
| }  // namespace | ||||
|  | ||||
| FMT_BEGIN_NAMESPACE | ||||
|  | ||||
| #ifdef _WIN32 | ||||
| namespace detail { | ||||
|  | ||||
| class system_message { | ||||
|   system_message(const system_message&) = delete; | ||||
|   void operator=(const system_message&) = delete; | ||||
|  | ||||
|   unsigned long result_; | ||||
|   wchar_t* message_; | ||||
|  | ||||
|   static bool is_whitespace(wchar_t c) noexcept { | ||||
|     return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0'; | ||||
|   } | ||||
|  | ||||
|  public: | ||||
|   explicit system_message(unsigned long error_code) | ||||
|       : result_(0), message_(nullptr) { | ||||
|     result_ = FormatMessageW( | ||||
|         FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | | ||||
|             FORMAT_MESSAGE_IGNORE_INSERTS, | ||||
|         nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | ||||
|         reinterpret_cast<wchar_t*>(&message_), 0, nullptr); | ||||
|     if (result_ != 0) { | ||||
|       while (result_ != 0 && is_whitespace(message_[result_ - 1])) { | ||||
|         --result_; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   ~system_message() { LocalFree(message_); } | ||||
|   explicit operator bool() const noexcept { return result_ != 0; } | ||||
|   operator basic_string_view<wchar_t>() const noexcept { | ||||
|     return basic_string_view<wchar_t>(message_, result_); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| class utf8_system_category final : public std::error_category { | ||||
|  public: | ||||
|   const char* name() const noexcept override { return "system"; } | ||||
|   std::string message(int error_code) const override { | ||||
|     auto&& msg = system_message(error_code); | ||||
|     if (msg) { | ||||
|       auto utf8_message = to_utf8<wchar_t>(); | ||||
|       if (utf8_message.convert(msg)) { | ||||
|         return utf8_message.str(); | ||||
|       } | ||||
|     } | ||||
|     return "unknown error"; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| }  // namespace detail | ||||
|  | ||||
| FMT_API const std::error_category& system_category() noexcept { | ||||
|   static const detail::utf8_system_category category; | ||||
|   return category; | ||||
| } | ||||
|  | ||||
| std::system_error vwindows_error(int err_code, string_view format_str, | ||||
|                                  format_args args) { | ||||
|   auto ec = std::error_code(err_code, system_category()); | ||||
|   return std::system_error(ec, vformat(format_str, args)); | ||||
| } | ||||
|  | ||||
| void detail::format_windows_error(detail::buffer<char>& out, int error_code, | ||||
|                                   const char* message) noexcept { | ||||
|   FMT_TRY { | ||||
|     auto&& msg = system_message(error_code); | ||||
|     if (msg) { | ||||
|       auto utf8_message = to_utf8<wchar_t>(); | ||||
|       if (utf8_message.convert(msg)) { | ||||
|         fmt::format_to(appender(out), FMT_STRING("{}: {}"), message, | ||||
|                        string_view(utf8_message)); | ||||
|         return; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   FMT_CATCH(...) {} | ||||
|   format_error_code(out, error_code, message); | ||||
| } | ||||
|  | ||||
| void report_windows_error(int error_code, const char* message) noexcept { | ||||
|   report_error(detail::format_windows_error, error_code, message); | ||||
| } | ||||
| #endif  // _WIN32 | ||||
|  | ||||
| buffered_file::~buffered_file() noexcept { | ||||
|   if (file_ && FMT_SYSTEM(fclose(file_)) != 0) | ||||
|     report_system_error(errno, "cannot close file"); | ||||
| } | ||||
|  | ||||
| buffered_file::buffered_file(cstring_view filename, cstring_view mode) { | ||||
|   FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), | ||||
|                 nullptr); | ||||
|   if (!file_) | ||||
|     FMT_THROW(system_error(errno, FMT_STRING("cannot open file {}"), | ||||
|                            filename.c_str())); | ||||
| } | ||||
|  | ||||
| void buffered_file::close() { | ||||
|   if (!file_) return; | ||||
|   int result = FMT_SYSTEM(fclose(file_)); | ||||
|   file_ = nullptr; | ||||
|   if (result != 0) | ||||
|     FMT_THROW(system_error(errno, FMT_STRING("cannot close file"))); | ||||
| } | ||||
|  | ||||
| int buffered_file::descriptor() const { | ||||
| #if !defined(fileno) | ||||
|   int fd = FMT_POSIX_CALL(fileno(file_)); | ||||
| #elif defined(FMT_HAS_SYSTEM) | ||||
|   // fileno is a macro on OpenBSD so we cannot use FMT_POSIX_CALL. | ||||
| #  define FMT_DISABLE_MACRO | ||||
|   int fd = FMT_SYSTEM(fileno FMT_DISABLE_MACRO(file_)); | ||||
| #else | ||||
|   int fd = fileno(file_); | ||||
| #endif | ||||
|   if (fd == -1) | ||||
|     FMT_THROW(system_error(errno, FMT_STRING("cannot get file descriptor"))); | ||||
|   return fd; | ||||
| } | ||||
|  | ||||
| #if FMT_USE_FCNTL | ||||
| #  ifdef _WIN32 | ||||
| using mode_t = int; | ||||
| #  endif | ||||
| constexpr mode_t default_open_mode = | ||||
|     S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; | ||||
|  | ||||
| file::file(cstring_view path, int oflag) { | ||||
| #  if defined(_WIN32) && !defined(__MINGW32__) | ||||
|   fd_ = -1; | ||||
|   auto converted = detail::utf8_to_utf16(string_view(path.c_str())); | ||||
|   *this = file::open_windows_file(converted.c_str(), oflag); | ||||
| #  else | ||||
|   FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, default_open_mode))); | ||||
|   if (fd_ == -1) | ||||
|     FMT_THROW( | ||||
|         system_error(errno, FMT_STRING("cannot open file {}"), path.c_str())); | ||||
| #  endif | ||||
| } | ||||
|  | ||||
| file::~file() noexcept { | ||||
|   // Don't retry close in case of EINTR! | ||||
|   // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html | ||||
|   if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0) | ||||
|     report_system_error(errno, "cannot close file"); | ||||
| } | ||||
|  | ||||
| void file::close() { | ||||
|   if (fd_ == -1) return; | ||||
|   // Don't retry close in case of EINTR! | ||||
|   // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html | ||||
|   int result = FMT_POSIX_CALL(close(fd_)); | ||||
|   fd_ = -1; | ||||
|   if (result != 0) | ||||
|     FMT_THROW(system_error(errno, FMT_STRING("cannot close file"))); | ||||
| } | ||||
|  | ||||
| long long file::size() const { | ||||
| #  ifdef _WIN32 | ||||
|   // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT | ||||
|   // is less than 0x0500 as is the case with some default MinGW builds. | ||||
|   // Both functions support large file sizes. | ||||
|   DWORD size_upper = 0; | ||||
|   HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd_)); | ||||
|   DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper)); | ||||
|   if (size_lower == INVALID_FILE_SIZE) { | ||||
|     DWORD error = GetLastError(); | ||||
|     if (error != NO_ERROR) | ||||
|       FMT_THROW(windows_error(GetLastError(), "cannot get file size")); | ||||
|   } | ||||
|   unsigned long long long_size = size_upper; | ||||
|   return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; | ||||
| #  else | ||||
|   using Stat = struct stat; | ||||
|   Stat file_stat = Stat(); | ||||
|   if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) | ||||
|     FMT_THROW(system_error(errno, FMT_STRING("cannot get file attributes"))); | ||||
|   static_assert(sizeof(long long) >= sizeof(file_stat.st_size), | ||||
|                 "return type of file::size is not large enough"); | ||||
|   return file_stat.st_size; | ||||
| #  endif | ||||
| } | ||||
|  | ||||
| std::size_t file::read(void* buffer, std::size_t count) { | ||||
|   rwresult result = 0; | ||||
|   FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); | ||||
|   if (result < 0) | ||||
|     FMT_THROW(system_error(errno, FMT_STRING("cannot read from file"))); | ||||
|   return detail::to_unsigned(result); | ||||
| } | ||||
|  | ||||
| std::size_t file::write(const void* buffer, std::size_t count) { | ||||
|   rwresult result = 0; | ||||
|   FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); | ||||
|   if (result < 0) | ||||
|     FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); | ||||
|   return detail::to_unsigned(result); | ||||
| } | ||||
|  | ||||
| file file::dup(int fd) { | ||||
|   // Don't retry as dup doesn't return EINTR. | ||||
|   // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html | ||||
|   int new_fd = FMT_POSIX_CALL(dup(fd)); | ||||
|   if (new_fd == -1) | ||||
|     FMT_THROW(system_error( | ||||
|         errno, FMT_STRING("cannot duplicate file descriptor {}"), fd)); | ||||
|   return file(new_fd); | ||||
| } | ||||
|  | ||||
| void file::dup2(int fd) { | ||||
|   int result = 0; | ||||
|   FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); | ||||
|   if (result == -1) { | ||||
|     FMT_THROW(system_error( | ||||
|         errno, FMT_STRING("cannot duplicate file descriptor {} to {}"), fd_, | ||||
|         fd)); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void file::dup2(int fd, std::error_code& ec) noexcept { | ||||
|   int result = 0; | ||||
|   FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); | ||||
|   if (result == -1) ec = std::error_code(errno, std::generic_category()); | ||||
| } | ||||
|  | ||||
| void file::pipe(file& read_end, file& write_end) { | ||||
|   // Close the descriptors first to make sure that assignments don't throw | ||||
|   // and there are no leaks. | ||||
|   read_end.close(); | ||||
|   write_end.close(); | ||||
|   int fds[2] = {}; | ||||
| #  ifdef _WIN32 | ||||
|   // Make the default pipe capacity same as on Linux 2.6.11+. | ||||
|   enum { DEFAULT_CAPACITY = 65536 }; | ||||
|   int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY)); | ||||
| #  else | ||||
|   // Don't retry as the pipe function doesn't return EINTR. | ||||
|   // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html | ||||
|   int result = FMT_POSIX_CALL(pipe(fds)); | ||||
| #  endif | ||||
|   if (result != 0) | ||||
|     FMT_THROW(system_error(errno, FMT_STRING("cannot create pipe"))); | ||||
|   // The following assignments don't throw because read_fd and write_fd | ||||
|   // are closed. | ||||
|   read_end = file(fds[0]); | ||||
|   write_end = file(fds[1]); | ||||
| } | ||||
|  | ||||
| buffered_file file::fdopen(const char* mode) { | ||||
| // Don't retry as fdopen doesn't return EINTR. | ||||
| #  if defined(__MINGW32__) && defined(_POSIX_) | ||||
|   FILE* f = ::fdopen(fd_, mode); | ||||
| #  else | ||||
|   FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode)); | ||||
| #  endif | ||||
|   if (!f) { | ||||
|     FMT_THROW(system_error( | ||||
|         errno, FMT_STRING("cannot associate stream with file descriptor"))); | ||||
|   } | ||||
|   buffered_file bf(f); | ||||
|   fd_ = -1; | ||||
|   return bf; | ||||
| } | ||||
|  | ||||
| #  if defined(_WIN32) && !defined(__MINGW32__) | ||||
| file file::open_windows_file(wcstring_view path, int oflag) { | ||||
|   int fd = -1; | ||||
|   auto err = _wsopen_s(&fd, path.c_str(), oflag, _SH_DENYNO, default_open_mode); | ||||
|   if (fd == -1) { | ||||
|     FMT_THROW(system_error(err, FMT_STRING("cannot open file {}"), | ||||
|                            detail::to_utf8<wchar_t>(path.c_str()).c_str())); | ||||
|   } | ||||
|   return file(fd); | ||||
| } | ||||
| #  endif | ||||
|  | ||||
| #  if !defined(__MSDOS__) | ||||
| long getpagesize() { | ||||
| #    ifdef _WIN32 | ||||
|   SYSTEM_INFO si; | ||||
|   GetSystemInfo(&si); | ||||
|   return si.dwPageSize; | ||||
| #    else | ||||
| #      ifdef _WRS_KERNEL | ||||
|   long size = FMT_POSIX_CALL(getpagesize()); | ||||
| #      else | ||||
|   long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE)); | ||||
| #      endif | ||||
|  | ||||
|   if (size < 0) | ||||
|     FMT_THROW(system_error(errno, FMT_STRING("cannot get memory page size"))); | ||||
|   return size; | ||||
| #    endif | ||||
| } | ||||
| #  endif | ||||
|  | ||||
| namespace detail { | ||||
|  | ||||
| void file_buffer::grow(size_t) { | ||||
|   if (this->size() == this->capacity()) flush(); | ||||
| } | ||||
|  | ||||
| file_buffer::file_buffer(cstring_view path, | ||||
|                          const detail::ostream_params& params) | ||||
|     : file_(path, params.oflag) { | ||||
|   set(new char[params.buffer_size], params.buffer_size); | ||||
| } | ||||
|  | ||||
| file_buffer::file_buffer(file_buffer&& other) | ||||
|     : detail::buffer<char>(other.data(), other.size(), other.capacity()), | ||||
|       file_(std::move(other.file_)) { | ||||
|   other.clear(); | ||||
|   other.set(nullptr, 0); | ||||
| } | ||||
|  | ||||
| file_buffer::~file_buffer() { | ||||
|   flush(); | ||||
|   delete[] data(); | ||||
| } | ||||
| }  // namespace detail | ||||
|  | ||||
| ostream::~ostream() = default; | ||||
| #endif  // FMT_USE_FCNTL | ||||
| FMT_END_NAMESPACE | ||||
| @@ -1,22 +0,0 @@ | ||||
| HFSUTILS_SRCS = \ | ||||
| 	dep/hfsutils/libhfs/block.c \ | ||||
| 	dep/hfsutils/libhfs/btree.c \ | ||||
| 	dep/hfsutils/libhfs/data.c \ | ||||
| 	dep/hfsutils/libhfs/file.c \ | ||||
| 	dep/hfsutils/libhfs/hfs.c \ | ||||
| 	dep/hfsutils/libhfs/low.c \ | ||||
| 	dep/hfsutils/libhfs/medium.c \ | ||||
| 	dep/hfsutils/libhfs/memcmp.c \ | ||||
| 	dep/hfsutils/libhfs/node.c \ | ||||
| 	dep/hfsutils/libhfs/record.c \ | ||||
| 	dep/hfsutils/libhfs/version.c \ | ||||
| 	dep/hfsutils/libhfs/volume.c \ | ||||
| 	 | ||||
| HFSUTILS_OBJS = $(patsubst %.c, $(OBJDIR)/%.o, $(HFSUTILS_SRCS)) | ||||
| $(HFSUTILS_OBJS): CFLAGS += -Idep/hfsutils/libhfs | ||||
| HFSUTILS_LIB = $(OBJDIR)/libhfsutils.a | ||||
| $(HFSUTILS_LIB): $(HFSUTILS_OBJS) | ||||
| HFSUTILS_CFLAGS = -Idep/hfsutils/libhfs | ||||
| HFSUTILS_LDFLAGS = | ||||
| OBJS += $(HFSUTILS_OBJS) | ||||
|  | ||||
							
								
								
									
										25
									
								
								dep/hfsutils/build.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								dep/hfsutils/build.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| from build.c import clibrary | ||||
|  | ||||
| clibrary( | ||||
|     name="hfsutils", | ||||
|     srcs=[ | ||||
|         "./libhfs/block.c", | ||||
|         "./libhfs/btree.c", | ||||
|         "./libhfs/data.c", | ||||
|         "./libhfs/file.c", | ||||
|         "./libhfs/hfs.c", | ||||
|         "./libhfs/low.c", | ||||
|         "./libhfs/medium.c", | ||||
|         "./libhfs/memcmp.c", | ||||
|         "./libhfs/node.c", | ||||
|         "./libhfs/record.c", | ||||
|         "./libhfs/version.c", | ||||
|         "./libhfs/volume.c", | ||||
|     ], | ||||
|     hdrs={ | ||||
|         "apple.h": "./libhfs/apple.h", | ||||
|         "hfs.h": "./libhfs/hfs.h", | ||||
|         "libhfs.h": "./libhfs/libhfs.h", | ||||
|         "os.h": "./libhfs/os.h", | ||||
|     }, | ||||
| ) | ||||
| @@ -1,61 +0,0 @@ | ||||
| LIBUSBP_SRCS = \ | ||||
| 	dep/libusbp/src/async_in_pipe.c \ | ||||
| 	dep/libusbp/src/error.c \ | ||||
| 	dep/libusbp/src/error_hresult.c \ | ||||
| 	dep/libusbp/src/find_device.c \ | ||||
| 	dep/libusbp/src/list.c \ | ||||
| 	dep/libusbp/src/pipe_id.c \ | ||||
| 	dep/libusbp/src/string.c \ | ||||
| 	 | ||||
| ifeq ($(OS), Windows_NT) | ||||
|  | ||||
| LIBUSBP_LDFLAGS += -lsetupapi -lwinusb -lole32 -luuid | ||||
| LIBUSBP_SRCS += \ | ||||
| 	dep/libusbp/src/windows/async_in_transfer_windows.c \ | ||||
| 	dep/libusbp/src/windows/device_instance_id_windows.c \ | ||||
| 	dep/libusbp/src/windows/device_windows.c \ | ||||
| 	dep/libusbp/src/windows/error_windows.c \ | ||||
| 	dep/libusbp/src/windows/generic_handle_windows.c \ | ||||
| 	dep/libusbp/src/windows/generic_interface_windows.c \ | ||||
| 	dep/libusbp/src/windows/interface_windows.c \ | ||||
| 	dep/libusbp/src/windows/list_windows.c \ | ||||
| 	dep/libusbp/src/windows/serial_port_windows.c \ | ||||
|  | ||||
| else ifeq ($(shell uname),Darwin) | ||||
|  | ||||
| LIBUSBP_SRCS += \ | ||||
| 	dep/libusbp/src/mac/async_in_transfer_mac.c \ | ||||
| 	dep/libusbp/src/mac/device_mac.c \ | ||||
| 	dep/libusbp/src/mac/error_mac.c \ | ||||
| 	dep/libusbp/src/mac/generic_handle_mac.c \ | ||||
| 	dep/libusbp/src/mac/generic_interface_mac.c \ | ||||
| 	dep/libusbp/src/mac/iokit_mac.c \ | ||||
| 	dep/libusbp/src/mac/list_mac.c \ | ||||
| 	dep/libusbp/src/mac/serial_port_mac.c \ | ||||
|  | ||||
| else | ||||
|  | ||||
| LIBUSBP_CFLAGS += $(shell pkg-config --cflags libudev) | ||||
| LIBUSBP_LDFLAGS += $(shell pkg-config --libs libudev) | ||||
| LIBUSBP_SRCS += \ | ||||
| 	dep/libusbp/src/linux/async_in_transfer_linux.c \ | ||||
| 	dep/libusbp/src/linux/device_linux.c \ | ||||
| 	dep/libusbp/src/linux/error_linux.c \ | ||||
| 	dep/libusbp/src/linux/generic_handle_linux.c \ | ||||
| 	dep/libusbp/src/linux/generic_interface_linux.c \ | ||||
| 	dep/libusbp/src/linux/list_linux.c \ | ||||
| 	dep/libusbp/src/linux/serial_port_linux.c \ | ||||
| 	dep/libusbp/src/linux/udev_linux.c \ | ||||
| 	dep/libusbp/src/linux/usbfd_linux.c \ | ||||
|  | ||||
| endif | ||||
|  | ||||
| LIBUSBP_OBJS = $(patsubst %.c, $(OBJDIR)/%.o, $(LIBUSBP_SRCS)) | ||||
| $(LIBUSBP_OBJS): private CFLAGS += -Idep/libusbp/src -Idep/libusbp/include | ||||
| LIBUSBP_LIB = $(OBJDIR)/libusbp.a | ||||
| LIBUSBP_CFLAGS += -Idep/libusbp/include | ||||
| LIBUSBP_LDFLAGS += | ||||
| $(LIBUSBP_LIB): $(LIBUSBP_OBJS) | ||||
| OBJS += $(LIBUSBP_OBJS) | ||||
|  | ||||
|  | ||||
							
								
								
									
										72
									
								
								dep/libusbp/build.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								dep/libusbp/build.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| from build.ab import emit | ||||
| from build.c import clibrary | ||||
| from build.pkg import package | ||||
| from config import windows, osx, unix | ||||
|  | ||||
| srcs = [ | ||||
|     "./src/async_in_pipe.c", | ||||
|     "./src/error.c", | ||||
|     "./src/error_hresult.c", | ||||
|     "./src/find_device.c", | ||||
|     "./src/list.c", | ||||
|     "./src/pipe_id.c", | ||||
|     "./src/string.c", | ||||
|     "./src/libusbp_internal.h", | ||||
|     "./include/libusbp_config.h", | ||||
|     "./include/libusbp.h", | ||||
| ] | ||||
| deps = [] | ||||
| ldflags = [] | ||||
|  | ||||
| if windows: | ||||
|     srcs += [ | ||||
|         "./src/windows/async_in_transfer_windows.c", | ||||
|         "./src/windows/device_instance_id_windows.c", | ||||
|         "./src/windows/device_windows.c", | ||||
|         "./src/windows/error_windows.c", | ||||
|         "./src/windows/generic_handle_windows.c", | ||||
|         "./src/windows/generic_interface_windows.c", | ||||
|         "./src/windows/interface_windows.c", | ||||
|         "./src/windows/list_windows.c", | ||||
|         "./src/windows/serial_port_windows.c", | ||||
|     ] | ||||
|     ldflags += ["-lsetupapi", "-lwinusb", "-lole32", "-luuid"] | ||||
| elif osx: | ||||
|     srcs += [ | ||||
|         "./src/mac/async_in_transfer_mac.c", | ||||
|         "./src/mac/device_mac.c", | ||||
|         "./src/mac/error_mac.c", | ||||
|         "./src/mac/generic_handle_mac.c", | ||||
|         "./src/mac/generic_interface_mac.c", | ||||
|         "./src/mac/iokit_mac.c", | ||||
|         "./src/mac/list_mac.c", | ||||
|         "./src/mac/serial_port_mac.c", | ||||
|     ] | ||||
| else: | ||||
|     package(name="udev_lib", package="libudev") | ||||
|     srcs += [ | ||||
|         "./src/linux/async_in_transfer_linux.c", | ||||
|         "./src/linux/device_linux.c", | ||||
|         "./src/linux/error_linux.c", | ||||
|         "./src/linux/generic_handle_linux.c", | ||||
|         "./src/linux/generic_interface_linux.c", | ||||
|         "./src/linux/list_linux.c", | ||||
|         "./src/linux/serial_port_linux.c", | ||||
|         "./src/linux/udev_linux.c", | ||||
|         "./src/linux/usbfd_linux.c", | ||||
|     ] | ||||
|     deps += [".+udev_lib"] | ||||
|  | ||||
| clibrary( | ||||
|     name="libusbp", | ||||
|     srcs=srcs, | ||||
|     cflags=["-Idep/libusbp/include", "-Idep/libusbp/src"], | ||||
|     caller_ldflags=ldflags, | ||||
|     deps=deps, | ||||
|     hdrs={ | ||||
|         "libusbp_internal.h": "./src/libusbp_internal.h", | ||||
|         "libusbp_config.h": "./include/libusbp_config.h", | ||||
|         "libusbp.hpp": "./include/libusbp.hpp", | ||||
|         "libusbp.h": "./include/libusbp.h", | ||||
|     }, | ||||
| ) | ||||
| @@ -234,7 +234,7 @@ namespace libusbp | ||||
|         } | ||||
|  | ||||
|         /*! Wrapper for libusbp_error_get_message(). */ | ||||
|         virtual const char * what() const noexcept | ||||
|         virtual const char * what() const noexcept override | ||||
|         { | ||||
|             return libusbp_error_get_message(pointer); | ||||
|         } | ||||
|   | ||||
							
								
								
									
										103
									
								
								dep/libusbp/src/dummy.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								dep/libusbp/src/dummy.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
|  | ||||
| // This file contains failing place-holders to make things compile | ||||
| // on otherwise unsupported platforms. | ||||
|  | ||||
| #include <libusbp_internal.h> | ||||
|  | ||||
| struct libusbp_device | ||||
| { | ||||
|     char* syspath; | ||||
|     char* serial_number; // may be NULL | ||||
|     uint16_t product_id; | ||||
|     uint16_t vendor_id; | ||||
|     uint16_t revision; | ||||
| }; | ||||
|  | ||||
| static libusbp_error* fail() | ||||
| { | ||||
|     return error_create("USB hardware is not supported on this platform"); | ||||
| } | ||||
|  | ||||
| libusbp_error* libusbp_device_copy( | ||||
|     const libusbp_device* source, libusbp_device** dest) | ||||
| { | ||||
|     return fail(); | ||||
| } | ||||
|  | ||||
| libusbp_error* libusbp_generic_interface_create(const libusbp_device* device, | ||||
|     uint8_t interface_number, | ||||
|     bool composite __attribute__((unused)), | ||||
|     libusbp_generic_interface** gi) | ||||
| { | ||||
|     return fail(); | ||||
| } | ||||
|  | ||||
| libusbp_error* libusbp_generic_handle_open( | ||||
|     const libusbp_generic_interface* gi, libusbp_generic_handle** handle) | ||||
| { | ||||
|     return fail(); | ||||
| } | ||||
|  | ||||
| void libusbp_device_free(libusbp_device* device) {} | ||||
|  | ||||
| void libusbp_generic_handle_close(libusbp_generic_handle* handle) {} | ||||
|  | ||||
| void libusbp_generic_interface_free(libusbp_generic_interface* gi) {} | ||||
|  | ||||
| libusbp_error* libusbp_device_get_vendor_id( | ||||
|     const libusbp_device* device, uint16_t* vendor_id) | ||||
| { | ||||
|     return fail(); | ||||
| } | ||||
|  | ||||
| libusbp_error* libusbp_device_get_product_id( | ||||
|     const libusbp_device* device, uint16_t* product_id) | ||||
| { | ||||
|     return fail(); | ||||
| } | ||||
|  | ||||
| libusbp_error* libusbp_device_get_serial_number( | ||||
|     const libusbp_device* device, char** serial_number) | ||||
| { | ||||
|     return fail(); | ||||
| } | ||||
|  | ||||
| libusbp_error* libusbp_write_pipe(libusbp_generic_handle* handle, | ||||
|     uint8_t pipe_id, | ||||
|     const void* data, | ||||
|     size_t size, | ||||
|     size_t* transferred) | ||||
| { | ||||
|     return fail(); | ||||
| } | ||||
|  | ||||
| libusbp_error* libusbp_read_pipe(libusbp_generic_handle* handle, | ||||
|     uint8_t pipe_id, | ||||
|     void* data, | ||||
|     size_t size, | ||||
|     size_t* transferred) | ||||
| { | ||||
|     return fail(); | ||||
| } | ||||
|  | ||||
| libusbp_error* libusbp_serial_port_create(const libusbp_device* device, | ||||
|     uint8_t interface_number, | ||||
|     bool composite, | ||||
|     libusbp_serial_port** port) | ||||
| { | ||||
|     return fail(); | ||||
| } | ||||
|  | ||||
| libusbp_error* libusbp_serial_port_get_name( | ||||
|     const libusbp_serial_port* port, char** name) | ||||
| { | ||||
|     return fail(); | ||||
| } | ||||
|  | ||||
| void libusbp_serial_port_free(libusbp_serial_port* port) {} | ||||
|  | ||||
| libusbp_error* libusbp_list_connected_devices( | ||||
|     libusbp_device*** device_list, size_t* device_count) | ||||
| { | ||||
|     return fail(); | ||||
| } | ||||
							
								
								
									
										49
									
								
								dep/snowhouse/build.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								dep/snowhouse/build.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| from build.c import cxxlibrary | ||||
|  | ||||
| cxxlibrary( | ||||
|     name="snowhouse", | ||||
|     hdrs={ | ||||
|         "snowhouse/snowhouse.h": "./include/snowhouse/snowhouse.h", | ||||
|         "snowhouse/assert.h": "./include/snowhouse/assert.h", | ||||
|         "snowhouse/fluent/fluent.h": "./include/snowhouse/fluent/fluent.h", | ||||
|         "snowhouse/fluent/constraintadapter.h": "./include/snowhouse/fluent/constraintadapter.h", | ||||
|         "snowhouse/fluent/constraintlist.h": "./include/snowhouse/fluent/constraintlist.h", | ||||
|         "snowhouse/fluent/operators/andoperator.h": "./include/snowhouse/fluent/operators/andoperator.h", | ||||
|         "snowhouse/fluent/operators/invalidexpressionexception.h": "./include/snowhouse/fluent/operators/invalidexpressionexception.h", | ||||
|         "snowhouse/fluent/operators/collections/collectionoperator.h": "./include/snowhouse/fluent/operators/collections/collectionoperator.h", | ||||
|         "snowhouse/fluent/operators/collections/collectionconstraintevaluator.h": "./include/snowhouse/fluent/operators/collections/collectionconstraintevaluator.h", | ||||
|         "snowhouse/fluent/operators/collections/atleastoperator.h": "./include/snowhouse/fluent/operators/collections/atleastoperator.h", | ||||
|         "snowhouse/fluent/operators/collections/noneoperator.h": "./include/snowhouse/fluent/operators/collections/noneoperator.h", | ||||
|         "snowhouse/fluent/operators/collections/atmostoperator.h": "./include/snowhouse/fluent/operators/collections/atmostoperator.h", | ||||
|         "snowhouse/fluent/operators/collections/alloperator.h": "./include/snowhouse/fluent/operators/collections/alloperator.h", | ||||
|         "snowhouse/fluent/operators/collections/exactlyoperator.h": "./include/snowhouse/fluent/operators/collections/exactlyoperator.h", | ||||
|         "snowhouse/fluent/operators/notoperator.h": "./include/snowhouse/fluent/operators/notoperator.h", | ||||
|         "snowhouse/fluent/operators/constraintoperator.h": "./include/snowhouse/fluent/operators/constraintoperator.h", | ||||
|         "snowhouse/fluent/operators/oroperator.h": "./include/snowhouse/fluent/operators/oroperator.h", | ||||
|         "snowhouse/fluent/expressionbuilder.h": "./include/snowhouse/fluent/expressionbuilder.h", | ||||
|         "snowhouse/assertionexception.h": "./include/snowhouse/assertionexception.h", | ||||
|         "snowhouse/exceptions.h": "./include/snowhouse/exceptions.h", | ||||
|         "snowhouse/stringizers.h": "./include/snowhouse/stringizers.h", | ||||
|         "snowhouse/macros.h": "./include/snowhouse/macros.h", | ||||
|         "snowhouse/constraints/equalscontainerconstraint.h": "./include/snowhouse/constraints/equalscontainerconstraint.h", | ||||
|         "snowhouse/constraints/islessthanorequaltoconstraint.h": "./include/snowhouse/constraints/islessthanorequaltoconstraint.h", | ||||
|         "snowhouse/constraints/equalsconstraint.h": "./include/snowhouse/constraints/equalsconstraint.h", | ||||
|         "snowhouse/constraints/isgreaterthanconstraint.h": "./include/snowhouse/constraints/isgreaterthanconstraint.h", | ||||
|         "snowhouse/constraints/fulfillsconstraint.h": "./include/snowhouse/constraints/fulfillsconstraint.h", | ||||
|         "snowhouse/constraints/endswithconstraint.h": "./include/snowhouse/constraints/endswithconstraint.h", | ||||
|         "snowhouse/constraints/constraints.h": "./include/snowhouse/constraints/constraints.h", | ||||
|         "snowhouse/constraints/haslengthconstraint.h": "./include/snowhouse/constraints/haslengthconstraint.h", | ||||
|         "snowhouse/constraints/startswithconstraint.h": "./include/snowhouse/constraints/startswithconstraint.h", | ||||
|         "snowhouse/constraints/equalswithdeltaconstraint.h": "./include/snowhouse/constraints/equalswithdeltaconstraint.h", | ||||
|         "snowhouse/constraints/isgreaterthanorequaltoconstraint.h": "./include/snowhouse/constraints/isgreaterthanorequaltoconstraint.h", | ||||
|         "snowhouse/constraints/containsconstraint.h": "./include/snowhouse/constraints/containsconstraint.h", | ||||
|         "snowhouse/constraints/islessthanconstraint.h": "./include/snowhouse/constraints/islessthanconstraint.h", | ||||
|         "snowhouse/constraints/isemptyconstraint.h": "./include/snowhouse/constraints/isemptyconstraint.h", | ||||
|         "snowhouse/constraints/expressions/andexpression.h": "./include/snowhouse/constraints/expressions/andexpression.h", | ||||
|         "snowhouse/constraints/expressions/orexpression.h": "./include/snowhouse/constraints/expressions/orexpression.h", | ||||
|         "snowhouse/constraints/expressions/expression_fwd.h": "./include/snowhouse/constraints/expressions/expression_fwd.h", | ||||
|         "snowhouse/constraints/expressions/notexpression.h": "./include/snowhouse/constraints/expressions/notexpression.h", | ||||
|         "snowhouse/constraints/expressions/expression.h": "./include/snowhouse/constraints/expressions/expression.h", | ||||
|         "snowhouse/stringize.h": "./include/snowhouse/stringize.h", | ||||
|     }, | ||||
| ) | ||||
| @@ -1,23 +0,0 @@ | ||||
| ifeq ($(shell $(PKG_CONFIG) stb; echo $$?), 0) | ||||
|  | ||||
| # System libstb present. | ||||
|  | ||||
| STB_LIB = | ||||
| STB_CFLAGS := $(shell $(PKG_CONFIG) --cflags stb) | ||||
| STB_LDFLAGS := $(shell $(PKG_CONFIG) --libs stb) | ||||
|  | ||||
| else | ||||
|  | ||||
| STB_SRCS = \ | ||||
| 	dep/stb/stb_image_write.c | ||||
| 	 | ||||
| STB_OBJS = $(patsubst %.c, $(OBJDIR)/%.o, $(STB_SRCS)) | ||||
| $(STB_OBJS): CFLAGS += -Idep/stb/src | ||||
| STB_LIB = $(OBJDIR)/libstb.a | ||||
| $(STB_LIB): $(STB_OBJS) | ||||
| STB_CFLAGS = | ||||
| STB_LDFLAGS = $(STB_LIB) | ||||
| OBJS += $(STB_OBJS) | ||||
|  | ||||
| endif | ||||
|  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user