Compare commits

...

241 Commits
lif ... protos

Author SHA1 Message Date
David Given
dc6af483a5 Remember to build the drivetypes table. 2024-08-12 17:32:13 +02:00
David Given
9a0b487f4b Remember to build the formats table. 2024-08-12 17:26:28 +02:00
David Given
cac4d1ce86 Encode all the protos in one go (per library), as it's vastly faster. 2024-08-12 12:36:39 +02:00
David Given
7a3a31a929 Merge pull request #759 from davidgiven/a2r
Improve the A2R writer.
2024-07-31 23:45:51 +02:00
David Given
eee6f95b15 Typo fix. 2024-07-31 13:48:06 +02:00
David Given
7a3d10451d Rework the A2R writer to be a bit less broken. 2024-07-30 22:54:59 +02:00
David Given
e4f1a5a06f Merge pull request #752 from davidgiven/tartu
Add encoder support for the Tartu format.
2024-05-14 21:48:36 +02:00
David Given
500fcde21b Merge. 2024-05-14 21:41:30 +02:00
David Given
eb363a4b2a Update Tartu documentation. 2024-05-14 21:40:50 +02:00
David Given
8a78e609b0 And fix everywhere else... 2024-05-13 23:41:37 +02:00
David Given
15c67b8cc1 Bash into workingness on OSX. 2024-05-13 23:27:53 +02:00
David Given
00e9c5a07f Add support for updating file metadata (only the SRA bits, really). 2024-05-13 21:44:58 +02:00
David Given
7643457374 Add support for renaming files. 2024-05-13 21:12:42 +02:00
David Given
78d5584e21 Add creeate, put and delete support to the CP/M filesystem driver. 2024-05-13 00:32:57 +02:00
David Given
1d1143a893 Merge from master. 2024-05-10 00:19:57 +02:00
David Given
91093e1304 Merge pull request #754 from davidgiven/greaseweazle
Correctly twiddle DTR on Linux/OSX when changing baud rates.
2024-05-01 19:11:57 +02:00
David Given
1175a06f3d Merge from master. 2024-05-01 16:23:59 +02:00
David Given
6e5abd1189 Merge from master. 2024-05-01 16:23:38 +02:00
David Given
34f97384e7 Merge pull request #753 from davidgiven/osx
Fix OSX build problems.
2024-05-01 16:23:09 +02:00
David Given
653a6a0189 Be more consistent about DTR toggling (needed to reset serial devices). 2024-05-01 12:54:22 +02:00
David Given
f0b1b61eac Merge pull request #749 from p-j-b/fix-hang-windows-adafruit-floppy-greaseweazle
Set DTR after calling SetCommState
2024-05-01 12:46:08 +02:00
David Given
c0fd121bdf Restore build script to normal. 2024-05-01 00:25:41 +02:00
David Given
b805b86ddb Fix truncate arg ordering because of stupid OSX. 2024-05-01 00:25:10 +02:00
David Given
654e7e750c Fix truncate arg ordering because of stupid OSX. 2024-05-01 00:25:10 +02:00
David Given
7501fcfe8b Looks like compiling protobuf files now requires access to the protobuf
libraries.
2024-05-01 00:18:18 +02:00
David Given
fdb7837e03 Looks like compiling protobuf files now requires access to the protobuf
libraries.
2024-05-01 00:18:18 +02:00
David Given
1c57cea483 Try and debug the OSX build failure. 2024-05-01 00:00:30 +02:00
David Given
0c8e8d4d69 Remember to mark the 40-track format as being such. 2024-04-30 23:09:45 +02:00
David Given
8876aae2cc Calculate gaps in bits, not bytes (more accurate). Pad the end of the track to
avoid weirdness reading the last sector.
2024-04-30 23:09:30 +02:00
David Given
3e053b32e2 Display a useful command to repeat a test if one fails. 2024-04-30 23:07:10 +02:00
David Given
0611728537 Don't try to change the build system just yet. 2024-04-30 21:32:58 +02:00
David Given
a84cf83ce5 Add a prototype Tartu encoder. 2024-04-30 00:56:26 +02:00
David Given
c064aa7862 Merge pull request #751 from davidgiven/tartu
Add support for the Tartu Palivere.
2024-04-23 22:21:05 +02:00
David Given
195f7126cc Update link. 2024-04-23 21:58:42 +02:00
David Given
50d466c9c1 Update Tartu documentation. 2024-04-23 21:56:42 +02:00
David Given
5763574634 Update documentation. 2024-04-21 01:18:17 +02:00
David Given
2da568b3e8 Update the Tartu documentation. 2024-04-21 00:35:39 +02:00
David Given
2732d9aec8 Get the Tartu checksums working, and hook up the CP/M filesystem code. 2024-04-21 00:17:11 +02:00
David Given
15d34aff15 Work-in-progress Tartu decoder. 2024-04-20 01:20:49 +02:00
David Given
af3e257c78 Add boilerplate for the Tartu. 2024-04-19 21:10:49 +02:00
p-j-b
c2248c7e4a Added CLRDTR and SETDTR to setBaudRate
Fixes hang in Windows with Adafruit Floppy GreaseWeazle
2024-04-02 13:05:29 +01:00
David Given
a7967b6dc3 More release script tweaks. 2024-03-31 22:50:55 +02:00
David Given
c1f47921e6 Adjust release script. 2024-03-31 22:38:21 +02:00
David Given
cda93d516b Merge pull request #748 from davidgiven/windows
Switch from MSYS builds to WSL/Fedora builds.
2024-03-31 22:31:36 +02:00
David Given
8f9c12b26c Update the release build script. 2024-03-31 22:18:56 +02:00
David Given
cdb4e9ed21 Typo fix. 2024-03-31 22:00:27 +02:00
David Given
1a612c3db5 Pull the .a file out of fallback targets at make time, not at config time. 2024-03-31 21:53:40 +02:00
David Given
72ab957134 Remember to build C++ files with g++. 2024-03-31 21:44:12 +02:00
David Given
621523db62 Try not to build fallback packages unless necessary. 2024-03-31 21:30:26 +02:00
David Given
cdf9cc387c Finally, it works! 2024-03-31 18:42:37 +02:00
David Given
b84ecd289d Again. 2024-03-31 18:25:36 +02:00
David Given
d4cb8f414a Again. 2024-03-31 18:06:19 +02:00
David Given
8180c1f79e Again. 2024-03-31 17:47:16 +02:00
David Given
b23b21a7bf Again. 2024-03-31 17:38:36 +02:00
David Given
b30eff294d Again. 2024-03-31 15:45:54 +02:00
David Given
cacb397198 Again. 2024-03-31 15:36:28 +02:00
David Given
0f8c7d6969 Again. 2024-03-31 15:13:43 +02:00
David Given
7b35232cad Again. 2024-03-31 14:47:44 +02:00
David Given
43624796db Again. 2024-03-31 14:30:52 +02:00
David Given
bc17c624d3 Again. 2024-03-31 14:10:53 +02:00
David Given
61476ea0cc Again. 2024-03-31 13:59:19 +02:00
David Given
f0663030e1 Again. 2024-03-31 13:39:19 +02:00
David Given
989a11931b Add libssp. 2024-03-31 13:27:00 +02:00
David Given
94372a7f09 Again. 2024-03-31 13:12:39 +02:00
David Given
5c2702c6ab Again. 2024-03-31 13:07:07 +02:00
David Given
586c09f5c3 Again. 2024-03-31 12:53:49 +02:00
David Given
7a94123f0d Again. 2024-03-31 12:31:58 +02:00
David Given
4cad34a8a4 Update ccpp.yml 2024-03-31 00:30:14 +01:00
David Given
c0ef3215df Update ccpp.yml 2024-03-30 23:48:40 +01:00
David Given
08982aae7a Update ccpp.yml 2024-03-30 23:34:38 +01:00
David Given
6366ac6639 Update ccpp.yml 2024-03-30 23:08:14 +01:00
David Given
3807d22a78 Update ccpp.yml 2024-03-30 22:57:18 +01:00
David Given
3adbfd7ef5 Update ccpp.yml 2024-03-30 22:52:56 +01:00
David Given
7e40dfa5da Update ccpp.yml 2024-03-30 22:45:15 +01:00
David Given
62ddca2bb4 Update ccpp.yml 2024-03-30 22:44:20 +01:00
David Given
1a59e5065d Update ccpp.yml 2024-03-30 22:36:39 +01:00
David Given
52c0c409e9 Update ccpp.yml 2024-03-30 22:35:28 +01:00
David Given
e74b16d28b Update ccpp.yml 2024-03-30 22:29:37 +01:00
David Given
c2369bcc31 Again. 2024-03-30 22:23:26 +01:00
David Given
2636352a49 Try doing real work. 2024-03-30 23:03:57 +01:00
David Given
222a88f097 Again. 2024-03-30 21:01:14 +01:00
David Given
dbc691726d Again. 2024-03-30 20:55:04 +01:00
David Given
9ff3aedf18 Again. 2024-03-30 20:53:20 +01:00
David Given
8303a1fbca Again. 2024-03-30 20:51:12 +01:00
David Given
0f584ee343 Can we install the Fedora WSL system? 2024-03-30 20:50:18 +01:00
David Given
aafad0a628 Install the rest of the packages. 2024-03-30 20:35:08 +01:00
David Given
9d03951da9 Try installing OpenSUSE packages. 2024-03-30 20:28:53 +01:00
David Given
b15d6cb8e5 Try out a WSL github workflow. 2024-03-30 20:25:42 +01:00
David Given
f9c1816e6f Format. 2024-03-30 19:29:48 +01:00
David Given
d960b020ea Get the executables building on WSL2 Fedora. 2024-03-30 19:14:02 +01:00
David Given
72e9d57b15 Raw import of libfmt. 2024-03-30 14:09:18 +01:00
David Given
968b90dbab Merge pull request #747 from davidgiven/ab
Convert to the latest ab.
2024-03-30 00:35:22 +01:00
David Given
2bccdcc93b Disable more Windows builds. 2024-03-30 00:25:01 +01:00
David Given
ce2a5eb6d9 Disable Windows builds. 2024-03-30 00:23:26 +01:00
David Given
353e4f6210 Try to fix OSX build. 2024-03-30 00:20:56 +01:00
David Given
c115de9d40 Update to build with ab. 2024-03-29 23:53:05 +01:00
David Given
df83b558bf Merge pull request #742 from davidgiven/devices
Don't print the detection banner if no devices were detected.
2024-01-30 22:59:18 +01:00
David Given
7c2b5f116d Don't print the detection banner if no devices were detected. 2024-01-30 22:58:40 +01:00
David Given
30fe75f9bf Merge pull request #741 from davidgiven/devices
Add a command to list detectable devices on the command line.
2024-01-30 22:57:01 +01:00
David Given
401e7a9edb The rpm command now defaults to use real hardware, like it should. 2024-01-30 22:36:16 +01:00
David Given
fd4ddc56f2 Add a command to list detectable devices on the command line. 2024-01-30 21:44:11 +01:00
David Given
83d907bf71 Do parallel builds on OSX. 2024-01-30 21:28:03 +01:00
David Given
327bc76c6e Another try at making OSX builds work. 2024-01-22 22:31:51 +01:00
David Given
fdd39fb2d8 Try to fix OSX builds. 2024-01-22 22:16:49 +01:00
David Given
bfcfa8eb19 Merge pull request #738 from davidgiven/overrides
Fix a whole pile of missing 'override' keywords.
2024-01-22 21:08:27 +01:00
David Given
7095c03e28 Fix a whole pile of missing 'override' keywords. 2024-01-22 20:55:38 +01:00
David Given
45e796f15f Merge pull request #736 from davidgiven/ab
Remove stray files.
2024-01-07 23:20:02 +01:00
David Given
3d1dcd6874 imagemagick is just too much trouble for creating icons, so use png2ico instead. 2024-01-08 00:05:18 +01:00
David Given
0033d0759f 32-bit imagemagick has gone. 2024-01-07 21:29:06 +01:00
David Given
53f7dfe6c9 Remove stray files. 2024-01-07 21:24:53 +01:00
David Given
75446de29b Merge pull request #732 from davidgiven/acorn
Update the acorndfs format so that writes actually work.
2023-12-12 23:45:47 +00:00
David Given
1d119d6921 Update the acorndfs format so that writes actually work. 2023-12-13 00:31:12 +01:00
David Given
7462bd995f Merge pull request #731 from davidgiven/ab
Update ab. You can now build individual tools individually.
2023-12-12 22:31:48 +00:00
David Given
0dd99efad3 Update ab. 2023-12-12 23:17:06 +01:00
David Given
1234e81463 Update ab. You can now build individual tools individually. 2023-12-12 23:11:09 +01:00
David Given
ea13d66e6b Merge pull request #725 from davidgiven/dmk
Add support for DMK directory streams.
2023-11-02 01:35:24 +01:00
David Given
a7cb7eb995 Add missing files... 2023-11-02 01:22:09 +01:00
David Given
29f5feb34d Add support for DMK directory streams. 2023-11-02 01:17:44 +01:00
David Given
5dc60db7b6 When installing files, remember to create the directories. 2023-10-31 00:48:50 +01:00
David Given
fb9f7fe445 Merge pull request #723 from davidgiven/fixes2
Miscellaneous bugfixes.
2023-10-30 23:54:18 +01:00
David Given
a548471652 Add missing files. 2023-10-30 23:35:27 +01:00
David Given
3e47d66644 Put back the standard binaries, tests, install, install-bin makefile targets. 2023-10-30 23:30:18 +01:00
David Given
3bfa45a80c Remember to build with optimisation on. 2023-10-30 23:11:20 +01:00
David Given
2d717af4db The flux and image file pickers can now create new files. 2023-10-30 23:07:36 +01:00
David Given
533b217c8f Eliminate the broken tpi system for a simple drive/format type field. 2023-10-29 21:10:14 +01:00
David Given
ff1fb761f2 Update documentation (last time was wrong). 2023-10-29 21:06:56 +01:00
David Given
95d49add2c Don't show '$formats' for the format list. 2023-10-29 11:18:21 +01:00
David Given
8b75609b70 Update line endings. 2023-10-29 11:18:05 +01:00
David Given
b8929dd589 Fix Windows dependencies. 2023-10-28 13:33:10 +02:00
David Given
2fd29f8786 Merge pull request #720 from davidgiven/build
Rework the build system... again.
2023-10-28 13:17:56 +02:00
David Given
38408820ca Update the release workflow. 2023-10-28 12:52:25 +02:00
David Given
43e6840e78 Try and set the imagemagick time limit? 2023-10-28 00:49:19 +01:00
David Given
15908c52bd Typo fix. 2023-10-27 22:12:46 +01:00
David Given
c90b0e7dc2 Try and fix dependencies again... 2023-10-27 22:10:00 +01:00
David Given
d2ff9806bd Enable build logging. 2023-10-27 21:47:22 +01:00
David Given
1e6993c12d Add missing dependency. 2023-10-27 21:39:55 +01:00
David Given
1122344016 Try to correctly build the manifest this time. 2023-10-27 21:28:47 +01:00
David Given
0dbce00fe4 Try building a Windows manifest. 2023-10-27 21:38:44 +02:00
David Given
5af0b68e06 Add the corpus tests. 2023-10-27 20:43:46 +02:00
dg
6038a11671 Update the README. 2023-10-26 19:31:58 +00:00
dg
dcb92db519 Remove old build system. 2023-10-26 19:29:01 +00:00
dg
dcaeabacc6 --no_warn_duplicate_libraries is apparently too new for github CI... 2023-10-26 19:08:21 +00:00
dg
a2a5c7eff0 Build Windows with all CPUs. 2023-10-26 19:07:43 +00:00
dg
e1cf927bf3 Typo fix. 2023-10-26 18:35:21 +00:00
dg
8fd98d674a Additional windows fixes. 2023-10-26 18:26:10 +00:00
David Given
fd884027c0 Try using the mingw python. 2023-10-26 01:28:58 +02:00
dg
26bd467f79 Make the Windows binaries build. 2023-10-25 21:55:40 +00:00
David Given
c7f22c0dab Build the GUI on OSX. 2023-10-25 22:15:32 +02:00
David Given
92d44f6ae3 Add missing file. 2023-10-25 22:15:09 +02:00
David Given
9143f477b2 Build OSX with all CPUs. 2023-10-25 00:56:45 +02:00
David Given
1a519bf837 Attempt to make build on OSX. 2023-10-25 00:49:39 +02:00
David Given
ca6b90f8c1 Split C and C++ libraries, so that you can use C++ compiler flags. Build with
C++17.
2023-10-24 22:00:09 +02:00
David Given
44fc532d63 Build the documentation. 2023-10-24 00:49:05 +02:00
David Given
6a6cd025c0 Install Python on Windows. 2023-10-24 00:27:04 +02:00
David Given
d769f90704 Increase processor count. 2023-10-23 01:18:33 +02:00
David Given
9d8e3b21ba I think something's wrong with the apt installer. 2023-10-23 01:12:50 +02:00
David Given
dabdfec3e7 Try more setup. 2023-10-23 01:11:15 +02:00
David Given
6a00653d1e Don't use xxd to objectify files. 2023-10-23 01:03:28 +02:00
David Given
8fb786094f Something's wrong with Ubuntu's wx-config setup. 2023-10-23 00:00:29 +02:00
David Given
87e978c817 And again. 2023-10-22 23:10:52 +02:00
David Given
4a31046c9c Adjust dependencies, again... 2023-10-22 23:09:52 +02:00
David Given
db420b3495 Adjust the way packages are detected. 2023-10-22 23:07:20 +02:00
David Given
c81dc166bc Adjust dependencies. 2023-10-22 23:03:44 +02:00
David Given
07aa416975 Make the tests work. 2023-10-22 22:57:54 +02:00
David Given
627820cddc Build the utilities. 2023-10-22 21:35:27 +02:00
David Given
a24fe420c4 We can now build both the CLI and GUI binaries! 2023-10-22 21:20:47 +02:00
David Given
986be921f4 First working command-line executable. 2023-10-22 19:18:14 +02:00
David Given
f5f223f622 First steps towards reworking the build system... again. 2023-10-21 23:02:46 +02:00
David Given
bbdfa0d651 Merge pull request #717 from kristomu/const-correct
Fix const-correct/discards qualifiers error.
2023-09-27 10:08:26 +02:00
K. M
e6bb0cb463 Fix const-correct/discards qualifiers error. 2023-09-27 01:19:17 +02:00
David Given
9e61670116 Merge pull request #656 from davidgiven/psos
Improve pSOS file system handling.
2023-08-20 22:00:51 +02:00
David Given
3876c07164 Merge branch 'master' into psos 2023-08-20 21:42:13 +02:00
David Given
ed315eade9 Merge pull request #668 from davidgiven/ms2000
Add basic support for the MS2000 Microdos file system.
2023-08-19 23:54:27 +02:00
David Given
7456fd0c90 Make the MS2000 stuff work again. Write documentation. 2023-08-19 23:29:55 +02:00
David Given
44160e66ac Merge branch 'master' into ms2000 2023-08-19 22:59:31 +02:00
David Given
9bd969a57b Merge pull request #688 from davidgiven/lif
Add HP9122 support; fix HP9121 support.
2023-08-19 22:55:39 +02:00
David Given
0b585078d8 Merge pull request #704 from ejona86/micropolis-ecc
Micropolis: Add Vector ECC support
2023-08-19 21:54:22 +02:00
David Given
0d495ed934 Merge pull request #710 from davidgiven/usb
Make work on FreeBSD
2023-08-19 21:23:54 +02:00
David Given
95b703b1ea Tidy reporting of USB errors. 2023-08-19 20:46:41 +02:00
David Given
688061397b Adjust error messages. 2023-08-19 20:39:55 +02:00
Poul-Henning Kamp
1f00176455 Make the non-gui executable build on FreeBSD 2023-08-14 19:51:21 +00:00
David Given
90da6b1e72 Merge pull request #706 from ejona86/pkg-config-protobuf
Makefile: Eagerly run pkg-config for protobuf
2023-08-06 01:12:49 +02:00
Eric Anderson
4deb45dc3f Makefile: Eagerly run pkg-config for protobuf
Protobuf added a dependency on absl and now pkg-config is incredibly
slow. `pkg-config --libs protobuf` and `--cflags` each take around 1.5
seconds on my laptop. Running pkg-config only once reduces a 100%
incremental build for 'make all' from 90 seconds to 3.2 seconds.

