, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return *(${NAME} *)instance; }")
if("${NAME}" STREQUAL "ScriptEvent")
string(APPEND SQUIRREL_EXPORT "\n template <> inline int Return<${NAME} *>(HSQUIRRELVM vm, ${NAME} *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, \"${REALNAME}\", res, nullptr, DefSQDestructorCallback<${NAME}>, true); return 1; }")
elseif("${NAME}" STREQUAL "ScriptText")
diff --git a/docs/company_colour_indexes.html b/docs/company_colour_indexes.html
new file mode 100644
index 0000000000..fb9dea7add
--- /dev/null
+++ b/docs/company_colour_indexes.html
@@ -0,0 +1,557 @@
+
+
+
+
+ OpenTTD Company Colour Indexes
+
+
+
+
+ Company Colour Indexes
+ Hex / dec indexes into the DOS palette
+
+ Visual representation of values derived from https://github.com/frosch123/TTDViewer/blob/master/src/recolor.xml#L186
+
+
+
+
+ | COLOUR_DARK_BLUE |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ | 0xc6 |
+ 0xc7 |
+ 0xc8 |
+ 0xc9 |
+ 0xca |
+ 0xcb |
+ 0xcc |
+ 0xcd |
+
+
+ | 198 |
+ 199 |
+ 200 |
+ 201 |
+ 202 |
+ 203 |
+ 204 |
+ 205 |
+
+
+
+ | COLOUR_PALE_GREEN |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ | 0x60 |
+ 0x61 |
+ 0x62 |
+ 0x63 |
+ 0x64 |
+ 0x65 |
+ 0x66 |
+ 0x67 |
+
+
+ | 96 |
+ 97 |
+ 98 |
+ 99 |
+ 100 |
+ 101 |
+ 102 |
+ 103 |
+
+
+
+ | COLOUR_PINK |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ | 0x2a |
+ 0x2b |
+ 0x2c |
+ 0x2d |
+ 0x2e |
+ 0x2f |
+ 0x30 |
+ 0x31 |
+
+
+ | 42 |
+ 43 |
+ 44 |
+ 45 |
+ 46 |
+ 47 |
+ 48 |
+ 49 |
+
+
+
+ | COLOUR_YELLOW |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ | 0x3e |
+ 0x3f |
+ 0x40 |
+ 0x41 |
+ 0x42 |
+ 0x43 |
+ 0x44 |
+ 0x45 |
+
+
+ | 62 |
+ 63 |
+ 64 |
+ 65 |
+ 66 |
+ 67 |
+ 68 |
+ 69 |
+
+
+
+ | COLOUR_RED |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ | 0xb3 |
+ 0xb4 |
+ 0xb5 |
+ 0xb6 |
+ 0xb7 |
+ 0xa4 |
+ 0xa5 |
+ 0xa6 |
+
+
+ | 179 |
+ 180 |
+ 181 |
+ 182 |
+ 183 |
+ 164 |
+ 165 |
+ 166 |
+
+
+
+ | COLOUR_LIGHT_BLUE |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ | 0x9a |
+ 0x9b |
+ 0x9c |
+ 0x9d |
+ 0x9e |
+ 0x9f |
+ 0xa0 |
+ 0xa1 |
+
+
+ | 154 |
+ 155 |
+ 156 |
+ 157 |
+ 158 |
+ 159 |
+ 160 |
+ 161 |
+
+
+
+ | COLOUR_GREEN |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ | 0x52 |
+ 0x53 |
+ 0x54 |
+ 0x55 |
+ 0xce |
+ 0xcf |
+ 0xd0 |
+ 0xd1 |
+
+
+ | 82 |
+ 83 |
+ 84 |
+ 85 |
+ 206 |
+ 207 |
+ 208 |
+ 209 |
+
+
+
+ | COLOUR_DARK_GREEN |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ | 0x58 |
+ 0x59 |
+ 0x5a |
+ 0x5b |
+ 0x5c |
+ 0x5d |
+ 0x5e |
+ 0x5f |
+
+
+ | 88 |
+ 89 |
+ 90 |
+ 91 |
+ 92 |
+ 93 |
+ 94 |
+ 95 |
+
+
+
+ | COLOUR_BLUE |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ | 0x92 |
+ 0x93 |
+ 0x94 |
+ 0x95 |
+ 0x96 |
+ 0x97 |
+ 0x98 |
+ 0x99 |
+
+
+ | 146 |
+ 147 |
+ 148 |
+ 149 |
+ 150 |
+ 151 |
+ 152 |
+ 153 |
+
+
+
+ | COLOUR_CREAM |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ | 0x72 |
+ 0x73 |
+ 0x74 |
+ 0x75 |
+ 0x76 |
+ 0x77 |
+ 0x78 |
+ 0x79 |
+
+
+ | 114 |
+ 115 |
+ 116 |
+ 117 |
+ 118 |
+ 119 |
+ 120 |
+ 121 |
+
+
+
+ | COLOUR_MAUVE |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ | 0x80 |
+ 0x81 |
+ 0x82 |
+ 0x83 |
+ 0x84 |
+ 0x85 |
+ 0x86 |
+ 0x87 |
+
+
+ | 128 |
+ 129 |
+ 130 |
+ 131 |
+ 132 |
+ 133 |
+ 134 |
+ 135 |
+
+
+
+ | COLOUR_PURPLE |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ | 0x88 |
+ 0x89 |
+ 0x8a |
+ 0x8b |
+ 0x8c |
+ 0x8d |
+ 0x8e |
+ 0x8f |
+
+
+ | 136 |
+ 137 |
+ 138 |
+ 139 |
+ 140 |
+ 141 |
+ 142 |
+ 143 |
+
+
+
+ | COLOUR_ORANGE |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ | 0x40 |
+ 0xc0 |
+ 0xc1 |
+ 0xc2 |
+ 0xc3 |
+ 0xc4 |
+ 0xc5 |
+ 0x27 |
+
+
+ | 64 |
+ 192 |
+ 193 |
+ 194 |
+ 195 |
+ 196 |
+ 197 |
+ 39 |
+
+
+
+ | COLOUR_BROWN |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ | 0x20 |
+ 0x21 |
+ 0x22 |
+ 0x23 |
+ 0x24 |
+ 0x25 |
+ 0x26 |
+ 0x27 |
+
+
+ | 32 |
+ 33 |
+ 34 |
+ 35 |
+ 36 |
+ 37 |
+ 38 |
+ 39 |
+
+
+
+ | COLOUR_GREY |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ | 0x4 |
+ 0x5 |
+ 0x6 |
+ 0x7 |
+ 0x8 |
+ 0x9 |
+ 0xa |
+ 0xb |
+
+
+ | 4 |
+ 5 |
+ 6 |
+ 7 |
+ 8 |
+ 9 |
+ 10 |
+ 11 |
+
+
+
+ | COLOUR_WHITE |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ | 0x8 |
+ 0x9 |
+ 0xa |
+ 0xb |
+ 0xc |
+ 0xd |
+ 0xe |
+ 0xf |
+
+
+ | 8 |
+ 9 |
+ 10 |
+ 11 |
+ 12 |
+ 13 |
+ 14 |
+ 15 |
+
+
+
+
+
diff --git a/docs/game_coordinator.md b/docs/game_coordinator.md
new file mode 100644
index 0000000000..8bf07d8027
--- /dev/null
+++ b/docs/game_coordinator.md
@@ -0,0 +1,83 @@
+# Game Coordinator
+
+To allow two players to play together, OpenTTD uses a Game Coordinator to
+facilitate this.
+
+When a server starts, it can register itself to the Game Coordinator. This
+happens when `server_game_type` is set to either `invite-only` or `public`.
+Upon registration, the Game Coordinator probes the network of the server, and
+assigns the server an unique code, called an `invite code`.
+
+When a client wants to join a server, it asks the Game Coordinator to help
+with this by giving it the `invite code` of the server. The Game Coordinator
+will, in this order, attempt several ways to connect the client and server
+together:
+
+## 1) Via direct IPv4 / IPv6
+
+Upon registration, the Game Coordinator probes the server to see if a
+direction connection to the server is possible based on the game port. It
+tries this over the public IPv4 and IPv6, as announced by the server.
+If either (or both) are successful, a client will always be asked to try
+these direct IPs first when it wants to connect to this server.
+
+- If the server is IPv4 only, the client is only asked to connect via IPv4.
+- If the server is IPv6 only, the client is only asked to connect via IPv6.
+- If the server is both IPv4 and IPv6, the client is asked to connect to to
+ one of those first. If that fails, it is asked to connect to the other.
+ Whether it tries IPv4 or IPv6 first, strongly depends on several network
+ infrastructure related events. The biggest influence is the network
+ latency over both protocols to the OpenTTD infrastructure.
+
+In the end, if either the server is not reachable directly from the Internet
+or the client fails to connect to either one of them, the connection attempt
+continues with the next available method.
+
+## 2) Via STUN
+
+When a client wants to join a server via STUN, both the client and server
+are asked to create a connection to the STUN server (normally
+`stun.openttd.org`) via both IPv4 and IPv6. If the client or server has no
+IPv4 or IPv6, it will not make a connection attempt via that protocol.
+
+The STUN server collects the public IPv4 and/or IPv6 of the client and server,
+together with the port the connection came in from. For most NAT gateways it
+holds true that as long as you use the same local IP + port, your public
+IP + port will remain the same, and allow for bi-directional communication.
+And this fact is used to later on pair the client and server.
+
+The STUN server reports this information directly to the Game Coordinator
+(this in contrast to most STUN implementation, where this information is
+first reported back to the peer itself, which has to relay it back to the
+coordinator. OpenTTD skips this step, as the STUN server can directly talk to
+the Game Coordinator). When the Game Coordinator sees a matching pair (in
+terms of IPv4 / IPv6), it will ask both the client and server to connect to
+their peer based on this public IP + port.
+
+As the NAT gateway forwards the traffic on the public IP + port to the local
+port, this creates a bi-directional socket between client and server. The
+connection to the STUN server can now safely be closed, and the client and
+server can continue to talk to each other.
+
+Some NAT gateways do not allow this method; for those this attempt will fail,
+and this also means that it is not possible to create a connection between
+the client and server.
+
+## 3) Via TURN
+
+As a last resort, the Game Coordinator can decide to connect the client and
+server together via TURN. TURN is a relay service, relaying the messages
+between client and server.
+
+As the client and server can already connect to the Game Coordinator, it is
+very likely this is successful.
+
+It is important to note that a relay service has full view of the traffic
+send between client and server, and as such it is important that you trust
+the relay service used.
+For official binaries, this relay service is hosted by openttd.org. The relay
+service as hosted by openttd.org only validates it is relaying valid OpenTTD
+packets and does no further inspection of the payload itself.
+Although in our experience most patch-packs also use the services as offered
+by openttd.org, it is possible they use different services. Please be mindful
+about this.
diff --git a/docs/multiplayer.md b/docs/multiplayer.md
index daccbf06d6..c7e1839cf3 100644
--- a/docs/multiplayer.md
+++ b/docs/multiplayer.md
@@ -48,6 +48,10 @@ Last updated: 2011-02-16
- click add server
- type in the ip address or hostname
- if you want to add a port use :
+ - If you want to play and you have the invite code of the game server you
+ want connect to.
+ - click add server
+ - type in the invite code
- Now you can select a company and press: "Join company", to help that company
- Or you can press "Spectate game", to spectate the game
- Or you can press "New company", and start your own company (if there are
@@ -110,9 +114,10 @@ Last updated: 2011-02-16
- You can let your server automatically restart a map when, let's say, year 2030
is reached. See 'set restart_game_date' for detail.
- - If you want to be on the server-list, enable Advertising. To do this, select
- 'Internet (advertise)' in the Start Server menu, or type in console:
- 'set server_advertise 1'.
+ - If you want to be on the server-list, make your server public. You can do
+ this either from the Start Server GUI, via the in-game Online Players GUI,
+ or by typing in the console:
+ 'set server_game_type public'.
- You can protect your server with a password via the console: 'set server_pw',
or via the Start Server menu.
diff --git a/docs/savegame_format.md b/docs/savegame_format.md
new file mode 100644
index 0000000000..fafbc64471
--- /dev/null
+++ b/docs/savegame_format.md
@@ -0,0 +1,214 @@
+# OpenTTD's Savegame Format
+
+Last updated: 2021-06-15
+
+## Outer container
+
+Savegames for OpenTTD start with an outer container, to contain the compressed data for the rest of the savegame.
+
+`[0..3]` - The first four bytes indicate what compression is used.
+In ASCII, these values are possible:
+
+- `OTTD` - Compressed with LZO (deprecated, only really old savegames would use this).
+- `OTTN` - No compression.
+- `OTTZ` - Compressed with zlib.
+- `OTTX` - Compressed with LZMA.
+
+`[4..5]` - The next two bytes indicate which savegame version used.
+
+`[6..7]` - The next two bytes can be ignored, and were only used in really old savegames.
+
+`[8..N]` - Next follows a binary blob which is compressed with the indicated compression algorithm.
+
+The rest of this document talks about this decompressed blob of data.
+
+## Data types
+
+The savegame is written in Big Endian, so when we talk about a 16-bit unsigned integer (`uint16`), we mean it is stored in Big Endian.
+
+The following types are valid:
+
+- `1` - `int8` / `SLE_FILE_I8` -8-bit signed integer
+- `2` - `uint8` / `SLE_FILE_U8` - 8-bit unsigned integer
+- `3` - `int16` / `SLE_FILE_I16` - 16-bit signed integer
+- `4` - `uint16` / `SLE_FILE_U16` - 16-bit unsigned integer
+- `5` - `int32` / `SLE_FILE_I32` - 32-bit signed integer
+- `6` - `uint32` / `SLE_FILE_U32` - 32-bit unsigned integer
+- `7` - `int64` / `SLE_FILE_I64` - 64-bit signed integer
+- `8` - `uint64` / `SLE_FILE_U64` - 64-bit unsigned integer
+- `9` - `StringID` / `SLE_FILE_STRINGID` - a StringID inside the OpenTTD's string table
+- `10` - `str` / `SLE_FILE_STRING` - a string (prefixed with a length-field)
+- `11` - `struct` / `SLE_FILE_STRUCT` - a struct
+
+### Gamma value
+
+There is also a field-type called `gamma`.
+This is most often used for length-fields, and uses as few bytes as possible to store an integer.
+For values <= 127, it uses a single byte.
+For values > 127, it uses two bytes and sets the highest bit to high.
+For values > 32767, it uses three bytes and sets the two highest bits to high.
+And this continues till the value fits.
+In a more visual approach:
+```
+ 0xxxxxxx
+ 10xxxxxx xxxxxxxx
+ 110xxxxx xxxxxxxx xxxxxxxx
+ 1110xxxx xxxxxxxx xxxxxxxx xxxxxxxx
+ 11110--- xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
+```
+
+## Chunks
+
+Savegames for OpenTTD store their data in chunks.
+Each chunk contains data for a certain part of the game, for example "Companies", "Vehicles", etc.
+
+`[0..3]` - Each chunk starts with four bytes to indicate the tag.
+If the tag is `\x00\x00\x00\x00` it means the end of the savegame is reached.
+An example of a valid tag is `PLYR` when looking at it via ASCII, which contains the information of all the companies.
+
+`[4..4]` - Next follows a byte where the lower 4 bits contain the type.
+The possible valid types are:
+
+- `0` - `CH_RIFF` - This chunk is a binary blob.
+- `1` - `CH_ARRAY` - This chunk is a list of items.
+- `2` - `CH_SPARSE_ARRAY` - This chunk is a list of items.
+- `3` - `CH_TABLE` - This chunk is self-describing list of items.
+- `4` - `CH_SPARSE_TABLE` - This chunk is self-describing list of items.
+
+Now per type the format is (slightly) different.
+
+### CH_RIFF
+
+(since savegame version 295, this chunk type is only used for MAP-chunks, containing bit-information about each tile on the map)
+
+A `CH_RIFF` starts with an `uint24` which together with the upper-bits of the type defines the length of the chunk.
+In pseudo-code:
+
+```
+type = read uint8
+if type == 0
+ length = read uint24
+ length |= ((type >> 4) << 24)
+```
+
+The next `length` bytes are part of the chunk.
+What those bytes mean depends on the tag of the chunk; further details per chunk can be found in the source-code.
+
+### CH_ARRAY / CH_SPARSE_ARRAY
+
+(this chunk type is deprecated since savegame version 295 and is no longer in use)
+
+`[0..G1]` - A `CH_ARRAY` / `CH_SPARSE_ARRAY` starts with a `gamma`, indicating the size of the next item plus one.
+If this size value is zero, it indicates the end of the list.
+This indicates the full length of the next item minus one.
+In psuedo-code:
+
+```
+loop
+ size = read gamma - 1
+ if size == -1
+ break loop
+ read bytes
+```
+
+`[]` - For `CH_ARRAY` there is an implicit index.
+The loop starts at zero, and every iteration adds one to the index.
+For entries in the game that were not allocated, the `size` will be zero.
+
+`[G1+1..G2]` - For `CH_SPARSE_ARRAY` there is an explicit index.
+The `gamma` following the size indicates the index.
+
+The content of the item is a binary blob, and similar to `CH_RIFF`, it depends on the tag of the chunk what it means.
+Please check the source-code for further details.
+
+### CH_TABLE / CH_SPARSE_TABLE
+
+(this chunk type only exists since savegame version 295)
+
+Both `CH_TABLE` and `CH_SPARSE_TABLE` are very similar to `CH_ARRAY` / `CH_SPARSE_ARRAY` respectively.
+The only change is that the chunk starts with a header.
+This header describes the chunk in details; with the header you know the meaning of each byte in the binary blob that follows.
+
+`[0..G]` - The header starts with a `gamma` to indicate the size of all the headers in this chunk plus one.
+If this size value is zero, it means there is no header, which should never be the case.
+
+Next follows a list of `(type, key)` pairs:
+
+- `[0..0]` - Type of the field.
+- `[1..G]` - `gamma` to indicate length of key.
+- `[G+1..N]` - Key (in UTF-8) of the field.
+
+If at any point `type` is zero, the list stops (and no `key` follows).
+
+The `type`'s lower 4 bits indicate the data-type (see chapter above).
+The `type`'s 5th bit (so `0x10`) indicates if the field is a list, and if this field in every record starts with a `gamma` to indicate how many times the `type` is repeated.
+
+If the `type` indicates either a `struct` or `str`, the `0x10` flag is also always set.
+
+As the savegame format allows (list of) structs in structs, if any `struct` type is found, this header will be followed by a header of that struct.
+This nesting of structs is stored depth-first, so given this table:
+
+```
+type | key
+-----------------
+uint8 | counter
+struct | substruct1
+struct | substruct2
+```
+
+With `substruct1` being like:
+
+```
+type | key
+-----------------
+uint8 | counter
+struct | substruct3
+```
+
+The headers will be, in order: `table`, `substruct1`, `substruct3`, `substruct2`, each ending with a `type` is zero field.
+
+After reading all the fields of all the headers, there is a list of records.
+To read this, see `CH_ARRAY` / `CH_SPARSE_ARRAY` for details.
+
+As each `type` has a well defined length, you can read the records even without knowing anything about the chunk-tag yourself.
+
+Do remember, that if the `type` had the `0x10` flag active, the field in the record first has a `gamma` to indicate how many times that `type` is repeated.
+
+#### Guidelines for network-compatible patch-packs
+
+For network-compatible patch-packs (client-side patches that can play together with unpatched clients) we advise to prefix the field-name with `__` when introducing new fields to an existing chunk.
+
+Example: you have an extra setting called `auto_destroy_rivers` you want to store in the savegame for your patched client called `mypp`.
+We advise you to call this setting `__mypp_auto_destroy_rivers` in the settings chunk.
+
+Doing it this way ensures that a savegame created by these patch-packs can still safely be loaded by unpatched clients.
+They will simply ignore the field and continue loading the savegame as usual.
+The prefix is strongly advised to avoid conflicts with future-settings in an unpatched client or conflicts with other patch-packs.
+
+## Scripts custom data format
+
+Script chunks (`AIPL` and `GSDT`) use `CH_TABLE` chunk type.
+
+At the end of each record there's an `uint8` to indicate if there's custom data (1) or not (0).
+
+There are 6 data types for scripts, called `script-data-type`.
+When saving, each `script-data-type` starts with the type marker saved as `uint8` followed by the actual data.
+- `0` - `SQSL_INT`:
+ - an `int64` with the actual value (`int32` before savegame version 296).
+- `1` - `SQSL_STRING`:
+ - an `uint8` with the string length.
+ - a list of `int8` for the string itself.
+- `2` - `SQSL_ARRAY`:
+ - each element saved as `script-data-type`.
+ - an `SQSL_ARRAY_TABLE_END` (0xFF) marker (`uint8`).
+- `3` - `SQSL_TABLE`:
+ - for each element:
+ - key saved as `script-data-type`.
+ - value saved as `script-data-type`.
+ - an `SQSL_ARRAY_TABLE_END` (0xFF) marker (`uint8`).
+- `4` - `SQSL_BOOL`:
+ - an `uint8` with 0 (false) or 1 (true).
+- `5` - `SQSL_NULL`:
+ - (no data follows)
+
+The first data type is always a `SQSL_TABLE`.
diff --git a/known-bugs.txt b/known-bugs.txt
index 4e9e3e9b5e..1b9a465af7 100644
--- a/known-bugs.txt
+++ b/known-bugs.txt
@@ -1,6 +1,4 @@
OpenTTD's known bugs
-Last updated: 2021-04-01
-Release version: 1.11.0
------------------------------------------------------------------------
diff --git a/media/baseset/openttd.grf b/media/baseset/openttd.grf
index a63bfc4e29..837e4b12d2 100644
Binary files a/media/baseset/openttd.grf and b/media/baseset/openttd.grf differ
diff --git a/media/baseset/openttd/openttdgui.nfo b/media/baseset/openttd/openttdgui.nfo
index eb1313365e..2fd5a5bb4c 100644
--- a/media/baseset/openttd/openttdgui.nfo
+++ b/media/baseset/openttd/openttdgui.nfo
@@ -4,7 +4,7 @@
// See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
//
-1 * 0 0C "OpenTTD GUI graphics"
- -1 * 3 05 15 \b 186 // OPENTTD_SPRITE_COUNT
+ -1 * 3 05 15 \b 191 // OPENTTD_SPRITE_COUNT
-1 sprites/openttdgui.png 8bpp 66 8 64 31 -31 7 normal
-1 sprites/openttdgui.png 8bpp 146 8 64 31 -31 7 normal
-1 sprites/openttdgui.png 8bpp 226 8 64 31 -31 7 normal
@@ -191,3 +191,8 @@
-1 sprites/openttdgui_convert_tram.png 8bpp 24 0 32 32 0 0 normal
-1 sprites/openttdgui.png 8bpp 513 440 10 10 0 0 normal
-1 sprites/openttdgui.png 8bpp 526 440 10 10 0 0 normal
+ -1 sprites/openttdgui.png 8bpp 539 440 12 10 0 0 normal
+ -1 sprites/openttdgui.png 8bpp 553 440 12 10 0 0 normal
+ -1 sprites/openttdgui.png 8bpp 567 440 12 10 0 0 normal
+ -1 sprites/openttdgui.png 8bpp 581 440 10 10 0 0 normal
+ -1 sprites/openttdgui.png 8bpp 593 440 10 10 0 0 normal
diff --git a/media/baseset/openttd/openttdgui.png b/media/baseset/openttd/openttdgui.png
index 1fc02aa61e..5b80c33260 100644
Binary files a/media/baseset/openttd/openttdgui.png and b/media/baseset/openttd/openttdgui.png differ
diff --git a/media/baseset/opntitle.dat b/media/baseset/opntitle.dat
index 9bfac1dec9..264aaff60b 100644
Binary files a/media/baseset/opntitle.dat and b/media/baseset/opntitle.dat differ
diff --git a/os/emscripten/cmake/FindLibLZMA.cmake b/os/emscripten/cmake/FindLibLZMA.cmake
index 99d1ca640a..e8a024c4ee 100644
--- a/os/emscripten/cmake/FindLibLZMA.cmake
+++ b/os/emscripten/cmake/FindLibLZMA.cmake
@@ -1,5 +1,5 @@
# LibLZMA is a recent addition to the emscripten SDK, so it is possible
-# someone hasn't updated his SDK yet. Test out if the SDK supports LibLZMA.
+# someone hasn't updated their SDK yet. Test out if the SDK supports LibLZMA.
include(CheckCXXSourceCompiles)
set(CMAKE_REQUIRED_FLAGS "-sUSE_LIBLZMA=1")
diff --git a/os/emscripten/pre.js b/os/emscripten/pre.js
index 1563e4f95b..2fb641017c 100644
--- a/os/emscripten/pre.js
+++ b/os/emscripten/pre.js
@@ -9,7 +9,15 @@ Module['websocket'] = { url: function(host, port, proto) {
* If you run your own server you can setup your own WebSocket proxy in
* front of it and let people connect to your server via the proxy. You
* are best to add another "if" statement as above for this. */
- return null;
+
+ if (location.protocol === 'https:') {
+ /* Insecure WebSockets do not work over HTTPS, so we force
+ * secure ones. */
+ return 'wss://';
+ } else {
+ /* Use the default provided by Emscripten. */
+ return null;
+ }
} };
Module.preRun.push(function() {
@@ -65,10 +73,14 @@ Module.preRun.push(function() {
}
window.openttd_server_list = function() {
- add_server = Module.cwrap("em_openttd_add_server", null, ["string", "number"]);
+ add_server = Module.cwrap("em_openttd_add_server", null, ["string"]);
- /* Add servers that support WebSocket here. Example:
- * add_server("localhost", 3979); */
+ /* Add servers that support WebSocket here. Examples:
+ * add_server("localhost");
+ * add_server("localhost:3979");
+ * add_server("127.0.0.1:3979");
+ * add_server("[::1]:3979");
+ */
}
var leftButtonDown = false;
diff --git a/os/emscripten/shell.html b/os/emscripten/shell.html
index 17ea5b414f..af031c6df8 100644
--- a/os/emscripten/shell.html
+++ b/os/emscripten/shell.html
@@ -85,6 +85,8 @@
position: absolute;
width: 100%;
z-index: 2;
+ /* OpenTTD draws the cursor itself */
+ cursor: none !important;
}
diff --git a/os/windows/sign.bat b/os/windows/sign.bat
new file mode 100644
index 0000000000..0e4291f9b8
--- /dev/null
+++ b/os/windows/sign.bat
@@ -0,0 +1,18 @@
+@echo off
+REM Signing script
+REM Arguments: sign.bat exe_to_sign certificate_subject_name
+
+REM This is a loose wrapper around the Microsoft signtool application (included in the Windows SDK).
+REM See https://docs.microsoft.com/en-us/dotnet/framework/tools/signtool-exe for more details.
+
+REM Path to signtool.exe
+IF NOT DEFINED SIGNTOOL_PATH (SET SIGNTOOL_PATH=signtool)
+
+REM URL of the timestamp server
+IF NOT DEFINED SIGNTOOL_TIMESTAMP_URL (SET SIGNTOOL_TIMESTAMP_URL=http://timestamp.digicert.com)
+
+REM Sign with SHA-1 for Windows 7 and below
+"%SIGNTOOL_PATH%" sign -v -n %2 -t %SIGNTOOL_TIMESTAMP_URL% %1
+
+REM Sign with SHA-256 for Windows 8 and above
+"%SIGNTOOL_PATH%" sign -v -n %2 -tr %SIGNTOOL_TIMESTAMP_URL% -fd sha256 -td sha256 -as %1
diff --git a/regression/regression/info.nut b/regression/regression/info.nut
index a3126121ee..1a52cfebbb 100644
--- a/regression/regression/info.nut
+++ b/regression/regression/info.nut
@@ -4,7 +4,7 @@ class Regression extends AIInfo {
function GetShortName() { return "REGR"; }
function GetDescription() { return "This runs regression-tests on some commands. On the same map the result should always be the same."; }
function GetVersion() { return 1; }
- function GetAPIVersion() { return "1.11"; }
+ function GetAPIVersion() { return "12"; }
function GetDate() { return "2007-03-18"; }
function CreateInstance() { return "Regression"; }
function UseAsRandomAI() { return false; }
diff --git a/regression/stationlist/info.nut b/regression/stationlist/info.nut
index 9b7c8febc7..ad91c7645c 100644
--- a/regression/stationlist/info.nut
+++ b/regression/stationlist/info.nut
@@ -4,7 +4,7 @@ class StationList extends AIInfo {
function GetShortName() { return "REGS"; }
function GetDescription() { return "This runs stationlist-tests on some commands. On the same map the result should always be the same."; }
function GetVersion() { return 1; }
- function GetAPIVersion() { return "1.11"; }
+ function GetAPIVersion() { return "12"; }
function GetDate() { return "2007-03-18"; }
function CreateInstance() { return "StationList"; }
function UseAsRandomAI() { return false; }
diff --git a/src/3rdparty/CMakeLists.txt b/src/3rdparty/CMakeLists.txt
index ca082cf785..50fa6922f4 100644
--- a/src/3rdparty/CMakeLists.txt
+++ b/src/3rdparty/CMakeLists.txt
@@ -1,3 +1,4 @@
+add_subdirectory(fmt)
add_subdirectory(md5)
add_subdirectory(squirrel)
add_subdirectory(opengl)
diff --git a/src/3rdparty/fmt/CMakeLists.txt b/src/3rdparty/fmt/CMakeLists.txt
new file mode 100644
index 0000000000..22a02416c3
--- /dev/null
+++ b/src/3rdparty/fmt/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_files(
+ core.h
+ format.h
+ format-inl.h
+)
diff --git a/src/3rdparty/fmt/LICENSE.rst b/src/3rdparty/fmt/LICENSE.rst
new file mode 100644
index 0000000000..f0ec3db4d2
--- /dev/null
+++ b/src/3rdparty/fmt/LICENSE.rst
@@ -0,0 +1,27 @@
+Copyright (c) 2012 - present, Victor Zverovich
+
+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.
diff --git a/src/3rdparty/fmt/core.h b/src/3rdparty/fmt/core.h
new file mode 100644
index 0000000000..0a81e0ccd9
--- /dev/null
+++ b/src/3rdparty/fmt/core.h
@@ -0,0 +1,2122 @@
+// Formatting library for C++ - the core API
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#ifndef FMT_CORE_H_
+#define FMT_CORE_H_
+
+#include // std::FILE
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// The fmt library version in the form major * 10000 + minor * 100 + patch.
+#define FMT_VERSION 70103
+
+#ifdef __clang__
+# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
+#else
+# define FMT_CLANG_VERSION 0
+#endif
+
+#if defined(__GNUC__) && !defined(__clang__)
+# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+#else
+# define FMT_GCC_VERSION 0
+#endif
+
+#if defined(__INTEL_COMPILER)
+# define FMT_ICC_VERSION __INTEL_COMPILER
+#else
+# define FMT_ICC_VERSION 0
+#endif
+
+#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION
+#else
+# define FMT_HAS_GXX_CXX11 0
+#endif
+
+#ifdef __NVCC__
+# define FMT_NVCC __NVCC__
+#else
+# define FMT_NVCC 0
+#endif
+
+#ifdef _MSC_VER
+# define FMT_MSC_VER _MSC_VER
+# define FMT_SUPPRESS_MSC_WARNING(n) __pragma(warning(suppress : n))
+#else
+# define FMT_MSC_VER 0
+# define FMT_SUPPRESS_MSC_WARNING(n)
+#endif
+
+#ifdef __has_feature
+# define FMT_HAS_FEATURE(x) __has_feature(x)
+#else
+# define FMT_HAS_FEATURE(x) 0
+#endif
+
+#if defined(__has_include) && !defined(__INTELLISENSE__) && \
+ (!FMT_ICC_VERSION || FMT_ICC_VERSION >= 1600)
+# define FMT_HAS_INCLUDE(x) __has_include(x)
+#else
+# define FMT_HAS_INCLUDE(x) 0
+#endif
+
+#ifdef __has_cpp_attribute
+# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
+#else
+# define FMT_HAS_CPP_ATTRIBUTE(x) 0
+#endif
+
+#define FMT_HAS_CPP14_ATTRIBUTE(attribute) \
+ (__cplusplus >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute))
+
+#define FMT_HAS_CPP17_ATTRIBUTE(attribute) \
+ (__cplusplus >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute))
+
+// Check if relaxed C++14 constexpr is supported.
+// GCC doesn't allow throw in constexpr until version 6 (bug 67371).
+#ifndef FMT_USE_CONSTEXPR
+# define FMT_USE_CONSTEXPR \
+ (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \
+ (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) && \
+ !FMT_NVCC && !FMT_ICC_VERSION
+#endif
+#if FMT_USE_CONSTEXPR
+# define FMT_CONSTEXPR constexpr
+# define FMT_CONSTEXPR_DECL constexpr
+#else
+# define FMT_CONSTEXPR inline
+# define FMT_CONSTEXPR_DECL
+#endif
+
+#ifndef FMT_OVERRIDE
+# if FMT_HAS_FEATURE(cxx_override_control) || \
+ (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900
+# define FMT_OVERRIDE override
+# else
+# define FMT_OVERRIDE
+# endif
+#endif
+
+// Check if exceptions are disabled.
+#ifndef FMT_EXCEPTIONS
+# if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \
+ FMT_MSC_VER && !_HAS_EXCEPTIONS
+# define FMT_EXCEPTIONS 0
+# else
+# define FMT_EXCEPTIONS 1
+# endif
+#endif
+
+// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature).
+#ifndef FMT_USE_NOEXCEPT
+# define FMT_USE_NOEXCEPT 0
+#endif
+
+#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
+ (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900
+# define FMT_DETECTED_NOEXCEPT noexcept
+# define FMT_HAS_CXX11_NOEXCEPT 1
+#else
+# define FMT_DETECTED_NOEXCEPT throw()
+# define FMT_HAS_CXX11_NOEXCEPT 0
+#endif
+
+#ifndef FMT_NOEXCEPT
+# if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT
+# define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT
+# else
+# define FMT_NOEXCEPT
+# endif
+#endif
+
+// [[noreturn]] is disabled on MSVC and NVCC because of bogus unreachable code
+// warnings.
+#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER && \
+ !FMT_NVCC
+# define FMT_NORETURN [[noreturn]]
+#else
+# define FMT_NORETURN
+#endif
+
+#ifndef FMT_DEPRECATED
+# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900
+# define FMT_DEPRECATED [[deprecated]]
+# else
+# if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__)
+# define FMT_DEPRECATED __attribute__((deprecated))
+# elif FMT_MSC_VER
+# define FMT_DEPRECATED __declspec(deprecated)
+# else
+# define FMT_DEPRECATED /* deprecated */
+# endif
+# endif
+#endif
+
+// Workaround broken [[deprecated]] in the Intel, PGI and NVCC compilers.
+#if FMT_ICC_VERSION || defined(__PGI) || FMT_NVCC
+# define FMT_DEPRECATED_ALIAS
+#else
+# define FMT_DEPRECATED_ALIAS FMT_DEPRECATED
+#endif
+
+#ifndef FMT_INLINE
+# if FMT_GCC_VERSION || FMT_CLANG_VERSION
+# define FMT_INLINE inline __attribute__((always_inline))
+# else
+# define FMT_INLINE inline
+# endif
+#endif
+
+#ifndef FMT_USE_INLINE_NAMESPACES
+# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \
+ (FMT_MSC_VER >= 1900 && !_MANAGED)
+# define FMT_USE_INLINE_NAMESPACES 1
+# else
+# define FMT_USE_INLINE_NAMESPACES 0
+# endif
+#endif
+
+#ifndef FMT_BEGIN_NAMESPACE
+# if FMT_USE_INLINE_NAMESPACES
+# define FMT_INLINE_NAMESPACE inline namespace
+# define FMT_END_NAMESPACE \
+ } \
+ }
+# else
+# define FMT_INLINE_NAMESPACE namespace
+# define FMT_END_NAMESPACE \
+ } \
+ using namespace v7; \
+ }
+# endif
+# define FMT_BEGIN_NAMESPACE \
+ namespace fmt { \
+ FMT_INLINE_NAMESPACE v7 {
+#endif
+
+#if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
+# define FMT_CLASS_API FMT_SUPPRESS_MSC_WARNING(4275)
+# ifdef FMT_EXPORT
+# define FMT_API __declspec(dllexport)
+# define FMT_EXTERN_TEMPLATE_API FMT_API
+# define FMT_EXPORTED
+# elif defined(FMT_SHARED)
+# define FMT_API __declspec(dllimport)
+# define FMT_EXTERN_TEMPLATE_API FMT_API
+# endif
+#else
+# define FMT_CLASS_API
+#endif
+#ifndef FMT_API
+# define FMT_API
+#endif
+#ifndef FMT_EXTERN_TEMPLATE_API
+# define FMT_EXTERN_TEMPLATE_API
+#endif
+#ifndef FMT_INSTANTIATION_DEF_API
+# define FMT_INSTANTIATION_DEF_API FMT_API
+#endif
+
+#ifndef FMT_HEADER_ONLY
+# define FMT_EXTERN extern
+#else
+# define FMT_EXTERN
+#endif
+
+// libc++ supports string_view in pre-c++17.
+#if (FMT_HAS_INCLUDE() && \
+ (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \
+ (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
+# include
+# define FMT_USE_STRING_VIEW
+#elif FMT_HAS_INCLUDE("experimental/string_view") && __cplusplus >= 201402L
+# include
+# define FMT_USE_EXPERIMENTAL_STRING_VIEW
+#endif
+
+#ifndef FMT_UNICODE
+# define FMT_UNICODE !FMT_MSC_VER
+#endif
+#if FMT_UNICODE && FMT_MSC_VER
+# pragma execution_character_set("utf-8")
+#endif
+
+FMT_BEGIN_NAMESPACE
+
+// Implementations of enable_if_t and other metafunctions for older systems.
+template
+using enable_if_t = typename std::enable_if::type;
+template
+using conditional_t = typename std::conditional::type;
+template using bool_constant = std::integral_constant;
+template
+using remove_reference_t = typename std::remove_reference::type;
+template
+using remove_const_t = typename std::remove_const::type;
+template
+using remove_cvref_t = typename std::remove_cv>::type;
+template struct type_identity { using type = T; };
+template using type_identity_t = typename type_identity::type;
+
+struct monostate {};
+
+// An enable_if helper to be used in template parameters which results in much
+// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed
+// to workaround a bug in MSVC 2019 (see #1140 and #1186).
+#define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0
+
+namespace detail {
+
+// A helper function to suppress "conditional expression is constant" warnings.
+template constexpr T const_check(T value) { return value; }
+
+FMT_NORETURN FMT_API void assert_fail(const char* file, int line,
+ const char* message);
+
+#ifndef FMT_ASSERT
+# ifdef NDEBUG
+// FMT_ASSERT is not empty to avoid -Werror=empty-body.
+# define FMT_ASSERT(condition, message) ((void)0)
+# else
+# define FMT_ASSERT(condition, message) \
+ ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \
+ ? (void)0 \
+ : ::fmt::detail::assert_fail(__FILE__, __LINE__, (message)))
+# endif
+#endif
+
+#if defined(FMT_USE_STRING_VIEW)
+template using std_string_view = std::basic_string_view;
+#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW)
+template
+using std_string_view = std::experimental::basic_string_view;
+#else
+template struct std_string_view {};
+#endif
+
+#ifdef FMT_USE_INT128
+// Do nothing.
+#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && \
+ !(FMT_CLANG_VERSION && FMT_MSC_VER)
+# define FMT_USE_INT128 1
+using int128_t = __int128_t;
+using uint128_t = __uint128_t;
+#else
+# define FMT_USE_INT128 0
+#endif
+#if !FMT_USE_INT128
+struct int128_t {};
+struct uint128_t {};
+#endif
+
+// Casts a nonnegative integer to unsigned.
+template
+FMT_CONSTEXPR typename std::make_unsigned::type to_unsigned(Int value) {
+ FMT_ASSERT(value >= 0, "negative value");
+ return static_cast::type>(value);
+}
+
+FMT_SUPPRESS_MSC_WARNING(4566) constexpr unsigned char micro[] = "\u00B5";
+
+template constexpr bool is_unicode() {
+ return FMT_UNICODE || sizeof(Char) != 1 ||
+ (sizeof(micro) == 3 && micro[0] == 0xC2 && micro[1] == 0xB5);
+}
+
+#ifdef __cpp_char8_t
+using char8_type = char8_t;
+#else
+enum char8_type : unsigned char {};
+#endif
+} // namespace detail
+
+#ifdef FMT_USE_INTERNAL
+namespace internal = detail; // DEPRECATED
+#endif
+
+/**
+ An implementation of ``std::basic_string_view`` for pre-C++17. It provides a
+ subset of the API. ``fmt::basic_string_view`` is used for format strings even
+ if ``std::string_view`` is available to prevent issues when a library is
+ compiled with a different ``-std`` option than the client code (which is not
+ recommended).
+ */
+template class basic_string_view {
+ private:
+ const Char* data_;
+ size_t size_;
+
+ public:
+ using value_type = Char;
+ using iterator = const Char*;
+
+ constexpr basic_string_view() FMT_NOEXCEPT : data_(nullptr), size_(0) {}
+
+ /** Constructs a string reference object from a C string and a size. */
+ constexpr basic_string_view(const Char* s, size_t count) FMT_NOEXCEPT
+ : data_(s),
+ size_(count) {}
+
+ /**
+ \rst
+ Constructs a string reference object from a C string computing
+ the size with ``std::char_traits::length``.
+ \endrst
+ */
+#if __cplusplus >= 201703L // C++17's char_traits::length() is constexpr.
+ FMT_CONSTEXPR
+#endif
+ basic_string_view(const Char* s)
+ : data_(s), size_(std::char_traits::length(s)) {}
+
+ /** Constructs a string reference from a ``std::basic_string`` object. */
+ template
+ FMT_CONSTEXPR basic_string_view(
+ const std::basic_string& s) FMT_NOEXCEPT
+ : data_(s.data()),
+ size_(s.size()) {}
+
+ template >::value)>
+ FMT_CONSTEXPR basic_string_view(S s) FMT_NOEXCEPT : data_(s.data()),
+ size_(s.size()) {}
+
+ /** Returns a pointer to the string data. */
+ constexpr const Char* data() const { return data_; }
+
+ /** Returns the string size. */
+ constexpr size_t size() const { return size_; }
+
+ constexpr iterator begin() const { return data_; }
+ constexpr iterator end() const { return data_ + size_; }
+
+ constexpr const Char& operator[](size_t pos) const { return data_[pos]; }
+
+ FMT_CONSTEXPR void remove_prefix(size_t n) {
+ data_ += n;
+ size_ -= n;
+ }
+
+ // Lexicographically compare this string reference to other.
+ int compare(basic_string_view other) const {
+ size_t str_size = size_ < other.size_ ? size_ : other.size_;
+ int result = std::char_traits::compare(data_, other.data_, str_size);
+ if (result == 0)
+ result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1);
+ return result;
+ }
+
+ friend bool operator==(basic_string_view lhs, basic_string_view rhs) {
+ return lhs.compare(rhs) == 0;
+ }
+ friend bool operator!=(basic_string_view lhs, basic_string_view rhs) {
+ return lhs.compare(rhs) != 0;
+ }
+ friend bool operator<(basic_string_view lhs, basic_string_view rhs) {
+ return lhs.compare(rhs) < 0;
+ }
+ friend bool operator<=(basic_string_view lhs, basic_string_view rhs) {
+ return lhs.compare(rhs) <= 0;
+ }
+ friend bool operator>(basic_string_view lhs, basic_string_view rhs) {
+ return lhs.compare(rhs) > 0;
+ }
+ friend bool operator>=(basic_string_view lhs, basic_string_view rhs) {
+ return lhs.compare(rhs) >= 0;
+ }
+};
+
+using string_view = basic_string_view;
+using wstring_view = basic_string_view;
+
+/** Specifies if ``T`` is a character type. Can be specialized by users. */
+template struct is_char : std::false_type {};
+template <> struct is_char : std::true_type {};
+template <> struct is_char : std::true_type {};
+template <> struct is_char : std::true_type {};
+template <> struct is_char : std::true_type {};
+template <> struct is_char : std::true_type {};
+
+/**
+ \rst
+ Returns a string view of `s`. In order to add custom string type support to
+ {fmt} provide an overload of `to_string_view` for it in the same namespace as
+ the type for the argument-dependent lookup to work.
+
+ **Example**::
+
+ namespace my_ns {
+ inline string_view to_string_view(const my_string& s) {
+ return {s.data(), s.length()};
+ }
+ }
+ std::string message = fmt::format(my_string("The answer is {}"), 42);
+ \endrst
+ */
+template ::value)>
+inline basic_string_view to_string_view(const Char* s) {
+ return s;
+}
+
+template
+inline basic_string_view to_string_view(
+ const std::basic_string& s) {
+ return s;
+}
+
+template
+inline basic_string_view to_string_view(basic_string_view s) {
+ return s;
+}
+
+template >::value)>
+inline basic_string_view to_string_view(detail::std_string_view s) {
+ return s;
+}
+
+// A base class for compile-time strings. It is defined in the fmt namespace to
+// make formatting functions visible via ADL, e.g. format(FMT_STRING("{}"), 42).
+struct compile_string {};
+
+template
+struct is_compile_string : std::is_base_of {};
+
+template ::value)>
+constexpr basic_string_view to_string_view(const S& s) {
+ return s;
+}
+
+namespace detail {
+void to_string_view(...);
+using fmt::v7::to_string_view;
+
+// Specifies whether S is a string type convertible to fmt::basic_string_view.
+// It should be a constexpr function but MSVC 2017 fails to compile it in
+// enable_if and MSVC 2015 fails to compile it as an alias template.
+template
+struct is_string : std::is_class()))> {
+};
+
+template struct char_t_impl {};
+template struct char_t_impl::value>> {
+ using result = decltype(to_string_view(std::declval()));
+ using type = typename result::value_type;
+};
+
+// Reports a compile-time error if S is not a valid format string.
+template ::value)>
+FMT_INLINE void check_format_string(const S&) {
+#ifdef FMT_ENFORCE_COMPILE_STRING
+ static_assert(is_compile_string::value,
+ "FMT_ENFORCE_COMPILE_STRING requires all format strings to use "
+ "FMT_STRING.");
+#endif
+}
+template ::value)>
+void check_format_string(S);
+
+struct error_handler {
+ constexpr error_handler() = default;
+ constexpr error_handler(const error_handler&) = default;
+
+ // This function is intentionally not constexpr to give a compile-time error.
+ FMT_NORETURN FMT_API void on_error(const char* message);
+};
+} // namespace detail
+
+/** String's character type. */
+template using char_t = typename detail::char_t_impl::type;
+
+/**
+ \rst
+ Parsing context consisting of a format string range being parsed and an
+ argument counter for automatic indexing.
+
+ You can use one of the following type aliases for common character types:
+
+ +-----------------------+-------------------------------------+
+ | Type | Definition |
+ +=======================+=====================================+
+ | format_parse_context | basic_format_parse_context |
+ +-----------------------+-------------------------------------+
+ | wformat_parse_context | basic_format_parse_context |
+ +-----------------------+-------------------------------------+
+ \endrst
+ */
+template
+class basic_format_parse_context : private ErrorHandler {
+ private:
+ basic_string_view format_str_;
+ int next_arg_id_;
+
+ public:
+ using char_type = Char;
+ using iterator = typename basic_string_view::iterator;
+
+ explicit constexpr basic_format_parse_context(
+ basic_string_view format_str, ErrorHandler eh = {},
+ int next_arg_id = 0)
+ : ErrorHandler(eh), format_str_(format_str), next_arg_id_(next_arg_id) {}
+
+ /**
+ Returns an iterator to the beginning of the format string range being
+ parsed.
+ */
+ constexpr iterator begin() const FMT_NOEXCEPT { return format_str_.begin(); }
+
+ /**
+ Returns an iterator past the end of the format string range being parsed.
+ */
+ constexpr iterator end() const FMT_NOEXCEPT { return format_str_.end(); }
+
+ /** Advances the begin iterator to ``it``. */
+ FMT_CONSTEXPR void advance_to(iterator it) {
+ format_str_.remove_prefix(detail::to_unsigned(it - begin()));
+ }
+
+ /**
+ Reports an error if using the manual argument indexing; otherwise returns
+ the next argument index and switches to the automatic indexing.
+ */
+ FMT_CONSTEXPR int next_arg_id() {
+ // Don't check if the argument id is valid to avoid overhead and because it
+ // will be checked during formatting anyway.
+ if (next_arg_id_ >= 0) return next_arg_id_++;
+ on_error("cannot switch from manual to automatic argument indexing");
+ return 0;
+ }
+
+ /**
+ Reports an error if using the automatic argument indexing; otherwise
+ switches to the manual indexing.
+ */
+ FMT_CONSTEXPR void check_arg_id(int) {
+ if (next_arg_id_ > 0)
+ on_error("cannot switch from automatic to manual argument indexing");
+ else
+ next_arg_id_ = -1;
+ }
+
+ FMT_CONSTEXPR void check_arg_id(basic_string_view) {}
+
+ FMT_CONSTEXPR void on_error(const char* message) {
+ ErrorHandler::on_error(message);
+ }
+
+ constexpr ErrorHandler error_handler() const { return *this; }
+};
+
+using format_parse_context = basic_format_parse_context;
+using wformat_parse_context = basic_format_parse_context;
+
+template class basic_format_arg;
+template class basic_format_args;
+template class dynamic_format_arg_store;
+
+// A formatter for objects of type T.
+template
+struct formatter {
+ // A deleted default constructor indicates a disabled formatter.
+ formatter() = delete;
+};
+
+// Specifies if T has an enabled formatter specialization. A type can be
+// formattable even if it doesn't have a formatter e.g. via a conversion.
+template
+using has_formatter =
+ std::is_constructible>;
+
+// Checks whether T is a container with contiguous storage.
+template struct is_contiguous : std::false_type {};
+template
+struct is_contiguous> : std::true_type {};
+
+namespace detail {
+
+// Extracts a reference to the container from back_insert_iterator.
+template
+inline Container& get_container(std::back_insert_iterator it) {
+ using bi_iterator = std::back_insert_iterator;
+ struct accessor : bi_iterator {
+ accessor(bi_iterator iter) : bi_iterator(iter) {}
+ using bi_iterator::container;
+ };
+ return *accessor(it).container;
+}
+
+/**
+ \rst
+ A contiguous memory buffer with an optional growing ability. It is an internal
+ class and shouldn't be used directly, only via `~fmt::basic_memory_buffer`.
+ \endrst
+ */
+template class buffer {
+ private:
+ T* ptr_;
+ size_t size_;
+ size_t capacity_;
+
+ protected:
+ // Don't initialize ptr_ since it is not accessed to save a few cycles.
+ FMT_SUPPRESS_MSC_WARNING(26495)
+ buffer(size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {}
+
+ buffer(T* p = nullptr, size_t sz = 0, size_t cap = 0) FMT_NOEXCEPT
+ : ptr_(p),
+ size_(sz),
+ capacity_(cap) {}
+
+ ~buffer() = default;
+
+ /** Sets the buffer data and capacity. */
+ void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT {
+ ptr_ = buf_data;
+ capacity_ = buf_capacity;
+ }
+
+ /** Increases the buffer capacity to hold at least *capacity* elements. */
+ virtual void grow(size_t capacity) = 0;
+
+ public:
+ using value_type = T;
+ using const_reference = const T&;
+
+ buffer(const buffer&) = delete;
+ void operator=(const buffer&) = delete;
+
+ T* begin() FMT_NOEXCEPT { return ptr_; }
+ T* end() FMT_NOEXCEPT { return ptr_ + size_; }
+
+ const T* begin() const FMT_NOEXCEPT { return ptr_; }
+ const T* end() const FMT_NOEXCEPT { return ptr_ + size_; }
+
+ /** Returns the size of this buffer. */
+ size_t size() const FMT_NOEXCEPT { return size_; }
+
+ /** Returns the capacity of this buffer. */
+ size_t capacity() const FMT_NOEXCEPT { return capacity_; }
+
+ /** Returns a pointer to the buffer data. */
+ T* data() FMT_NOEXCEPT { return ptr_; }
+
+ /** Returns a pointer to the buffer data. */
+ const T* data() const FMT_NOEXCEPT { return ptr_; }
+
+ /** Clears this buffer. */
+ void clear() { size_ = 0; }
+
+ // Tries resizing the buffer to contain *count* elements. If T is a POD type
+ // the new elements may not be initialized.
+ void try_resize(size_t count) {
+ try_reserve(count);
+ size_ = count <= capacity_ ? count : capacity_;
+ }
+
+ // Tries increasing the buffer capacity to *new_capacity*. It can increase the
+ // capacity by a smaller amount than requested but guarantees there is space
+ // for at least one additional element either by increasing the capacity or by
+ // flushing the buffer if it is full.
+ void try_reserve(size_t new_capacity) {
+ if (new_capacity > capacity_) grow(new_capacity);
+ }
+
+ void push_back(const T& value) {
+ try_reserve(size_ + 1);
+ ptr_[size_++] = value;
+ }
+
+ /** Appends data to the end of the buffer. */
+ template void append(const U* begin, const U* end);
+
+ template T& operator[](I index) { return ptr_[index]; }
+ template const T& operator[](I index) const {
+ return ptr_[index];
+ }
+};
+
+struct buffer_traits {
+ explicit buffer_traits(size_t) {}
+ size_t count() const { return 0; }
+ size_t limit(size_t size) { return size; }
+};
+
+class fixed_buffer_traits {
+ private:
+ size_t count_ = 0;
+ size_t limit_;
+
+ public:
+ explicit fixed_buffer_traits(size_t limit) : limit_(limit) {}
+ size_t count() const { return count_; }
+ size_t limit(size_t size) {
+ size_t n = limit_ > count_ ? limit_ - count_ : 0;
+ count_ += size;
+ return size < n ? size : n;
+ }
+};
+
+// A buffer that writes to an output iterator when flushed.
+template
+class iterator_buffer final : public Traits, public buffer {
+ private:
+ OutputIt out_;
+ enum { buffer_size = 256 };
+ T data_[buffer_size];
+
+ protected:
+ void grow(size_t) final FMT_OVERRIDE {
+ if (this->size() == buffer_size) flush();
+ }
+ void flush();
+
+ public:
+ explicit iterator_buffer(OutputIt out, size_t n = buffer_size)
+ : Traits(n),
+ buffer(data_, 0, buffer_size),
+ out_(out) {}
+ ~iterator_buffer() { flush(); }
+
+ OutputIt out() {
+ flush();
+ return out_;
+ }
+ size_t count() const { return Traits::count() + this->size(); }
+};
+
+template class iterator_buffer final : public buffer {
+ protected:
+ void grow(size_t) final FMT_OVERRIDE {}
+
+ public:
+ explicit iterator_buffer(T* out, size_t = 0) : buffer(out, 0, ~size_t()) {}
+
+ T* out() { return &*this->end(); }
+};
+
+// A buffer that writes to a container with the contiguous storage.
+template
+class iterator_buffer,
+ enable_if_t::value,
+ typename Container::value_type>>
+ final : public buffer {
+ private:
+ Container& container_;
+
+ protected:
+ void grow(size_t capacity) final FMT_OVERRIDE {
+ container_.resize(capacity);
+ this->set(&container_[0], capacity);
+ }
+
+ public:
+ explicit iterator_buffer(Container& c)
+ : buffer(c.size()), container_(c) {}
+ explicit iterator_buffer(std::back_insert_iterator out, size_t = 0)
+ : iterator_buffer(get_container(out)) {}
+ std::back_insert_iterator out() {
+ return std::back_inserter(container_);
+ }
+};
+
+// A buffer that counts the number of code units written discarding the output.
+template class counting_buffer final : public buffer {
+ private:
+ enum { buffer_size = 256 };
+ T data_[buffer_size];
+ size_t count_ = 0;
+
+ protected:
+ void grow(size_t) final FMT_OVERRIDE {
+ if (this->size() != buffer_size) return;
+ count_ += this->size();
+ this->clear();
+ }
+
+ public:
+ counting_buffer() : buffer(data_, 0, buffer_size) {}
+
+ size_t count() { return count_ + this->size(); }
+};
+
+// An output iterator that appends to the buffer.
+// It is used to reduce symbol sizes for the common case.
+template
+class buffer_appender : public std::back_insert_iterator> {
+ using base = std::back_insert_iterator>;
+
+ public:
+ explicit buffer_appender(buffer& buf) : base(buf) {}
+ buffer_appender(base it) : base(it) {}
+
+ buffer_appender& operator++() {
+ base::operator++();
+ return *this;
+ }
+
+ buffer_appender operator++(int) {
+ buffer_appender tmp = *this;
+ ++*this;
+ return tmp;
+ }
+};
+
+// Maps an output iterator into a buffer.
+template
+iterator_buffer get_buffer(OutputIt);
+template buffer& get_buffer(buffer_appender);
+
+template OutputIt get_buffer_init(OutputIt out) {
+ return out;
+}
+template buffer& get_buffer_init(buffer_appender out) {
+ return get_container(out);
+}
+
+template
+auto get_iterator(Buffer& buf) -> decltype(buf.out()) {
+ return buf.out();
+}
+template buffer_appender get_iterator(buffer& buf) {
+ return buffer_appender(buf);
+}
+
+template
+struct fallback_formatter {
+ fallback_formatter() = delete;
+};
+
+// Specifies if T has an enabled fallback_formatter specialization.
+template
+using has_fallback_formatter =
+ std::is_constructible>;
+
+struct view {};
+
+template struct named_arg : view {
+ const Char* name;
+ const T& value;
+ named_arg(const Char* n, const T& v) : name(n), value(v) {}
+};
+
+template struct named_arg_info {
+ const Char* name;
+ int id;
+};
+
+template
+struct arg_data {
+ // args_[0].named_args points to named_args_ to avoid bloating format_args.
+ // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
+ T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : +1)];
+ named_arg_info named_args_[NUM_NAMED_ARGS];
+
+ template
+ arg_data(const U&... init) : args_{T(named_args_, NUM_NAMED_ARGS), init...} {}
+ arg_data(const arg_data& other) = delete;
+ const T* args() const { return args_ + 1; }
+ named_arg_info* named_args() { return named_args_; }
+};
+
+template
+struct arg_data {
+ // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
+ T args_[NUM_ARGS != 0 ? NUM_ARGS : +1];
+
+ template
+ FMT_INLINE arg_data(const U&... init) : args_{init...} {}
+ FMT_INLINE const T* args() const { return args_; }
+ FMT_INLINE std::nullptr_t named_args() { return nullptr; }
+};
+
+template
+inline void init_named_args(named_arg_info*, int, int) {}
+
+template
+void init_named_args(named_arg_info* named_args, int arg_count,
+ int named_arg_count, const T&, const Tail&... args) {
+ init_named_args(named_args, arg_count + 1, named_arg_count, args...);
+}
+
+template
+void init_named_args(named_arg_info* named_args, int arg_count,
+ int named_arg_count, const named_arg& arg,
+ const Tail&... args) {
+ named_args[named_arg_count++] = {arg.name, arg_count};
+ init_named_args(named_args, arg_count + 1, named_arg_count, args...);
+}
+
+template
+FMT_INLINE void init_named_args(std::nullptr_t, int, int, const Args&...) {}
+
+template struct is_named_arg : std::false_type {};
+
+template
+struct is_named_arg> : std::true_type {};
+
+template constexpr size_t count() { return B ? 1 : 0; }
+template constexpr size_t count() {
+ return (B1 ? 1 : 0) + count();
+}
+
+template constexpr size_t count_named_args() {
+ return count::value...>();
+}
+
+enum class type {
+ none_type,
+ // Integer types should go first,
+ int_type,
+ uint_type,
+ long_long_type,
+ ulong_long_type,
+ int128_type,
+ uint128_type,
+ bool_type,
+ char_type,
+ last_integer_type = char_type,
+ // followed by floating-point types.
+ float_type,
+ double_type,
+ long_double_type,
+ last_numeric_type = long_double_type,
+ cstring_type,
+ string_type,
+ pointer_type,
+ custom_type
+};
+
+// Maps core type T to the corresponding type enum constant.
+template
+struct type_constant : std::integral_constant {};
+
+#define FMT_TYPE_CONSTANT(Type, constant) \
+ template \
+ struct type_constant \
+ : std::integral_constant {}
+
+FMT_TYPE_CONSTANT(int, int_type);
+FMT_TYPE_CONSTANT(unsigned, uint_type);
+FMT_TYPE_CONSTANT(long long, long_long_type);
+FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type);
+FMT_TYPE_CONSTANT(int128_t, int128_type);
+FMT_TYPE_CONSTANT(uint128_t, uint128_type);
+FMT_TYPE_CONSTANT(bool, bool_type);
+FMT_TYPE_CONSTANT(Char, char_type);
+FMT_TYPE_CONSTANT(float, float_type);
+FMT_TYPE_CONSTANT(double, double_type);
+FMT_TYPE_CONSTANT(long double, long_double_type);
+FMT_TYPE_CONSTANT(const Char*, cstring_type);
+FMT_TYPE_CONSTANT(basic_string_view, string_type);
+FMT_TYPE_CONSTANT(const void*, pointer_type);
+
+constexpr bool is_integral_type(type t) {
+ return t > type::none_type && t <= type::last_integer_type;
+}
+
+constexpr bool is_arithmetic_type(type t) {
+ return t > type::none_type && t <= type::last_numeric_type;
+}
+
+template struct string_value {
+ const Char* data;
+ size_t size;
+};
+
+template struct named_arg_value {
+ const named_arg_info* data;
+ size_t size;
+};
+
+template struct custom_value {
+ using parse_context = typename Context::parse_context_type;
+ const void* value;
+ void (*format)(const void* arg, parse_context& parse_ctx, Context& ctx);
+};
+
+// A formatting argument value.
+template class value {
+ public:
+ using char_type = typename Context::char_type;
+
+ union {
+ int int_value;
+ unsigned uint_value;
+ long long long_long_value;
+ unsigned long long ulong_long_value;
+ int128_t int128_value;
+ uint128_t uint128_value;
+ bool bool_value;
+ char_type char_value;
+ float float_value;
+ double double_value;
+ long double long_double_value;
+ const void* pointer;
+ string_value string;
+ custom_value custom;
+ named_arg_value named_args;
+ };
+
+ constexpr FMT_INLINE value(int val = 0) : int_value(val) {}
+ constexpr FMT_INLINE value(unsigned val) : uint_value(val) {}
+ FMT_INLINE value(long long val) : long_long_value(val) {}
+ FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {}
+ FMT_INLINE value(int128_t val) : int128_value(val) {}
+ FMT_INLINE value(uint128_t val) : uint128_value(val) {}
+ FMT_INLINE value(float val) : float_value(val) {}
+ FMT_INLINE value(double val) : double_value(val) {}
+ FMT_INLINE value(long double val) : long_double_value(val) {}
+ FMT_INLINE value(bool val) : bool_value(val) {}
+ FMT_INLINE value(char_type val) : char_value(val) {}
+ FMT_INLINE value(const char_type* val) { string.data = val; }
+ FMT_INLINE value(basic_string_view val) {
+ string.data = val.data();
+ string.size = val.size();
+ }
+ FMT_INLINE value(const void* val) : pointer(val) {}
+ FMT_INLINE value(const named_arg_info* args, size_t size)
+ : named_args{args, size} {}
+
+ template FMT_INLINE value(const T& val) {
+ custom.value = &val;
+ // Get the formatter type through the context to allow different contexts
+ // have different extension points, e.g. `formatter` for `format` and
+ // `printf_formatter` for `printf`.
+ custom.format = format_custom_arg<
+ T, conditional_t::value,
+ typename Context::template formatter_type,
+ fallback_formatter>>;
+ }
+
+ private:
+ // Formats an argument of a custom type, such as a user-defined class.
+ template
+ static void format_custom_arg(const void* arg,
+ typename Context::parse_context_type& parse_ctx,
+ Context& ctx) {
+ Formatter f;
+ parse_ctx.advance_to(f.parse(parse_ctx));
+ ctx.advance_to(f.format(*static_cast(arg), ctx));
+ }
+};
+
+template
+FMT_CONSTEXPR basic_format_arg make_arg(const T& value);
+
+// To minimize the number of types we need to deal with, long is translated
+// either to int or to long long depending on its size.
+enum { long_short = sizeof(long) == sizeof(int) };
+using long_type = conditional_t;
+using ulong_type = conditional_t;
+
+struct unformattable {};
+
+// Maps formatting arguments to core types.
+template struct arg_mapper {
+ using char_type = typename Context::char_type;
+
+ FMT_CONSTEXPR int map(signed char val) { return val; }
+ FMT_CONSTEXPR unsigned map(unsigned char val) { return val; }
+ FMT_CONSTEXPR int map(short val) { return val; }
+ FMT_CONSTEXPR unsigned map(unsigned short val) { return val; }
+ FMT_CONSTEXPR int map(int val) { return val; }
+ FMT_CONSTEXPR unsigned map(unsigned val) { return val; }
+ FMT_CONSTEXPR long_type map(long val) { return val; }
+ FMT_CONSTEXPR ulong_type map(unsigned long val) { return val; }
+ FMT_CONSTEXPR long long map(long long val) { return val; }
+ FMT_CONSTEXPR unsigned long long map(unsigned long long val) { return val; }
+ FMT_CONSTEXPR int128_t map(int128_t val) { return val; }
+ FMT_CONSTEXPR uint128_t map(uint128_t val) { return val; }
+ FMT_CONSTEXPR bool map(bool val) { return val; }
+
+ template ::value)>
+ FMT_CONSTEXPR char_type map(T val) {
+ static_assert(
+ std::is_same::value || std::is_same::value,
+ "mixing character types is disallowed");
+ return val;
+ }
+
+ FMT_CONSTEXPR float map(float val) { return val; }
+ FMT_CONSTEXPR double map(double val) { return val; }
+ FMT_CONSTEXPR long double map(long double val) { return val; }
+
+ FMT_CONSTEXPR const char_type* map(char_type* val) { return val; }
+ FMT_CONSTEXPR const char_type* map(const char_type* val) { return val; }
+ template ::value)>
+ FMT_CONSTEXPR basic_string_view map(const T& val) {
+ static_assert(std::is_same>::value,
+ "mixing character types is disallowed");
+ return to_string_view(val);
+ }
+ template , T>::value &&
+ !is_string::value && !has_formatter::value &&
+ !has_fallback_formatter::value)>
+ FMT_CONSTEXPR basic_string_view map(const T& val) {
+ return basic_string_view(val);
+ }
+ template <
+ typename T,
+ FMT_ENABLE_IF(
+ std::is_constructible, T>::value &&
+ !std::is_constructible, T>::value &&
+ !is_string::value && !has_formatter::value &&
+ !has_fallback_formatter::value)>
+ FMT_CONSTEXPR basic_string_view map(const T& val) {
+ return std_string_view(val);
+ }
+ FMT_CONSTEXPR const char* map(const signed char* val) {
+ static_assert(std::is_same::value, "invalid string type");
+ return reinterpret_cast(val);
+ }
+ FMT_CONSTEXPR const char* map(const unsigned char* val) {
+ static_assert(std::is_same::value, "invalid string type");
+ return reinterpret_cast(val);
+ }
+ FMT_CONSTEXPR const char* map(signed char* val) {
+ const auto* const_val = val;
+ return map(const_val);
+ }
+ FMT_CONSTEXPR const char* map(unsigned char* val) {
+ const auto* const_val = val;
+ return map(const_val);
+ }
+
+ FMT_CONSTEXPR const void* map(void* val) { return val; }
+ FMT_CONSTEXPR const void* map(const void* val) { return val; }
+ FMT_CONSTEXPR const void* map(std::nullptr_t val) { return val; }
+ template FMT_CONSTEXPR int map(const T*) {
+ // Formatting of arbitrary pointers is disallowed. If you want to output
+ // a pointer cast it to "void *" or "const void *". In particular, this
+ // forbids formatting of "[const] volatile char *" which is printed as bool
+ // by iostreams.
+ static_assert(!sizeof(T), "formatting of non-void pointers is disallowed");
+ return 0;
+ }
+
+ template ::value &&
+ !has_formatter::value &&
+ !has_fallback_formatter::value)>
+ FMT_CONSTEXPR auto map(const T& val)
+ -> decltype(std::declval().map(
+ static_cast::type>(val))) {
+ return map(static_cast::type>(val));
+ }
+ template ::value && !is_char::value &&
+ (has_formatter::value ||
+ has_fallback_formatter::value))>
+ FMT_CONSTEXPR const T& map(const T& val) {
+ return val;
+ }
+
+ template
+ FMT_CONSTEXPR auto map(const named_arg& val)
+ -> decltype(std::declval().map(val.value)) {
+ return map(val.value);
+ }
+
+ unformattable map(...) { return {}; }
+};
+
+// A type constant after applying arg_mapper.
+template
+using mapped_type_constant =
+ type_constant().map(std::declval())),
+ typename Context::char_type>;
+
+enum { packed_arg_bits = 4 };
+// Maximum number of arguments with packed types.
+enum { max_packed_args = 62 / packed_arg_bits };
+enum : unsigned long long { is_unpacked_bit = 1ULL << 63 };
+enum : unsigned long long { has_named_args_bit = 1ULL << 62 };
+} // namespace detail
+
+// A formatting argument. It is a trivially copyable/constructible type to
+// allow storage in basic_memory_buffer.
+template class basic_format_arg {
+ private:
+ detail::value value_;
+ detail::type type_;
+
+ template
+ friend FMT_CONSTEXPR basic_format_arg detail::make_arg(
+ const T& value);
+
+ template
+ friend FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis,
+ const basic_format_arg& arg)
+ -> decltype(vis(0));
+
+ friend class basic_format_args;
+ friend class dynamic_format_arg_store;
+
+ using char_type = typename Context::char_type;
+
+ template
+ friend struct detail::arg_data;
+
+ basic_format_arg(const detail::named_arg_info* args, size_t size)
+ : value_(args, size) {}
+
+ public:
+ class handle {
+ public:
+ explicit handle(detail::custom_value custom) : custom_(custom) {}
+
+ void format(typename Context::parse_context_type& parse_ctx,
+ Context& ctx) const {
+ custom_.format(custom_.value, parse_ctx, ctx);
+ }
+
+ private:
+ detail::custom_value