Unfortunately we will pay the 3 seconds every time we execute make, even
for something that doesn't need protobuf.
2023-08-05 13:02:50 -07:00
David Given
eeec5d106a Update missing file. 2023-08-02 14:08:38 +02:00
David Given
4e42d1d197 Release and ccpp workflows now run in different environments. 2023-08-02 14:08:19 +02:00
David Given
495d08c447 Merge pull request #705 from davidgiven/d20
Update D20 documentation.
2023-08-02 13:46:10 +02:00
David Given
1b859015ae Update documentation. 2023-08-02 13:42:23 +02:00
David Given
3db2109e01 Merge pull request #700 from davidgiven/d20
Add support for the Roland-D20 filesystem.
2023-07-31 23:01:49 +01:00
David Given
294ac87503 Update documentation for the Roland D20 format. 2023-07-31 23:36:45 +02:00
David Given
c297adb0c7 Try to fix Mac builds. 2023-07-31 22:30:52 +02:00
David Given
446b965794 Handle Roland extents properly if the directory entries are in the wrong order.
Deal with block numbers >39 (they go in the bottom of the disk).
2023-07-31 22:20:08 +02:00
Eric Anderson
96d4df296d Micropolis: Add Vector ECC support 2023-07-29 14:03:08 -07:00
David Given
a149aac0e9 Merge pull request #702 from ejona86/micropolis-encodedecode
Micropolis: Fix encoder and decoder to support encodedecodetest
2023-07-29 17:20:58 +01:00
David Given
aacc7be9f3 Merge pull request #703 from ejona86/vgi-hcs
Micropolis: Add missing HCS order for VGI
2023-07-29 17:17:44 +01:00
Eric Anderson
7409955701 Micropolis: Add missing HCS order for VGI 2023-07-29 07:12:35 -07:00
Eric Anderson
c623d95a80 Micropolis: Fix encoder and decoder to support encodedecodetest
These changes should not impact reading/writing from real disks. This
includes a bug fix to Fluxmap where it might miss a trailing interval
when adding bits, as mentioned in #333.

With the Fluxmap bug fixed, the encoder now includes index pulses in its
output. The decoder was relaxed to allow reading precisely one track.

We don't actually add an encodedecodetest for micropolis, though,
because the SCP encoder is unhappy with so many revolutions.
2023-07-29 07:08:23 -07:00
David Given
1927cc7fe1 Fix issue where trying to rename files by clicking on the tree wasn't working. 2023-07-27 23:44:33 +02:00
David Given
4eca254daf Add support for renaming files. 2023-07-27 23:44:04 +02:00
David Given
c7d4fee3f6 Add support for deleting files. 2023-07-27 23:19:50 +02:00
David Given
a6f798ae5b Mangle and demangle filenames. Remember to write the correct extent numbers in
multiextent files.
2023-07-27 23:09:57 +02:00
David Given
c9ae836e52 Add very brittle write support. 2023-07-27 22:49:10 +02:00
David Given
e3ffa63f7f Make sure that the rotational speed is measured even if reads are done through
Browse Disk.
2023-07-27 22:14:48 +02:00
David Given
4ffc2cc1dc Add support for, hopefully, multi-extent files. 2023-07-27 00:30:44 +02:00
David Given
7f9ba14687 Correct erroneous index. 2023-07-26 22:37:56 +02:00
David Given
a24933e272 Merge from master. 2023-07-26 22:33:40 +02:00
David Given
20bdacbecf Add initial support for the Roland-D20 filesystem. 2023-07-26 22:31:20 +02:00
David Given
ab9d6cf5ed Merge pull request #699 from davidgiven/wx
UI improvements
2023-07-25 23:03:02 +01:00
David Given
1f5903a9a0 Don't use std::filesystem; it makes life harder on Windows with its wide
strings.
2023-07-25 23:35:01 +02:00
David Given
bb073b6bb3 Apparently Mingw can't automatically convert from path to string. 2023-07-25 23:23:04 +02:00
David Given
516241f8f5 Replace the image read file picker with a simple one. 2023-07-25 23:11:52 +02:00
David Given
977b6831a0 When reading Kryoflux streams, you can specify any file in the directory and it
will work (as the GUI now forces you to do this).
2023-07-25 22:48:17 +02:00
David Given
c61effb54f Add a file type box to the flux source selection page. 2023-07-25 22:27:09 +02:00
David Given
346d989944 When reading Kryoflux streams, allow the user to specify any file within the
directory and have it work (as that's what the GUI does now).
2023-07-25 22:51:34 +02:00
David Given
60a73c8d1e Add a file type box to the flux source selection page. 2023-07-25 22:27:09 +02:00
dg
e52db4a837 Typo fix. 2023-07-24 20:56:37 +00:00
dg
4e317643bc Try and install compatible versions of protobuf. 2023-07-24 20:53:51 +00:00
David Given
5f520bf375 Merge pull request #698 from davidgiven/zilogmcz
Add support for the ZDOS filesystem for the Zilog MCZ.
2023-07-24 22:16:33 +02:00
David Given
2efe521b3a Update documentation. 2023-07-24 21:48:37 +02:00
David Given
5c21103646 Get the ZDOS filesystem driver working. 2023-07-24 21:46:49 +02:00
David Given
9444696f37 Merge pull request #697 from davidgiven/ro
Allow read-only flux and image in the GUI.
2023-07-24 08:20:39 +02:00
David Given
082fe4e787 Hack in boilerplate for a ZDos filesystem. 2023-07-24 08:18:18 +02:00
David Given
5e13cf23f9 Allow read-only image reader/writers in the GUI. 2023-07-24 07:53:47 +02:00
David Given
8f98a1f557 Consolidate the image constructors in the same way that's been done for the
flux constructors.
2023-07-24 07:50:16 +02:00
David Given
5b21e8798b Allow read-only flux sources in the GUI. 2023-07-24 07:39:59 +02:00
David Given
b9ef5b7db8 Rename all the flux and image types to prefix the enums, due to them being in
the global namespace now.
2023-07-24 02:18:53 +02:00
David Given
9867f8c302 Combine enums for flux source/sink types. config.cc now knows whether they're
read-only, write-only, and read-write.
2023-07-24 00:50:54 +02:00
David Given
315889faf6 Warning fix. 2023-07-23 22:49:23 +02:00
David Given
798e8fee89 Merge pull request #692 from davidgiven/protobuf
Rename the `requires` config field to `prerequisite`
2023-07-08 00:43:15 +02:00
dg
e1c49db329 Use brew --prefix to detect the installation path when copying licenses from
packages.
2023-07-07 22:10:52 +00:00
dg
dae9537472 Warning fixes. 2023-07-07 21:51:24 +00:00
dg
1330d56cdd Fix a bunch of errors caused by changes to libfmt. 2023-07-07 21:32:21 +00:00
David Given
6ce3ce20d0 Remove stray debugging code. 2023-07-07 01:03:31 +02:00
David Given
362c5ee9b0 Rename the requires config field to prerequisite, as requires is about to
become a C++ keyword.
2023-07-07 00:34:03 +02:00
David Given
0f34ce0278 Merge pull request #690 from Deledrius/nsi-fix
Fix incorrect product name in installer.
2023-06-26 14:27:39 +02:00
Joseph Davies
0c27c7c4c8 Fix incorrect product name in installer. 2023-06-25 16:18:03 -07:00
dg
ba1f8b8ed8 Add missing file. Reformat. 2023-05-06 00:28:13 +00:00
dg
10605b3908 Add a read-only MS2000 file system, and a format (with no encoder or decoder). 2023-05-06 00:21:10 +00:00
dg
e31e547322 Add a routine to count the number of bits in a word. 2023-05-06 00:20:48 +00:00
dg
9484a1b870 Swap minutes and seconds, as this seems to be more correct. 2023-04-07 16:38:08 +00:00
dg
0a5a814a88 Typo fix. 2023-04-05 17:17:15 +00:00
dg
08ce455d1d Properly terminate pSOS filenames. Make a guess at the ctime format. 2023-04-05 17:13:49 +00:00
368 changed files with 30236 additions and 3290 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -1,4 +1,5 @@
.obj
.git
streams
.*\.flux
.*\.img

346
Makefile
View File

@@ -1,300 +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,,--608 --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

View File

@@ -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 -->

View File

@@ -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>

View File

@@ -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)

View File

@@ -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>

View File

@@ -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)

View File

@@ -1,7 +1,7 @@
#ifndef AMIGA_H
#define AMIGA_H
#include "encoders/encoders.h"
#include "lib/encoders/encoders.h"
#define AMIGA_SECTOR_RECORD 0xaaaa44894489LL

View File

@@ -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>

View File

@@ -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"

View File

@@ -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

View File

@@ -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>

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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"

View File

@@ -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
View 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",
],
)

View File

@@ -1,4 +1,4 @@
#include "globals.h"
#include "lib/globals.h"
#include "c64.h"
/*

View File

@@ -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

View File

@@ -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>

View File

@@ -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)
{
/*

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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"

View File

@@ -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>

View File

@@ -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"

View File

@@ -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:

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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"];
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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"

View File

@@ -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

View File

@@ -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>

View File

@@ -1,6 +1,4 @@
syntax = "proto2";
import "lib/common.proto";
message Smaky6DecoderProto {}

84
arch/tartu/decoder.cc Normal file
View 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
View 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
View 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
View 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" ];
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;

View File

@@ -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
View File

@@ -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
View 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
View 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
View 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
View 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()

View File

@@ -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
View 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
View 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
View 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,
)

View File

@@ -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
View 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
View 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

View File

@@ -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
View 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",
},
)

View File

@@ -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
View 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",
},
)

View File

@@ -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
View File

@@ -0,0 +1,3 @@
from build.c import clibrary
clibrary(name="emu", srcs=["./fnmatch.c"], hdrs={"fnmatch.h": "./fnmatch.h"})

View File

@@ -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
View 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
View 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
View 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
View 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
View File

File diff suppressed because it is too large Load Diff

27
dep/fmt/LICENSE Normal file
View 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
View File

@@ -0,0 +1,490 @@
<img src="https://user-images.githubusercontent.com/576385/156254208-f5b743a9-88cf-439d-b0c0-923d53e8d551.png" alt="{fmt}" width="25%"/>
[![image](https://github.com/fmtlib/fmt/workflows/linux/badge.svg)](https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux)
[![image](https://github.com/fmtlib/fmt/workflows/macos/badge.svg)](https://github.com/fmtlib/fmt/actions?query=workflow%3Amacos)
[![image](https://github.com/fmtlib/fmt/workflows/windows/badge.svg)](https://github.com/fmtlib/fmt/actions?query=workflow%3Awindows)
[![fmt is continuously fuzzed at oss-fuzz](https://oss-fuzz-build-logs.storage.googleapis.com/badges/fmt.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?\%0Acolspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20\%0ASummary&q=proj%3Dfmt&can=1)
[![Ask questions at StackOverflow with the tag fmt](https://img.shields.io/badge/stackoverflow-fmt-blue.svg)](https://stackoverflow.com/questions/tagged/fmt)
[![image](https://api.securityscorecards.dev/projects/github.com/fmtlib/fmt/badge)](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:
![image](https://github.com/fmtlib/fmt/assets/%0A576385/2a93c904-d6fa-4aa6-b453-2618e1c327d7)
# 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):
[![image](https://user-images.githubusercontent.com/576385/95684665-11719600-0ba8-11eb-8e5b-972ff4e49428.png)](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
View 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
View 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
View 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
View File

File diff suppressed because it is too large Load Diff

643
dep/fmt/include/fmt/color.h Normal file
View 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_

View 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
View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

4535
dep/fmt/include/fmt/format.h Normal file
View File

File diff suppressed because it is too large Load Diff

455
dep/fmt/include/fmt/os.h Normal file
View 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_

View 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_

View 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_

View 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
View 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
View 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
View 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
View 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
View 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

View File

@@ -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
View 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",
},
)

View File

@@ -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
View 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",
},
)

View File

@@ -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
View 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
View 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",
},
)

View File

@@ -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