├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── comboaddress.cc ├── comboaddress.hh ├── ext └── fmt-5.2.1 │ ├── README.md │ ├── include │ └── fmt │ │ ├── color.h │ │ ├── core.h │ │ ├── format-inl.h │ │ ├── format.h │ │ ├── ostream.h │ │ ├── posix.h │ │ ├── printf.h │ │ ├── ranges.h │ │ └── time.h │ └── src │ ├── format.cc │ └── posix.cc ├── meson.build ├── sclasses.cc ├── sclasses.hh ├── socket-api.md ├── swrappers.cc ├── swrappers.hh └── test.cc /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.d 3 | # Compiled Object files 4 | *.slo 5 | *.lo 6 | *.o 7 | *.obj 8 | 9 | # Precompiled Headers 10 | *.gch 11 | *.pch 12 | 13 | # Compiled Dynamic libraries 14 | *.so 15 | *.dylib 16 | *.dll 17 | 18 | # Fortran module files 19 | *.mod 20 | *.smod 21 | 22 | # Compiled Static libraries 23 | *.lai 24 | *.la 25 | *.a 26 | *.lib 27 | 28 | # Executables 29 | *.exe 30 | *.out 31 | *.app 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017 PowerDNS.COM BV & various contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to 5 | deal in the Software without restriction, including without limitation the 6 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | sell copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CXXFLAGS:=-std=gnu++14 -Wall -MMD -MP -Iext/fmt-5.2.1/include 2 | 3 | 4 | all: test 5 | 6 | clean: 7 | rm -f *~ *.o *.d test 8 | 9 | -include *.d 10 | 11 | SIMPLESOCKETS=comboaddress.o swrappers.o sclasses.o ext/fmt-5.2.1/src/format.o 12 | 13 | test: test.o $(SIMPLESOCKETS) 14 | g++ -std=gnu++14 $^ -o $@ 15 | 16 | 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # simplesocket 2 | simple socket helpers for C++ 2011 (or perhaps C++ 2014). 3 | 4 | From C++ the full POSIX and OS socket functions are available. These are 5 | very powerful, offer well known semantics, but are somewhat of a pain to 6 | use. 7 | 8 | Various libraries have attempted to offer "C++ native" socket environments, 9 | but most of these offer different semantics that are less well known. Many 10 | of them are also painful to use but in different ways. 11 | 12 | This small set of files attempts to offer: 13 | 14 | * A native datastructure that is understood by all socket calls, but easily 15 | manipulated and created form C++ (ComboAddress) 16 | * Easier to use wrappers of the main BSD socket calls 17 | * A few classes that build on the above to aid you achieve common tasks like 18 | reading a line from a socket to C++ friendly data structures 19 | 20 | Each of these layers builds on the previous ones. If you want, you can only 21 | use only ComboAddress, or only ComboAddress and the wrappers. 22 | 23 | Documentation (by Doxygen) is [here](https://ds9a.nl/simplesocket). 24 | 25 | ## Sample code 26 | Some sample code using all three elements: 27 | ``` 28 | auto addresses=resolveName("ds9a.nl"); // this retrieves IPv4 and IPv6 29 | 30 | for(auto& a : addresses) { 31 | a.setPort(80); 32 | cout << "Connecting to: " << a.toStringWithPort() << endl; 33 | 34 | Socket rs(a.sin.sin_family, SOCK_STREAM); 35 | SocketCommunicator sc(rs); 36 | sc.connect(a); 37 | sc.writen("GET / HTTP/1.1\r\nHost: ds9a.nl\r\nConnection: Close\r\n\r\n"); 38 | 39 | std::string line; 40 | while(sc.getLine(line)) { 41 | cout<<"Got: "<= 32) 9 | return; 10 | start = (uint8_t*)&sin4.sin_addr.s_addr; 11 | len=4; 12 | } 13 | else { 14 | if(bits >= 128) 15 | return; 16 | start = (uint8_t*)&sin6.sin6_addr.s6_addr; 17 | len=16; 18 | } 19 | 20 | auto tozero= len*8 - bits; // if set to 22, this will clear 1 byte, as it should 21 | 22 | memset(start + len - tozero/8, 0, tozero/8); // blot out the whole bytes on the right 23 | 24 | auto bitsleft=tozero % 8; // 2 bits left to clear 25 | 26 | // a b c d, to truncate to 22 bits, we just zeroed 'd' and need to zero 2 bits from c 27 | // so and by '11111100', which is ~((1<<2)-1) = ~3 28 | uint8_t* place = start + len - 1 - tozero/8; 29 | *place &= (~((1< addr.size() || addr[pos+1]!=':') 41 | return -1; 42 | ourAddr.assign(addr.c_str() + 1, pos-1); 43 | port = atoi(addr.substr(pos+2).c_str()); 44 | } 45 | ret->sin6_scope_id=0; 46 | ret->sin6_family=AF_INET6; 47 | 48 | if(inet_pton(AF_INET6, ourAddr.c_str(), (void*)&ret->sin6_addr) != 1) { 49 | struct addrinfo* res; 50 | struct addrinfo hints; 51 | memset(&hints, 0, sizeof(hints)); 52 | 53 | hints.ai_family = AF_INET6; 54 | hints.ai_flags = AI_NUMERICHOST; 55 | 56 | int error; 57 | // getaddrinfo has anomalous return codes, anything nonzero is an error, positive or negative 58 | if((error=getaddrinfo(ourAddr.c_str(), 0, &hints, &res))) { 59 | return -1; 60 | } 61 | 62 | memcpy(ret, res->ai_addr, res->ai_addrlen); 63 | freeaddrinfo(res); 64 | } 65 | 66 | if(port > 65535) 67 | // negative ports are found with the pdns_stou above 68 | return -1; 69 | 70 | if(port >= 0) 71 | ret->sin6_port = htons(port); 72 | 73 | return 0; 74 | } 75 | 76 | int makeIPv4sockaddr(const std::string& str, struct sockaddr_in* ret) 77 | { 78 | if(str.empty()) { 79 | return -1; 80 | } 81 | struct in_addr inp; 82 | 83 | auto pos = str.find(':'); 84 | if(pos == std::string::npos) { // no port specified, not touching the port 85 | if(inet_aton(str.c_str(), &inp)) { 86 | ret->sin_addr.s_addr=inp.s_addr; 87 | return 0; 88 | } 89 | return -1; 90 | } 91 | if(!*(str.c_str() + pos + 1)) // trailing : 92 | return -1; 93 | 94 | char *eptr = (char*)str.c_str() + str.size(); 95 | int port = strtol(str.c_str() + pos + 1, &eptr, 10); 96 | if (port < 0 || port > 65535) 97 | return -1; 98 | 99 | if(*eptr) 100 | return -1; 101 | 102 | ret->sin_port = htons(port); 103 | if(inet_aton(str.substr(0, pos).c_str(), &inp)) { 104 | ret->sin_addr.s_addr=inp.s_addr; 105 | return 0; 106 | } 107 | return -1; 108 | } 109 | -------------------------------------------------------------------------------- /comboaddress.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret); 16 | int makeIPv4sockaddr(const std::string& str, struct sockaddr_in* ret); 17 | 18 | constexpr uint32_t chtonl(uint32_t s) 19 | { 20 | return ( 21 | ((s & 0x000000FF) << 24) | ((s & 0x0000FF00) << 8) 22 | | ((s & 0xFF000000) >> 24) | ((s & 0x00FF0000) >> 8) 23 | ); 24 | } 25 | 26 | constexpr struct sockaddr_in operator "" _ipv4(const char* p, size_t l) 27 | { 28 | struct sockaddr_in ret={}; 29 | ret.sin_addr.s_addr=0; 30 | ret.sin_family=AF_INET; 31 | 32 | uint8_t octet=0; 33 | 34 | size_t n=0; 35 | for(; n < l; ++n) { 36 | if(p[n]==':') 37 | break; 38 | if(p[n]=='.') { 39 | ret.sin_addr.s_addr*=0x100; 40 | ret.sin_addr.s_addr+=octet; 41 | octet=0; 42 | } 43 | else { 44 | octet*=10; 45 | octet+=p[n]-'0'; 46 | } 47 | } 48 | ret.sin_addr.s_addr*=0x100; 49 | ret.sin_addr.s_addr+=octet; 50 | 51 | ret.sin_addr.s_addr = chtonl(ret.sin_addr.s_addr); 52 | 53 | if(p[n]==':') { 54 | for(++n; n < l; ++n) { 55 | ret.sin_port*=10; 56 | ret.sin_port += p[n]-'0'; 57 | } 58 | ret.sin_port = 0x100 * (ret.sin_port&0xff) + (ret.sin_port/0x100); 59 | } 60 | return ret; 61 | 62 | } 63 | 64 | /** The ComboAddress holds an IPv4 or an IPv6 endpoint, including a source port. 65 | It is ABI-compatible with struct sockaddr, sockaddr_in and sockaddr_in6. 66 | This means it can be passed to the kernel via a pointer directly. 67 | 68 | When doing so, it is imperative to pass the right length parameter, because some 69 | operating systems get confused if they see length longer than necessary. 70 | 71 | Canonical use is: connect(sock, (struct sockaddr*)&combo, combo.getSocklen()) 72 | 73 | The union has methods for parsing string ('human') IP address representations, and 74 | these support all kinds of addresses, including scoped IPv6 and port numbers 75 | (1.2.3.4:80 and [::1]:80 or even [fe80::1%eth0]:80). 76 | */ 77 | 78 | union ComboAddress { 79 | struct sockaddr_in sin; 80 | struct sockaddr_in sin4; 81 | struct sockaddr_in6 sin6; 82 | 83 | //! Tests for equality, including port number. IPv4 and IPv6 are never equal. 84 | bool operator==(const ComboAddress& rhs) const 85 | { 86 | if(std::tie(sin4.sin_family, sin4.sin_port) != std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) 87 | return false; 88 | if(sin4.sin_family == AF_INET) 89 | return sin4.sin_addr.s_addr == rhs.sin4.sin_addr.s_addr; 90 | else 91 | return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(sin6.sin6_addr.s6_addr))==0; 92 | } 93 | 94 | //! Inequality 95 | bool operator!=(const ComboAddress& rhs) const 96 | { 97 | return(!operator==(rhs)); 98 | } 99 | 100 | //! This ordering is intended to be fast and strict, but not necessarily human friendly. 101 | bool operator<(const ComboAddress& rhs) const 102 | { 103 | if(sin4.sin_family == 0) { 104 | return false; 105 | } 106 | if(std::tie(sin4.sin_family, sin4.sin_port) < std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) 107 | return true; 108 | if(std::tie(sin4.sin_family, sin4.sin_port) > std::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) 109 | return false; 110 | 111 | if(sin4.sin_family == AF_INET) 112 | return sin4.sin_addr.s_addr < rhs.sin4.sin_addr.s_addr; 113 | else 114 | return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(sin6.sin6_addr.s6_addr)) < 0; 115 | } 116 | 117 | bool operator>(const ComboAddress& rhs) const 118 | { 119 | return rhs.operator<(*this); 120 | } 121 | /* 122 | struct addressOnlyHash 123 | { 124 | uint32_t operator()(const ComboAddress& ca) const 125 | { 126 | const unsigned char* start; 127 | int len; 128 | if(ca.sin4.sin_family == AF_INET) { 129 | start =(const unsigned char*)&ca.sin4.sin_addr.s_addr; 130 | len=4; 131 | } 132 | else { 133 | start =(const unsigned char*)&ca.sin6.sin6_addr.s6_addr; 134 | len=16; 135 | } 136 | return burtle(start, len, 0); 137 | } 138 | }; 139 | */ 140 | 141 | //! Convenience comparator that compares regardless of port. 142 | struct addressOnlyLessThan 143 | { 144 | bool operator()(const ComboAddress& a, const ComboAddress& b) const 145 | { 146 | if(a.sin4.sin_family < b.sin4.sin_family) 147 | return true; 148 | if(a.sin4.sin_family > b.sin4.sin_family) 149 | return false; 150 | if(a.sin4.sin_family == AF_INET) 151 | return a.sin4.sin_addr.s_addr < b.sin4.sin_addr.s_addr; 152 | else 153 | return memcmp(&a.sin6.sin6_addr.s6_addr, &b.sin6.sin6_addr.s6_addr, sizeof(a.sin6.sin6_addr.s6_addr)) < 0; 154 | } 155 | }; 156 | //! Convenience comparator that compares regardless of port. 157 | struct addressOnlyEqual 158 | { 159 | bool operator()(const ComboAddress& a, const ComboAddress& b) const 160 | { 161 | if(a.sin4.sin_family != b.sin4.sin_family) 162 | return false; 163 | if(a.sin4.sin_family == AF_INET) 164 | return a.sin4.sin_addr.s_addr == b.sin4.sin_addr.s_addr; 165 | else 166 | return !memcmp(&a.sin6.sin6_addr.s6_addr, &b.sin6.sin6_addr.s6_addr, sizeof(a.sin6.sin6_addr.s6_addr)); 167 | } 168 | }; 169 | 170 | //! it is vital to pass the correct socklen to the kernel 171 | socklen_t getSocklen() const 172 | { 173 | if(sin4.sin_family == AF_INET) 174 | return sizeof(sin4); 175 | else 176 | return sizeof(sin6); 177 | } 178 | 179 | //! Initializes an 'empty', impossible, ComboAddress 180 | ComboAddress() 181 | { 182 | sin4.sin_family=AF_INET; 183 | sin4.sin_addr.s_addr=0; 184 | sin4.sin_port=0; 185 | } 186 | 187 | //! Make a ComboAddress from a traditional sockaddr 188 | ComboAddress(const struct sockaddr *sa, socklen_t salen) { 189 | setSockaddr(sa, salen); 190 | } 191 | 192 | //! Make a ComboAddress from a traditional sockaddr_in6 193 | ComboAddress(const struct sockaddr_in6 *sa) { 194 | setSockaddr((const struct sockaddr*)sa, sizeof(struct sockaddr_in6)); 195 | } 196 | 197 | //! Make a ComboAddress from a traditional sockaddr_in 198 | ComboAddress(const struct sockaddr_in *sa) { 199 | setSockaddr((const struct sockaddr*)sa, sizeof(struct sockaddr_in)); 200 | } 201 | //! Make a ComboAddress from a traditional sockaddr 202 | ComboAddress(const struct sockaddr_in& sa) { 203 | setSockaddr((const struct sockaddr*)&sa, sizeof(struct sockaddr_in)); 204 | } 205 | 206 | void setSockaddr(const struct sockaddr *sa, socklen_t salen) { 207 | if (salen > sizeof(struct sockaddr_in6)) throw std::runtime_error("ComboAddress can't handle other than sockaddr_in or sockaddr_in6"); 208 | memcpy(this, sa, salen); 209 | } 210 | 211 | /** "Human" representation constructor. 212 | The following are all identical: 213 | ComboAddress("1.2.3.4:80"); 214 | ComboAddress("1.2.3.4", 80); 215 | ComboAddress("1.2.3.4:80", 1234) 216 | 217 | As are: 218 | ComboAddress("fe80::1%eth0", 80); 219 | ComboAddress("[fe80::1%eth0]:80"); 220 | ComboAddress("[fe::1%eth0]:80", 1234); 221 | */ 222 | explicit ComboAddress(const std::string& str, uint16_t port=0) 223 | { 224 | memset(&sin6, 0, sizeof(sin6)); 225 | sin4.sin_family = AF_INET; 226 | sin4.sin_port = 0; 227 | if(makeIPv4sockaddr(str, &sin4)) { 228 | sin6.sin6_family = AF_INET6; 229 | if(makeIPv6sockaddr(str, &sin6) < 0) 230 | throw std::runtime_error("Unable to convert presentation address '"+ str +"'"); 231 | 232 | } 233 | if(!sin4.sin_port) // 'str' overrides port! 234 | sin4.sin_port=htons(port); 235 | } 236 | //! Sets port, deals with htons for you 237 | void setPort(uint16_t port) 238 | { 239 | sin4.sin_port = htons(port); 240 | } 241 | //! Is this an IPv6 address? 242 | bool isIPv6() const 243 | { 244 | return sin4.sin_family == AF_INET6; 245 | } 246 | 247 | //! Is this an IPv4 address? 248 | bool isIPv4() const 249 | { 250 | return sin4.sin_family == AF_INET; 251 | } 252 | 253 | //! Is this an ffff:: style IPv6 address? 254 | bool isMappedIPv4() const 255 | { 256 | if(sin4.sin_family!=AF_INET6) 257 | return false; 258 | 259 | int n=0; 260 | const unsigned char*ptr = (unsigned char*) &sin6.sin6_addr.s6_addr; 261 | for(n=0; n < 10; ++n) 262 | if(ptr[n]) 263 | return false; 264 | 265 | for(; n < 12; ++n) 266 | if(ptr[n]!=0xff) 267 | return false; 268 | 269 | return true; 270 | } 271 | 272 | //! Extract the IPv4 address from a mapped IPv6 address 273 | ComboAddress mapToIPv4() const 274 | { 275 | if(!isMappedIPv4()) 276 | throw std::runtime_error("ComboAddress can't map non-mapped IPv6 address back to IPv4"); 277 | ComboAddress ret; 278 | ret.sin4.sin_family=AF_INET; 279 | ret.sin4.sin_port=sin4.sin_port; 280 | 281 | const unsigned char*ptr = (unsigned char*) &sin6.sin6_addr.s6_addr; 282 | ptr+=(sizeof(sin6.sin6_addr.s6_addr) - sizeof(ret.sin4.sin_addr.s_addr)); 283 | memcpy(&ret.sin4.sin_addr.s_addr, ptr, sizeof(ret.sin4.sin_addr.s_addr)); 284 | return ret; 285 | } 286 | 287 | //! Returns a string (human) represntation of the address 288 | std::string toString() const 289 | { 290 | char host[1024]; 291 | if(sin4.sin_family && !getnameinfo((struct sockaddr*) this, getSocklen(), host, sizeof(host),0, 0, NI_NUMERICHOST)) 292 | return host; 293 | else 294 | return "invalid"; 295 | } 296 | 297 | //! Returns a string (human) represntation of the address, including port 298 | std::string toStringWithPort() const 299 | { 300 | if(sin4.sin_family==AF_INET) 301 | return toString() + ":" + std::to_string(ntohs(sin4.sin_port)); 302 | else 303 | return "["+toString() + "]:" + std::to_string(ntohs(sin4.sin_port)); 304 | } 305 | 306 | void truncate(unsigned int bits); 307 | }; 308 | 309 | 310 | 311 | /** This class represents a netmask and can be queried to see if a certain 312 | IP address is matched by this mask */ 313 | class Netmask 314 | { 315 | public: 316 | Netmask() 317 | { 318 | d_network.sin4.sin_family=0; // disable this doing anything useful 319 | d_network.sin4.sin_port = 0; // this guarantees d_network compares identical 320 | d_mask=0; 321 | d_bits=0; 322 | } 323 | 324 | explicit Netmask(const ComboAddress& network, uint8_t bits=0xff) 325 | { 326 | d_network = network; 327 | d_network.sin4.sin_port=0; 328 | if(bits > 128) 329 | bits = (network.sin4.sin_family == AF_INET) ? 32 : 128; 330 | 331 | d_bits = bits; 332 | if(d_bits<32) 333 | d_mask=~(0xFFFFFFFF>>d_bits); 334 | else 335 | d_mask=0xFFFFFFFF; // not actually used for IPv6 336 | } 337 | 338 | static std::pair splitField(const std::string& inp, char sepa) 339 | { 340 | std::pair ret; 341 | auto cpos=inp.find(sepa); 342 | if(cpos==std::string::npos) 343 | ret.first=inp; 344 | else { 345 | ret.first=inp.substr(0, cpos); 346 | ret.second=inp.substr(cpos+1); 347 | } 348 | return ret; 349 | } 350 | 351 | 352 | //! Constructor supplies the mask, which cannot be changed 353 | Netmask(const std::string &mask) 354 | { 355 | auto split=splitField(mask,'/'); 356 | d_network=ComboAddress(split.first); 357 | 358 | if(!split.second.empty()) { 359 | d_bits = (uint8_t)atoi(split.second.c_str()); 360 | if(d_bits<32) 361 | d_mask=~(0xFFFFFFFF>>d_bits); 362 | else 363 | d_mask=0xFFFFFFFF; 364 | } 365 | else if(d_network.sin4.sin_family==AF_INET) { 366 | d_bits = 32; 367 | d_mask = 0xFFFFFFFF; 368 | } 369 | else { 370 | d_bits=128; 371 | d_mask=0; // silence silly warning - d_mask is unused for IPv6 372 | } 373 | } 374 | 375 | bool match(const ComboAddress& ip) const 376 | { 377 | return match(&ip); 378 | } 379 | 380 | //! If this IP address in socket address matches 381 | bool match(const ComboAddress *ip) const 382 | { 383 | if(d_network.sin4.sin_family != ip->sin4.sin_family) { 384 | return false; 385 | } 386 | if(d_network.sin4.sin_family == AF_INET) { 387 | return match4(htonl((unsigned int)ip->sin4.sin_addr.s_addr)); 388 | } 389 | if(d_network.sin6.sin6_family == AF_INET6) { 390 | uint8_t bytes=d_bits/8, n; 391 | const uint8_t *us=(const uint8_t*) &d_network.sin6.sin6_addr.s6_addr; 392 | const uint8_t *them=(const uint8_t*) &ip->sin6.sin6_addr.s6_addr; 393 | 394 | for(n=0; n < bytes; ++n) { 395 | if(us[n]!=them[n]) { 396 | return false; 397 | } 398 | } 399 | // still here, now match remaining bits 400 | uint8_t bits= d_bits % 8; 401 | uint8_t mask= (uint8_t) ~(0xFF>>bits); 402 | 403 | return((us[n] & mask) == (them[n] & mask)); 404 | } 405 | return false; 406 | } 407 | 408 | //! If this ASCII IP address matches 409 | bool match(const std::string &ip) const 410 | { 411 | ComboAddress address(ip); 412 | return match(&address); 413 | } 414 | 415 | //! If this IP address in native format matches 416 | bool match4(uint32_t ip) const 417 | { 418 | return (ip & d_mask) == (ntohl(d_network.sin4.sin_addr.s_addr) & d_mask); 419 | } 420 | 421 | std::string toString() const 422 | { 423 | return d_network.toString()+"/"+std::to_string((unsigned int)d_bits); 424 | } 425 | 426 | std::string toStringNoMask() const 427 | { 428 | return d_network.toString(); 429 | } 430 | const ComboAddress& getNetwork() const 431 | { 432 | return d_network; 433 | } 434 | const ComboAddress getMaskedNetwork() const 435 | { 436 | ComboAddress result(d_network); 437 | if(isIpv4()) { 438 | result.sin4.sin_addr.s_addr = htonl(ntohl(result.sin4.sin_addr.s_addr) & d_mask); 439 | } 440 | else if(isIpv6()) { 441 | size_t idx; 442 | uint8_t bytes=d_bits/8; 443 | uint8_t *us=(uint8_t*) &result.sin6.sin6_addr.s6_addr; 444 | uint8_t bits= d_bits % 8; 445 | uint8_t mask= (uint8_t) ~(0xFF>>bits); 446 | 447 | if (bytes < sizeof(result.sin6.sin6_addr.s6_addr)) { 448 | us[bytes] &= mask; 449 | } 450 | 451 | for(idx = bytes + 1; idx < sizeof(result.sin6.sin6_addr.s6_addr); ++idx) { 452 | us[idx] = 0; 453 | } 454 | } 455 | return result; 456 | } 457 | int getBits() const 458 | { 459 | return d_bits; 460 | } 461 | bool isIpv6() const 462 | { 463 | return d_network.sin6.sin6_family == AF_INET6; 464 | } 465 | bool isIpv4() const 466 | { 467 | return d_network.sin4.sin_family == AF_INET; 468 | } 469 | 470 | bool operator<(const Netmask& rhs) const 471 | { 472 | return std::tie(d_network, d_bits) < std::tie(rhs.d_network, rhs.d_bits); 473 | } 474 | 475 | bool operator==(const Netmask& rhs) const 476 | { 477 | return std::tie(d_network, d_bits) == std::tie(rhs.d_network, rhs.d_bits); 478 | } 479 | 480 | bool empty() const 481 | { 482 | return d_network.sin4.sin_family==0; 483 | } 484 | 485 | private: 486 | ComboAddress d_network; 487 | uint32_t d_mask; 488 | uint8_t d_bits; 489 | }; 490 | 491 | 492 | -------------------------------------------------------------------------------- /ext/fmt-5.2.1/README.md: -------------------------------------------------------------------------------- 1 | This is fmt from https://github.com/fmtlib/fmt 2 | -------------------------------------------------------------------------------- /ext/fmt-5.2.1/include/fmt/color.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - color support 2 | // 3 | // Copyright (c) 2018 - present, Victor Zverovich and fmt contributors 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_COLOR_H_ 9 | #define FMT_COLOR_H_ 10 | 11 | #include "format.h" 12 | 13 | FMT_BEGIN_NAMESPACE 14 | 15 | #ifdef FMT_DEPRECATED_COLORS 16 | 17 | // color and (v)print_colored are deprecated. 18 | enum color { black, red, green, yellow, blue, magenta, cyan, white }; 19 | FMT_API void vprint_colored(color c, string_view format, format_args args); 20 | FMT_API void vprint_colored(color c, wstring_view format, wformat_args args); 21 | template 22 | inline void print_colored(color c, string_view format_str, 23 | const Args & ... args) { 24 | vprint_colored(c, format_str, make_format_args(args...)); 25 | } 26 | template 27 | inline void print_colored(color c, wstring_view format_str, 28 | const Args & ... args) { 29 | vprint_colored(c, format_str, make_format_args(args...)); 30 | } 31 | 32 | inline void vprint_colored(color c, string_view format, format_args args) { 33 | char escape[] = "\x1b[30m"; 34 | escape[3] = static_cast('0' + c); 35 | std::fputs(escape, stdout); 36 | vprint(format, args); 37 | std::fputs(internal::data::RESET_COLOR, stdout); 38 | } 39 | 40 | inline void vprint_colored(color c, wstring_view format, wformat_args args) { 41 | wchar_t escape[] = L"\x1b[30m"; 42 | escape[3] = static_cast('0' + c); 43 | std::fputws(escape, stdout); 44 | vprint(format, args); 45 | std::fputws(internal::data::WRESET_COLOR, stdout); 46 | } 47 | 48 | #else 49 | 50 | // Experimental color support. 51 | enum class color : uint32_t { 52 | alice_blue = 0xF0F8FF, // rgb(240,248,255) 53 | antique_white = 0xFAEBD7, // rgb(250,235,215) 54 | aqua = 0x00FFFF, // rgb(0,255,255) 55 | aquamarine = 0x7FFFD4, // rgb(127,255,212) 56 | azure = 0xF0FFFF, // rgb(240,255,255) 57 | beige = 0xF5F5DC, // rgb(245,245,220) 58 | bisque = 0xFFE4C4, // rgb(255,228,196) 59 | black = 0x000000, // rgb(0,0,0) 60 | blanched_almond = 0xFFEBCD, // rgb(255,235,205) 61 | blue = 0x0000FF, // rgb(0,0,255) 62 | blue_violet = 0x8A2BE2, // rgb(138,43,226) 63 | brown = 0xA52A2A, // rgb(165,42,42) 64 | burly_wood = 0xDEB887, // rgb(222,184,135) 65 | cadet_blue = 0x5F9EA0, // rgb(95,158,160) 66 | chartreuse = 0x7FFF00, // rgb(127,255,0) 67 | chocolate = 0xD2691E, // rgb(210,105,30) 68 | coral = 0xFF7F50, // rgb(255,127,80) 69 | cornflower_blue = 0x6495ED, // rgb(100,149,237) 70 | cornsilk = 0xFFF8DC, // rgb(255,248,220) 71 | crimson = 0xDC143C, // rgb(220,20,60) 72 | cyan = 0x00FFFF, // rgb(0,255,255) 73 | dark_blue = 0x00008B, // rgb(0,0,139) 74 | dark_cyan = 0x008B8B, // rgb(0,139,139) 75 | dark_golden_rod = 0xB8860B, // rgb(184,134,11) 76 | dark_gray = 0xA9A9A9, // rgb(169,169,169) 77 | dark_green = 0x006400, // rgb(0,100,0) 78 | dark_khaki = 0xBDB76B, // rgb(189,183,107) 79 | dark_magenta = 0x8B008B, // rgb(139,0,139) 80 | dark_olive_green = 0x556B2F, // rgb(85,107,47) 81 | dark_orange = 0xFF8C00, // rgb(255,140,0) 82 | dark_orchid = 0x9932CC, // rgb(153,50,204) 83 | dark_red = 0x8B0000, // rgb(139,0,0) 84 | dark_salmon = 0xE9967A, // rgb(233,150,122) 85 | dark_sea_green = 0x8FBC8F, // rgb(143,188,143) 86 | dark_slate_blue = 0x483D8B, // rgb(72,61,139) 87 | dark_slate_gray = 0x2F4F4F, // rgb(47,79,79) 88 | dark_turquoise = 0x00CED1, // rgb(0,206,209) 89 | dark_violet = 0x9400D3, // rgb(148,0,211) 90 | deep_pink = 0xFF1493, // rgb(255,20,147) 91 | deep_sky_blue = 0x00BFFF, // rgb(0,191,255) 92 | dim_gray = 0x696969, // rgb(105,105,105) 93 | dodger_blue = 0x1E90FF, // rgb(30,144,255) 94 | fire_brick = 0xB22222, // rgb(178,34,34) 95 | floral_white = 0xFFFAF0, // rgb(255,250,240) 96 | forest_green = 0x228B22, // rgb(34,139,34) 97 | fuchsia = 0xFF00FF, // rgb(255,0,255) 98 | gainsboro = 0xDCDCDC, // rgb(220,220,220) 99 | ghost_white = 0xF8F8FF, // rgb(248,248,255) 100 | gold = 0xFFD700, // rgb(255,215,0) 101 | golden_rod = 0xDAA520, // rgb(218,165,32) 102 | gray = 0x808080, // rgb(128,128,128) 103 | green = 0x008000, // rgb(0,128,0) 104 | green_yellow = 0xADFF2F, // rgb(173,255,47) 105 | honey_dew = 0xF0FFF0, // rgb(240,255,240) 106 | hot_pink = 0xFF69B4, // rgb(255,105,180) 107 | indian_red = 0xCD5C5C, // rgb(205,92,92) 108 | indigo = 0x4B0082, // rgb(75,0,130) 109 | ivory = 0xFFFFF0, // rgb(255,255,240) 110 | khaki = 0xF0E68C, // rgb(240,230,140) 111 | lavender = 0xE6E6FA, // rgb(230,230,250) 112 | lavender_blush = 0xFFF0F5, // rgb(255,240,245) 113 | lawn_green = 0x7CFC00, // rgb(124,252,0) 114 | lemon_chiffon = 0xFFFACD, // rgb(255,250,205) 115 | light_blue = 0xADD8E6, // rgb(173,216,230) 116 | light_coral = 0xF08080, // rgb(240,128,128) 117 | light_cyan = 0xE0FFFF, // rgb(224,255,255) 118 | light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210) 119 | light_gray = 0xD3D3D3, // rgb(211,211,211) 120 | light_green = 0x90EE90, // rgb(144,238,144) 121 | light_pink = 0xFFB6C1, // rgb(255,182,193) 122 | light_salmon = 0xFFA07A, // rgb(255,160,122) 123 | light_sea_green = 0x20B2AA, // rgb(32,178,170) 124 | light_sky_blue = 0x87CEFA, // rgb(135,206,250) 125 | light_slate_gray = 0x778899, // rgb(119,136,153) 126 | light_steel_blue = 0xB0C4DE, // rgb(176,196,222) 127 | light_yellow = 0xFFFFE0, // rgb(255,255,224) 128 | lime = 0x00FF00, // rgb(0,255,0) 129 | lime_green = 0x32CD32, // rgb(50,205,50) 130 | linen = 0xFAF0E6, // rgb(250,240,230) 131 | magenta = 0xFF00FF, // rgb(255,0,255) 132 | maroon = 0x800000, // rgb(128,0,0) 133 | medium_aquamarine = 0x66CDAA, // rgb(102,205,170) 134 | medium_blue = 0x0000CD, // rgb(0,0,205) 135 | medium_orchid = 0xBA55D3, // rgb(186,85,211) 136 | medium_purple = 0x9370DB, // rgb(147,112,219) 137 | medium_sea_green = 0x3CB371, // rgb(60,179,113) 138 | medium_slate_blue = 0x7B68EE, // rgb(123,104,238) 139 | medium_spring_green = 0x00FA9A, // rgb(0,250,154) 140 | medium_turquoise = 0x48D1CC, // rgb(72,209,204) 141 | medium_violet_red = 0xC71585, // rgb(199,21,133) 142 | midnight_blue = 0x191970, // rgb(25,25,112) 143 | mint_cream = 0xF5FFFA, // rgb(245,255,250) 144 | misty_rose = 0xFFE4E1, // rgb(255,228,225) 145 | moccasin = 0xFFE4B5, // rgb(255,228,181) 146 | navajo_white = 0xFFDEAD, // rgb(255,222,173) 147 | navy = 0x000080, // rgb(0,0,128) 148 | old_lace = 0xFDF5E6, // rgb(253,245,230) 149 | olive = 0x808000, // rgb(128,128,0) 150 | olive_drab = 0x6B8E23, // rgb(107,142,35) 151 | orange = 0xFFA500, // rgb(255,165,0) 152 | orange_red = 0xFF4500, // rgb(255,69,0) 153 | orchid = 0xDA70D6, // rgb(218,112,214) 154 | pale_golden_rod = 0xEEE8AA, // rgb(238,232,170) 155 | pale_green = 0x98FB98, // rgb(152,251,152) 156 | pale_turquoise = 0xAFEEEE, // rgb(175,238,238) 157 | pale_violet_red = 0xDB7093, // rgb(219,112,147) 158 | papaya_whip = 0xFFEFD5, // rgb(255,239,213) 159 | peach_puff = 0xFFDAB9, // rgb(255,218,185) 160 | peru = 0xCD853F, // rgb(205,133,63) 161 | pink = 0xFFC0CB, // rgb(255,192,203) 162 | plum = 0xDDA0DD, // rgb(221,160,221) 163 | powder_blue = 0xB0E0E6, // rgb(176,224,230) 164 | purple = 0x800080, // rgb(128,0,128) 165 | rebecca_purple = 0x663399, // rgb(102,51,153) 166 | red = 0xFF0000, // rgb(255,0,0) 167 | rosy_brown = 0xBC8F8F, // rgb(188,143,143) 168 | royal_blue = 0x4169E1, // rgb(65,105,225) 169 | saddle_brown = 0x8B4513, // rgb(139,69,19) 170 | salmon = 0xFA8072, // rgb(250,128,114) 171 | sandy_brown = 0xF4A460, // rgb(244,164,96) 172 | sea_green = 0x2E8B57, // rgb(46,139,87) 173 | sea_shell = 0xFFF5EE, // rgb(255,245,238) 174 | sienna = 0xA0522D, // rgb(160,82,45) 175 | silver = 0xC0C0C0, // rgb(192,192,192) 176 | sky_blue = 0x87CEEB, // rgb(135,206,235) 177 | slate_blue = 0x6A5ACD, // rgb(106,90,205) 178 | slate_gray = 0x708090, // rgb(112,128,144) 179 | snow = 0xFFFAFA, // rgb(255,250,250) 180 | spring_green = 0x00FF7F, // rgb(0,255,127) 181 | steel_blue = 0x4682B4, // rgb(70,130,180) 182 | tan = 0xD2B48C, // rgb(210,180,140) 183 | teal = 0x008080, // rgb(0,128,128) 184 | thistle = 0xD8BFD8, // rgb(216,191,216) 185 | tomato = 0xFF6347, // rgb(255,99,71) 186 | turquoise = 0x40E0D0, // rgb(64,224,208) 187 | violet = 0xEE82EE, // rgb(238,130,238) 188 | wheat = 0xF5DEB3, // rgb(245,222,179) 189 | white = 0xFFFFFF, // rgb(255,255,255) 190 | white_smoke = 0xF5F5F5, // rgb(245,245,245) 191 | yellow = 0xFFFF00, // rgb(255,255,0) 192 | yellow_green = 0x9ACD32, // rgb(154,205,50) 193 | }; // enum class color 194 | 195 | // rgb is a struct for red, green and blue colors. 196 | // We use rgb as name because some editors will show it as color direct in the 197 | // editor. 198 | struct rgb { 199 | FMT_CONSTEXPR_DECL rgb() : r(0), g(0), b(0) {} 200 | FMT_CONSTEXPR_DECL rgb(uint8_t r_, uint8_t g_, uint8_t b_) 201 | : r(r_), g(g_), b(b_) {} 202 | FMT_CONSTEXPR_DECL rgb(uint32_t hex) 203 | : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b((hex) & 0xFF) {} 204 | FMT_CONSTEXPR_DECL rgb(color hex) 205 | : r((uint32_t(hex) >> 16) & 0xFF), g((uint32_t(hex) >> 8) & 0xFF), 206 | b(uint32_t(hex) & 0xFF) {} 207 | uint8_t r; 208 | uint8_t g; 209 | uint8_t b; 210 | }; 211 | 212 | void vprint_rgb(rgb fd, string_view format, format_args args); 213 | void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args); 214 | 215 | /** 216 | Formats a string and prints it to stdout using ANSI escape sequences to 217 | specify foreground color 'fd'. 218 | Example: 219 | fmt::print(fmt::color::red, "Elapsed time: {0:.2f} seconds", 1.23); 220 | */ 221 | template 222 | inline void print(rgb fd, string_view format_str, const Args & ... args) { 223 | vprint_rgb(fd, format_str, make_format_args(args...)); 224 | } 225 | 226 | /** 227 | Formats a string and prints it to stdout using ANSI escape sequences to 228 | specify foreground color 'fd' and background color 'bg'. 229 | Example: 230 | fmt::print(fmt::color::red, fmt::color::black, 231 | "Elapsed time: {0:.2f} seconds", 1.23); 232 | */ 233 | template 234 | inline void print(rgb fd, rgb bg, string_view format_str, 235 | const Args & ... args) { 236 | vprint_rgb(fd, bg, format_str, make_format_args(args...)); 237 | } 238 | namespace internal { 239 | FMT_CONSTEXPR void to_esc(uint8_t c, char out[], int offset) { 240 | out[offset + 0] = static_cast('0' + c / 100); 241 | out[offset + 1] = static_cast('0' + c / 10 % 10); 242 | out[offset + 2] = static_cast('0' + c % 10); 243 | } 244 | } // namespace internal 245 | 246 | inline void vprint_rgb(rgb fd, string_view format, format_args args) { 247 | char escape_fd[] = "\x1b[38;2;000;000;000m"; 248 | internal::to_esc(fd.r, escape_fd, 7); 249 | internal::to_esc(fd.g, escape_fd, 11); 250 | internal::to_esc(fd.b, escape_fd, 15); 251 | 252 | std::fputs(escape_fd, stdout); 253 | vprint(format, args); 254 | std::fputs(internal::data::RESET_COLOR, stdout); 255 | } 256 | 257 | inline void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args) { 258 | char escape_fd[] = "\x1b[38;2;000;000;000m"; // foreground color 259 | char escape_bg[] = "\x1b[48;2;000;000;000m"; // background color 260 | internal::to_esc(fd.r, escape_fd, 7); 261 | internal::to_esc(fd.g, escape_fd, 11); 262 | internal::to_esc(fd.b, escape_fd, 15); 263 | 264 | internal::to_esc(bg.r, escape_bg, 7); 265 | internal::to_esc(bg.g, escape_bg, 11); 266 | internal::to_esc(bg.b, escape_bg, 15); 267 | 268 | std::fputs(escape_fd, stdout); 269 | std::fputs(escape_bg, stdout); 270 | vprint(format, args); 271 | std::fputs(internal::data::RESET_COLOR, stdout); 272 | } 273 | 274 | #endif 275 | 276 | FMT_END_NAMESPACE 277 | 278 | #endif // FMT_COLOR_H_ 279 | -------------------------------------------------------------------------------- /ext/fmt-5.2.1/include/fmt/format-inl.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_FORMAT_INL_H_ 9 | #define FMT_FORMAT_INL_H_ 10 | 11 | #include "format.h" 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include // for std::ptrdiff_t 21 | #include // for std::memmove 22 | #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) 23 | # include 24 | #endif 25 | 26 | #if FMT_USE_WINDOWS_H 27 | # if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN) 28 | # define WIN32_LEAN_AND_MEAN 29 | # endif 30 | # if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) 31 | # include 32 | # else 33 | # define NOMINMAX 34 | # include 35 | # undef NOMINMAX 36 | # endif 37 | #endif 38 | 39 | #if FMT_EXCEPTIONS 40 | # define FMT_TRY try 41 | # define FMT_CATCH(x) catch (x) 42 | #else 43 | # define FMT_TRY if (true) 44 | # define FMT_CATCH(x) if (false) 45 | #endif 46 | 47 | #ifdef _MSC_VER 48 | # pragma warning(push) 49 | # pragma warning(disable: 4127) // conditional expression is constant 50 | # pragma warning(disable: 4702) // unreachable code 51 | // Disable deprecation warning for strerror. The latter is not called but 52 | // MSVC fails to detect it. 53 | # pragma warning(disable: 4996) 54 | #endif 55 | 56 | // Dummy implementations of strerror_r and strerror_s called if corresponding 57 | // system functions are not available. 58 | inline fmt::internal::null<> strerror_r(int, char *, ...) { 59 | return fmt::internal::null<>(); 60 | } 61 | inline fmt::internal::null<> strerror_s(char *, std::size_t, ...) { 62 | return fmt::internal::null<>(); 63 | } 64 | 65 | FMT_BEGIN_NAMESPACE 66 | 67 | namespace { 68 | 69 | #ifndef _MSC_VER 70 | # define FMT_SNPRINTF snprintf 71 | #else // _MSC_VER 72 | inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { 73 | va_list args; 74 | va_start(args, format); 75 | int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); 76 | va_end(args); 77 | return result; 78 | } 79 | # define FMT_SNPRINTF fmt_snprintf 80 | #endif // _MSC_VER 81 | 82 | #if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) 83 | # define FMT_SWPRINTF snwprintf 84 | #else 85 | # define FMT_SWPRINTF swprintf 86 | #endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) 87 | 88 | typedef void (*FormatFunc)(internal::buffer &, int, string_view); 89 | 90 | // Portable thread-safe version of strerror. 91 | // Sets buffer to point to a string describing the error code. 92 | // This can be either a pointer to a string stored in buffer, 93 | // or a pointer to some static immutable string. 94 | // Returns one of the following values: 95 | // 0 - success 96 | // ERANGE - buffer is not large enough to store the error message 97 | // other - failure 98 | // Buffer should be at least of size 1. 99 | int safe_strerror( 100 | int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { 101 | FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer"); 102 | 103 | class dispatcher { 104 | private: 105 | int error_code_; 106 | char *&buffer_; 107 | std::size_t buffer_size_; 108 | 109 | // A noop assignment operator to avoid bogus warnings. 110 | void operator=(const dispatcher &) {} 111 | 112 | // Handle the result of XSI-compliant version of strerror_r. 113 | int handle(int result) { 114 | // glibc versions before 2.13 return result in errno. 115 | return result == -1 ? errno : result; 116 | } 117 | 118 | // Handle the result of GNU-specific version of strerror_r. 119 | int handle(char *message) { 120 | // If the buffer is full then the message is probably truncated. 121 | if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) 122 | return ERANGE; 123 | buffer_ = message; 124 | return 0; 125 | } 126 | 127 | // Handle the case when strerror_r is not available. 128 | int handle(internal::null<>) { 129 | return fallback(strerror_s(buffer_, buffer_size_, error_code_)); 130 | } 131 | 132 | // Fallback to strerror_s when strerror_r is not available. 133 | int fallback(int result) { 134 | // If the buffer is full then the message is probably truncated. 135 | return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? 136 | ERANGE : result; 137 | } 138 | 139 | // Fallback to strerror if strerror_r and strerror_s are not available. 140 | int fallback(internal::null<>) { 141 | errno = 0; 142 | buffer_ = strerror(error_code_); 143 | return errno; 144 | } 145 | 146 | public: 147 | dispatcher(int err_code, char *&buf, std::size_t buf_size) 148 | : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} 149 | 150 | int run() { 151 | return handle(strerror_r(error_code_, buffer_, buffer_size_)); 152 | } 153 | }; 154 | return dispatcher(error_code, buffer, buffer_size).run(); 155 | } 156 | 157 | void format_error_code(internal::buffer &out, int error_code, 158 | string_view message) FMT_NOEXCEPT { 159 | // Report error code making sure that the output fits into 160 | // inline_buffer_size to avoid dynamic memory allocation and potential 161 | // bad_alloc. 162 | out.resize(0); 163 | static const char SEP[] = ": "; 164 | static const char ERROR_STR[] = "error "; 165 | // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. 166 | std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; 167 | typedef internal::int_traits::main_type main_type; 168 | main_type abs_value = static_cast(error_code); 169 | if (internal::is_negative(error_code)) { 170 | abs_value = 0 - abs_value; 171 | ++error_code_size; 172 | } 173 | error_code_size += internal::count_digits(abs_value); 174 | writer w(out); 175 | if (message.size() <= inline_buffer_size - error_code_size) { 176 | w.write(message); 177 | w.write(SEP); 178 | } 179 | w.write(ERROR_STR); 180 | w.write(error_code); 181 | assert(out.size() <= inline_buffer_size); 182 | } 183 | 184 | void report_error(FormatFunc func, int error_code, 185 | string_view message) FMT_NOEXCEPT { 186 | memory_buffer full_message; 187 | func(full_message, error_code, message); 188 | // Use Writer::data instead of Writer::c_str to avoid potential memory 189 | // allocation. 190 | std::fwrite(full_message.data(), full_message.size(), 1, stderr); 191 | std::fputc('\n', stderr); 192 | } 193 | } // namespace 194 | 195 | #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) 196 | class locale { 197 | private: 198 | std::locale locale_; 199 | 200 | public: 201 | explicit locale(std::locale loc = std::locale()) : locale_(loc) {} 202 | std::locale get() { return locale_; } 203 | }; 204 | 205 | FMT_FUNC size_t internal::count_code_points(u8string_view s) { 206 | const char8_t *data = s.data(); 207 | int num_code_points = 0; 208 | for (size_t i = 0, size = s.size(); i != size; ++i) { 209 | if ((data[i].value & 0xc0) != 0x80) 210 | ++num_code_points; 211 | } 212 | return num_code_points; 213 | } 214 | 215 | template 216 | FMT_FUNC Char internal::thousands_sep(locale_provider *lp) { 217 | std::locale loc = lp ? lp->locale().get() : std::locale(); 218 | return std::use_facet>(loc).thousands_sep(); 219 | } 220 | #else 221 | template 222 | FMT_FUNC Char internal::thousands_sep(locale_provider *lp) { 223 | return FMT_STATIC_THOUSANDS_SEPARATOR; 224 | } 225 | #endif 226 | 227 | FMT_FUNC void system_error::init( 228 | int err_code, string_view format_str, format_args args) { 229 | error_code_ = err_code; 230 | memory_buffer buffer; 231 | format_system_error(buffer, err_code, vformat(format_str, args)); 232 | std::runtime_error &base = *this; 233 | base = std::runtime_error(to_string(buffer)); 234 | } 235 | 236 | namespace internal { 237 | template 238 | int char_traits::format_float( 239 | char *buffer, std::size_t size, const char *format, int precision, T value) { 240 | return precision < 0 ? 241 | FMT_SNPRINTF(buffer, size, format, value) : 242 | FMT_SNPRINTF(buffer, size, format, precision, value); 243 | } 244 | 245 | template 246 | int char_traits::format_float( 247 | wchar_t *buffer, std::size_t size, const wchar_t *format, int precision, 248 | T value) { 249 | return precision < 0 ? 250 | FMT_SWPRINTF(buffer, size, format, value) : 251 | FMT_SWPRINTF(buffer, size, format, precision, value); 252 | } 253 | 254 | template 255 | const char basic_data::DIGITS[] = 256 | "0001020304050607080910111213141516171819" 257 | "2021222324252627282930313233343536373839" 258 | "4041424344454647484950515253545556575859" 259 | "6061626364656667686970717273747576777879" 260 | "8081828384858687888990919293949596979899"; 261 | 262 | #define FMT_POWERS_OF_10(factor) \ 263 | factor * 10, \ 264 | factor * 100, \ 265 | factor * 1000, \ 266 | factor * 10000, \ 267 | factor * 100000, \ 268 | factor * 1000000, \ 269 | factor * 10000000, \ 270 | factor * 100000000, \ 271 | factor * 1000000000 272 | 273 | template 274 | const uint32_t basic_data::POWERS_OF_10_32[] = { 275 | 1, FMT_POWERS_OF_10(1) 276 | }; 277 | 278 | template 279 | const uint32_t basic_data::ZERO_OR_POWERS_OF_10_32[] = { 280 | 0, FMT_POWERS_OF_10(1) 281 | }; 282 | 283 | template 284 | const uint64_t basic_data::ZERO_OR_POWERS_OF_10_64[] = { 285 | 0, 286 | FMT_POWERS_OF_10(1), 287 | FMT_POWERS_OF_10(1000000000ull), 288 | 10000000000000000000ull 289 | }; 290 | 291 | // Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340. 292 | // These are generated by support/compute-powers.py. 293 | template 294 | const uint64_t basic_data::POW10_SIGNIFICANDS[] = { 295 | 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76, 296 | 0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, 297 | 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c, 298 | 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5, 299 | 0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57, 300 | 0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7, 301 | 0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e, 302 | 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996, 303 | 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126, 304 | 0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053, 305 | 0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f, 306 | 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b, 307 | 0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06, 308 | 0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb, 309 | 0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000, 310 | 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984, 311 | 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068, 312 | 0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8, 313 | 0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758, 314 | 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85, 315 | 0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d, 316 | 0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25, 317 | 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2, 318 | 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a, 319 | 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410, 320 | 0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129, 321 | 0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85, 322 | 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841, 323 | 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b, 324 | }; 325 | 326 | // Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding 327 | // to significands above. 328 | template 329 | const int16_t basic_data::POW10_EXPONENTS[] = { 330 | -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, 331 | -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661, 332 | -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, 333 | -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, 334 | -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, 335 | 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, 336 | 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, 337 | 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066 338 | }; 339 | 340 | template const char basic_data::RESET_COLOR[] = "\x1b[0m"; 341 | template const wchar_t basic_data::WRESET_COLOR[] = L"\x1b[0m"; 342 | 343 | // A handmade floating-point number f * pow(2, e). 344 | class fp { 345 | private: 346 | typedef uint64_t significand_type; 347 | 348 | // All sizes are in bits. 349 | static FMT_CONSTEXPR_DECL const int char_size = 350 | std::numeric_limits::digits; 351 | // Subtract 1 to account for an implicit most significant bit in the 352 | // normalized form. 353 | static FMT_CONSTEXPR_DECL const int double_significand_size = 354 | std::numeric_limits::digits - 1; 355 | static FMT_CONSTEXPR_DECL const uint64_t implicit_bit = 356 | 1ull << double_significand_size; 357 | 358 | public: 359 | significand_type f; 360 | int e; 361 | 362 | static FMT_CONSTEXPR_DECL const int significand_size = 363 | sizeof(significand_type) * char_size; 364 | 365 | fp(): f(0), e(0) {} 366 | fp(uint64_t f, int e): f(f), e(e) {} 367 | 368 | // Constructs fp from an IEEE754 double. It is a template to prevent compile 369 | // errors on platforms where double is not IEEE754. 370 | template 371 | explicit fp(Double d) { 372 | // Assume double is in the format [sign][exponent][significand]. 373 | typedef std::numeric_limits limits; 374 | const int double_size = static_cast(sizeof(Double) * char_size); 375 | const int exponent_size = 376 | double_size - double_significand_size - 1; // -1 for sign 377 | const uint64_t significand_mask = implicit_bit - 1; 378 | const uint64_t exponent_mask = (~0ull >> 1) & ~significand_mask; 379 | const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1; 380 | auto u = bit_cast(d); 381 | auto biased_e = (u & exponent_mask) >> double_significand_size; 382 | f = u & significand_mask; 383 | if (biased_e != 0) 384 | f += implicit_bit; 385 | else 386 | biased_e = 1; // Subnormals use biased exponent 1 (min exponent). 387 | e = static_cast(biased_e - exponent_bias - double_significand_size); 388 | } 389 | 390 | // Normalizes the value converted from double and multiplied by (1 << SHIFT). 391 | template 392 | void normalize() { 393 | // Handle subnormals. 394 | auto shifted_implicit_bit = implicit_bit << SHIFT; 395 | while ((f & shifted_implicit_bit) == 0) { 396 | f <<= 1; 397 | --e; 398 | } 399 | // Subtract 1 to account for hidden bit. 400 | auto offset = significand_size - double_significand_size - SHIFT - 1; 401 | f <<= offset; 402 | e -= offset; 403 | } 404 | 405 | // Compute lower and upper boundaries (m^- and m^+ in the Grisu paper), where 406 | // a boundary is a value half way between the number and its predecessor 407 | // (lower) or successor (upper). The upper boundary is normalized and lower 408 | // has the same exponent but may be not normalized. 409 | void compute_boundaries(fp &lower, fp &upper) const { 410 | lower = f == implicit_bit ? 411 | fp((f << 2) - 1, e - 2) : fp((f << 1) - 1, e - 1); 412 | upper = fp((f << 1) + 1, e - 1); 413 | upper.normalize<1>(); // 1 is to account for the exponent shift above. 414 | lower.f <<= lower.e - upper.e; 415 | lower.e = upper.e; 416 | } 417 | }; 418 | 419 | // Returns an fp number representing x - y. Result may not be normalized. 420 | inline fp operator-(fp x, fp y) { 421 | FMT_ASSERT(x.f >= y.f && x.e == y.e, "invalid operands"); 422 | return fp(x.f - y.f, x.e); 423 | } 424 | 425 | // Computes an fp number r with r.f = x.f * y.f / pow(2, 64) rounded to nearest 426 | // with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be normalized. 427 | FMT_API fp operator*(fp x, fp y); 428 | 429 | // Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its 430 | // (binary) exponent satisfies min_exponent <= c_k.e <= min_exponent + 3. 431 | FMT_API fp get_cached_power(int min_exponent, int &pow10_exponent); 432 | 433 | FMT_FUNC fp operator*(fp x, fp y) { 434 | // Multiply 32-bit parts of significands. 435 | uint64_t mask = (1ULL << 32) - 1; 436 | uint64_t a = x.f >> 32, b = x.f & mask; 437 | uint64_t c = y.f >> 32, d = y.f & mask; 438 | uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d; 439 | // Compute mid 64-bit of result and round. 440 | uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31); 441 | return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64); 442 | } 443 | 444 | FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) { 445 | const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10) 446 | int index = static_cast(std::ceil( 447 | (min_exponent + fp::significand_size - 1) * one_over_log2_10)); 448 | // Decimal exponent of the first (smallest) cached power of 10. 449 | const int first_dec_exp = -348; 450 | // Difference between 2 consecutive decimal exponents in cached powers of 10. 451 | const int dec_exp_step = 8; 452 | index = (index - first_dec_exp - 1) / dec_exp_step + 1; 453 | pow10_exponent = first_dec_exp + index * dec_exp_step; 454 | return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]); 455 | } 456 | 457 | // Generates output using Grisu2 digit-gen algorithm. 458 | FMT_FUNC void grisu2_gen_digits( 459 | const fp &scaled_value, const fp &scaled_upper, uint64_t delta, 460 | char *buffer, size_t &size, int &dec_exp) { 461 | internal::fp one(1ull << -scaled_upper.e, scaled_upper.e); 462 | // hi (p1 in Grisu) contains the most significant digits of scaled_upper. 463 | // hi = floor(scaled_upper / one). 464 | uint32_t hi = static_cast(scaled_upper.f >> -one.e); 465 | // lo (p2 in Grisu) contains the least significants digits of scaled_upper. 466 | // lo = scaled_upper mod 1. 467 | uint64_t lo = scaled_upper.f & (one.f - 1); 468 | size = 0; 469 | auto exp = count_digits(hi); // kappa in Grisu. 470 | while (exp > 0) { 471 | uint32_t digit = 0; 472 | // This optimization by miloyip reduces the number of integer divisions by 473 | // one per iteration. 474 | switch (exp) { 475 | case 10: digit = hi / 1000000000; hi %= 1000000000; break; 476 | case 9: digit = hi / 100000000; hi %= 100000000; break; 477 | case 8: digit = hi / 10000000; hi %= 10000000; break; 478 | case 7: digit = hi / 1000000; hi %= 1000000; break; 479 | case 6: digit = hi / 100000; hi %= 100000; break; 480 | case 5: digit = hi / 10000; hi %= 10000; break; 481 | case 4: digit = hi / 1000; hi %= 1000; break; 482 | case 3: digit = hi / 100; hi %= 100; break; 483 | case 2: digit = hi / 10; hi %= 10; break; 484 | case 1: digit = hi; hi = 0; break; 485 | default: 486 | FMT_ASSERT(false, "invalid number of digits"); 487 | } 488 | if (digit != 0 || size != 0) 489 | buffer[size++] = static_cast('0' + digit); 490 | --exp; 491 | uint64_t remainder = (static_cast(hi) << -one.e) + lo; 492 | if (remainder <= delta) { 493 | dec_exp += exp; 494 | // TODO: use scaled_value 495 | (void)scaled_value; 496 | return; 497 | } 498 | } 499 | for (;;) { 500 | lo *= 10; 501 | delta *= 10; 502 | char digit = static_cast(lo >> -one.e); 503 | if (digit != 0 || size != 0) 504 | buffer[size++] = static_cast('0' + digit); 505 | lo &= one.f - 1; 506 | --exp; 507 | if (lo < delta) { 508 | dec_exp += exp; 509 | return; 510 | } 511 | } 512 | } 513 | 514 | FMT_FUNC void grisu2_format_positive(double value, char *buffer, size_t &size, 515 | int &dec_exp) { 516 | FMT_ASSERT(value > 0, "value is nonpositive"); 517 | fp fp_value(value); 518 | fp lower, upper; // w^- and w^+ in the Grisu paper. 519 | fp_value.compute_boundaries(lower, upper); 520 | // Find a cached power of 10 close to 1 / upper. 521 | const int min_exp = -60; // alpha in Grisu. 522 | auto dec_pow = get_cached_power( // \tilde{c}_{-k} in Grisu. 523 | min_exp - (upper.e + fp::significand_size), dec_exp); 524 | dec_exp = -dec_exp; 525 | fp_value.normalize(); 526 | fp scaled_value = fp_value * dec_pow; 527 | fp scaled_lower = lower * dec_pow; // \tilde{M}^- in Grisu. 528 | fp scaled_upper = upper * dec_pow; // \tilde{M}^+ in Grisu. 529 | ++scaled_lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}. 530 | --scaled_upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}. 531 | uint64_t delta = scaled_upper.f - scaled_lower.f; 532 | grisu2_gen_digits(scaled_value, scaled_upper, delta, buffer, size, dec_exp); 533 | } 534 | 535 | FMT_FUNC void round(char *buffer, size_t &size, int &exp, 536 | int digits_to_remove) { 537 | size -= to_unsigned(digits_to_remove); 538 | exp += digits_to_remove; 539 | int digit = buffer[size] - '0'; 540 | // TODO: proper rounding and carry 541 | if (digit > 5 || (digit == 5 && (digits_to_remove > 1 || 542 | (buffer[size - 1] - '0') % 2) != 0)) { 543 | ++buffer[size - 1]; 544 | } 545 | } 546 | 547 | // Writes the exponent exp in the form "[+-]d{1,3}" to buffer. 548 | FMT_FUNC char *write_exponent(char *buffer, int exp) { 549 | FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range"); 550 | if (exp < 0) { 551 | *buffer++ = '-'; 552 | exp = -exp; 553 | } else { 554 | *buffer++ = '+'; 555 | } 556 | if (exp >= 100) { 557 | *buffer++ = static_cast('0' + exp / 100); 558 | exp %= 100; 559 | const char *d = data::DIGITS + exp * 2; 560 | *buffer++ = d[0]; 561 | *buffer++ = d[1]; 562 | } else { 563 | const char *d = data::DIGITS + exp * 2; 564 | *buffer++ = d[0]; 565 | *buffer++ = d[1]; 566 | } 567 | return buffer; 568 | } 569 | 570 | FMT_FUNC void format_exp_notation( 571 | char *buffer, size_t &size, int exp, int precision, bool upper) { 572 | // Insert a decimal point after the first digit and add an exponent. 573 | std::memmove(buffer + 2, buffer + 1, size - 1); 574 | buffer[1] = '.'; 575 | exp += static_cast(size) - 1; 576 | int num_digits = precision - static_cast(size) + 1; 577 | if (num_digits > 0) { 578 | std::uninitialized_fill_n(buffer + size + 1, num_digits, '0'); 579 | size += to_unsigned(num_digits); 580 | } else if (num_digits < 0) { 581 | round(buffer, size, exp, -num_digits); 582 | } 583 | char *p = buffer + size + 1; 584 | *p++ = upper ? 'E' : 'e'; 585 | size = to_unsigned(write_exponent(p, exp) - buffer); 586 | } 587 | 588 | // Prettifies the output of the Grisu2 algorithm. 589 | // The number is given as v = buffer * 10^exp. 590 | FMT_FUNC void grisu2_prettify(char *buffer, size_t &size, int exp, 591 | int precision, bool upper) { 592 | // pow(10, full_exp - 1) <= v <= pow(10, full_exp). 593 | int int_size = static_cast(size); 594 | int full_exp = int_size + exp; 595 | const int exp_threshold = 21; 596 | if (int_size <= full_exp && full_exp <= exp_threshold) { 597 | // 1234e7 -> 12340000000[.0+] 598 | std::uninitialized_fill_n(buffer + int_size, full_exp - int_size, '0'); 599 | char *p = buffer + full_exp; 600 | if (precision > 0) { 601 | *p++ = '.'; 602 | std::uninitialized_fill_n(p, precision, '0'); 603 | p += precision; 604 | } 605 | size = to_unsigned(p - buffer); 606 | } else if (0 < full_exp && full_exp <= exp_threshold) { 607 | // 1234e-2 -> 12.34[0+] 608 | int fractional_size = -exp; 609 | std::memmove(buffer + full_exp + 1, buffer + full_exp, 610 | to_unsigned(fractional_size)); 611 | buffer[full_exp] = '.'; 612 | int num_zeros = precision - fractional_size; 613 | if (num_zeros > 0) { 614 | std::uninitialized_fill_n(buffer + size + 1, num_zeros, '0'); 615 | size += to_unsigned(num_zeros); 616 | } 617 | ++size; 618 | } else if (-6 < full_exp && full_exp <= 0) { 619 | // 1234e-6 -> 0.001234 620 | int offset = 2 - full_exp; 621 | std::memmove(buffer + offset, buffer, size); 622 | buffer[0] = '0'; 623 | buffer[1] = '.'; 624 | std::uninitialized_fill_n(buffer + 2, -full_exp, '0'); 625 | size = to_unsigned(int_size + offset); 626 | } else { 627 | format_exp_notation(buffer, size, exp, precision, upper); 628 | } 629 | } 630 | 631 | #if FMT_CLANG_VERSION 632 | # define FMT_FALLTHROUGH [[clang::fallthrough]]; 633 | #elif FMT_GCC_VERSION >= 700 634 | # define FMT_FALLTHROUGH [[gnu::fallthrough]]; 635 | #else 636 | # define FMT_FALLTHROUGH 637 | #endif 638 | 639 | // Formats a nonnegative value using Grisu2 algorithm. Grisu2 doesn't give any 640 | // guarantees on the shortness of the result. 641 | FMT_FUNC void grisu2_format(double value, char *buffer, size_t &size, char type, 642 | int precision, bool write_decimal_point) { 643 | FMT_ASSERT(value >= 0, "value is negative"); 644 | int dec_exp = 0; // K in Grisu. 645 | if (value > 0) { 646 | grisu2_format_positive(value, buffer, size, dec_exp); 647 | } else { 648 | *buffer = '0'; 649 | size = 1; 650 | } 651 | const int default_precision = 6; 652 | if (precision < 0) 653 | precision = default_precision; 654 | bool upper = false; 655 | switch (type) { 656 | case 'G': 657 | upper = true; 658 | FMT_FALLTHROUGH 659 | case '\0': case 'g': { 660 | int digits_to_remove = static_cast(size) - precision; 661 | if (digits_to_remove > 0) { 662 | round(buffer, size, dec_exp, digits_to_remove); 663 | // Remove trailing zeros. 664 | while (size > 0 && buffer[size - 1] == '0') { 665 | --size; 666 | ++dec_exp; 667 | } 668 | } 669 | precision = 0; 670 | break; 671 | } 672 | case 'F': 673 | upper = true; 674 | FMT_FALLTHROUGH 675 | case 'f': { 676 | int digits_to_remove = -dec_exp - precision; 677 | if (digits_to_remove > 0) { 678 | if (digits_to_remove >= static_cast(size)) 679 | digits_to_remove = static_cast(size) - 1; 680 | round(buffer, size, dec_exp, digits_to_remove); 681 | } 682 | break; 683 | } 684 | case 'e': case 'E': 685 | format_exp_notation(buffer, size, dec_exp, precision, type == 'E'); 686 | return; 687 | } 688 | if (write_decimal_point && precision < 1) 689 | precision = 1; 690 | grisu2_prettify(buffer, size, dec_exp, precision, upper); 691 | } 692 | } // namespace internal 693 | 694 | #if FMT_USE_WINDOWS_H 695 | 696 | FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) { 697 | static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; 698 | if (s.size() > INT_MAX) 699 | FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG)); 700 | int s_size = static_cast(s.size()); 701 | if (s_size == 0) { 702 | // MultiByteToWideChar does not support zero length, handle separately. 703 | buffer_.resize(1); 704 | buffer_[0] = 0; 705 | return; 706 | } 707 | 708 | int length = MultiByteToWideChar( 709 | CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0); 710 | if (length == 0) 711 | FMT_THROW(windows_error(GetLastError(), ERROR_MSG)); 712 | buffer_.resize(length + 1); 713 | length = MultiByteToWideChar( 714 | CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length); 715 | if (length == 0) 716 | FMT_THROW(windows_error(GetLastError(), ERROR_MSG)); 717 | buffer_[length] = 0; 718 | } 719 | 720 | FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) { 721 | if (int error_code = convert(s)) { 722 | FMT_THROW(windows_error(error_code, 723 | "cannot convert string from UTF-16 to UTF-8")); 724 | } 725 | } 726 | 727 | FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) { 728 | if (s.size() > INT_MAX) 729 | return ERROR_INVALID_PARAMETER; 730 | int s_size = static_cast(s.size()); 731 | if (s_size == 0) { 732 | // WideCharToMultiByte does not support zero length, handle separately. 733 | buffer_.resize(1); 734 | buffer_[0] = 0; 735 | return 0; 736 | } 737 | 738 | int length = WideCharToMultiByte( 739 | CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL); 740 | if (length == 0) 741 | return GetLastError(); 742 | buffer_.resize(length + 1); 743 | length = WideCharToMultiByte( 744 | CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL); 745 | if (length == 0) 746 | return GetLastError(); 747 | buffer_[length] = 0; 748 | return 0; 749 | } 750 | 751 | FMT_FUNC void windows_error::init( 752 | int err_code, string_view format_str, format_args args) { 753 | error_code_ = err_code; 754 | memory_buffer buffer; 755 | internal::format_windows_error(buffer, err_code, vformat(format_str, args)); 756 | std::runtime_error &base = *this; 757 | base = std::runtime_error(to_string(buffer)); 758 | } 759 | 760 | FMT_FUNC void internal::format_windows_error( 761 | internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT { 762 | FMT_TRY { 763 | wmemory_buffer buf; 764 | buf.resize(inline_buffer_size); 765 | for (;;) { 766 | wchar_t *system_message = &buf[0]; 767 | int result = FormatMessageW( 768 | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 769 | FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 770 | system_message, static_cast(buf.size()), FMT_NULL); 771 | if (result != 0) { 772 | utf16_to_utf8 utf8_message; 773 | if (utf8_message.convert(system_message) == ERROR_SUCCESS) { 774 | writer w(out); 775 | w.write(message); 776 | w.write(": "); 777 | w.write(utf8_message); 778 | return; 779 | } 780 | break; 781 | } 782 | if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 783 | break; // Can't get error message, report error code instead. 784 | buf.resize(buf.size() * 2); 785 | } 786 | } FMT_CATCH(...) {} 787 | format_error_code(out, error_code, message); 788 | } 789 | 790 | #endif // FMT_USE_WINDOWS_H 791 | 792 | FMT_FUNC void format_system_error( 793 | internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT { 794 | FMT_TRY { 795 | memory_buffer buf; 796 | buf.resize(inline_buffer_size); 797 | for (;;) { 798 | char *system_message = &buf[0]; 799 | int result = safe_strerror(error_code, system_message, buf.size()); 800 | if (result == 0) { 801 | writer w(out); 802 | w.write(message); 803 | w.write(": "); 804 | w.write(system_message); 805 | return; 806 | } 807 | if (result != ERANGE) 808 | break; // Can't get error message, report error code instead. 809 | buf.resize(buf.size() * 2); 810 | } 811 | } FMT_CATCH(...) {} 812 | format_error_code(out, error_code, message); 813 | } 814 | 815 | template 816 | void basic_fixed_buffer::grow(std::size_t) { 817 | FMT_THROW(std::runtime_error("buffer overflow")); 818 | } 819 | 820 | FMT_FUNC void internal::error_handler::on_error(const char *message) { 821 | FMT_THROW(format_error(message)); 822 | } 823 | 824 | FMT_FUNC void report_system_error( 825 | int error_code, fmt::string_view message) FMT_NOEXCEPT { 826 | report_error(format_system_error, error_code, message); 827 | } 828 | 829 | #if FMT_USE_WINDOWS_H 830 | FMT_FUNC void report_windows_error( 831 | int error_code, fmt::string_view message) FMT_NOEXCEPT { 832 | report_error(internal::format_windows_error, error_code, message); 833 | } 834 | #endif 835 | 836 | FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) { 837 | memory_buffer buffer; 838 | vformat_to(buffer, format_str, args); 839 | std::fwrite(buffer.data(), 1, buffer.size(), f); 840 | } 841 | 842 | FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) { 843 | wmemory_buffer buffer; 844 | vformat_to(buffer, format_str, args); 845 | std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f); 846 | } 847 | 848 | FMT_FUNC void vprint(string_view format_str, format_args args) { 849 | vprint(stdout, format_str, args); 850 | } 851 | 852 | FMT_FUNC void vprint(wstring_view format_str, wformat_args args) { 853 | vprint(stdout, format_str, args); 854 | } 855 | 856 | #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) 857 | FMT_FUNC locale locale_provider::locale() { return fmt::locale(); } 858 | #endif 859 | 860 | FMT_END_NAMESPACE 861 | 862 | #ifdef _MSC_VER 863 | # pragma warning(pop) 864 | #endif 865 | 866 | #endif // FMT_FORMAT_INL_H_ 867 | -------------------------------------------------------------------------------- /ext/fmt-5.2.1/include/fmt/ostream.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - std::ostream support 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_OSTREAM_H_ 9 | #define FMT_OSTREAM_H_ 10 | 11 | #include "format.h" 12 | #include 13 | 14 | FMT_BEGIN_NAMESPACE 15 | namespace internal { 16 | 17 | template 18 | class formatbuf : public std::basic_streambuf { 19 | private: 20 | typedef typename std::basic_streambuf::int_type int_type; 21 | typedef typename std::basic_streambuf::traits_type traits_type; 22 | 23 | basic_buffer &buffer_; 24 | 25 | public: 26 | formatbuf(basic_buffer &buffer) : buffer_(buffer) {} 27 | 28 | protected: 29 | // The put-area is actually always empty. This makes the implementation 30 | // simpler and has the advantage that the streambuf and the buffer are always 31 | // in sync and sputc never writes into uninitialized memory. The obvious 32 | // disadvantage is that each call to sputc always results in a (virtual) call 33 | // to overflow. There is no disadvantage here for sputn since this always 34 | // results in a call to xsputn. 35 | 36 | int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE { 37 | if (!traits_type::eq_int_type(ch, traits_type::eof())) 38 | buffer_.push_back(static_cast(ch)); 39 | return ch; 40 | } 41 | 42 | std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE { 43 | buffer_.append(s, s + count); 44 | return count; 45 | } 46 | }; 47 | 48 | template 49 | struct test_stream : std::basic_ostream { 50 | private: 51 | struct null; 52 | // Hide all operator<< from std::basic_ostream. 53 | void operator<<(null); 54 | }; 55 | 56 | // Checks if T has a user-defined operator<< (e.g. not a member of std::ostream). 57 | template 58 | class is_streamable { 59 | private: 60 | template 61 | static decltype( 62 | internal::declval&>() 63 | << internal::declval(), std::true_type()) test(int); 64 | 65 | template 66 | static std::false_type test(...); 67 | 68 | typedef decltype(test(0)) result; 69 | 70 | public: 71 | static const bool value = result::value; 72 | }; 73 | 74 | // Write the content of buf to os. 75 | template 76 | void write(std::basic_ostream &os, basic_buffer &buf) { 77 | const Char *data = buf.data(); 78 | typedef std::make_unsigned::type UnsignedStreamSize; 79 | UnsignedStreamSize size = buf.size(); 80 | UnsignedStreamSize max_size = 81 | internal::to_unsigned((std::numeric_limits::max)()); 82 | do { 83 | UnsignedStreamSize n = size <= max_size ? size : max_size; 84 | os.write(data, static_cast(n)); 85 | data += n; 86 | size -= n; 87 | } while (size != 0); 88 | } 89 | 90 | template 91 | void format_value(basic_buffer &buffer, const T &value) { 92 | internal::formatbuf format_buf(buffer); 93 | std::basic_ostream output(&format_buf); 94 | output.exceptions(std::ios_base::failbit | std::ios_base::badbit); 95 | output << value; 96 | buffer.resize(buffer.size()); 97 | } 98 | } // namespace internal 99 | 100 | // Disable conversion to int if T has an overloaded operator<< which is a free 101 | // function (not a member of std::ostream). 102 | template 103 | struct convert_to_int { 104 | static const bool value = 105 | convert_to_int::value && 106 | !internal::is_streamable::value; 107 | }; 108 | 109 | // Formats an object of type T that has an overloaded ostream operator<<. 110 | template 111 | struct formatter::value && 114 | !internal::format_type< 115 | typename buffer_context::type, T>::value>::type> 116 | : formatter, Char> { 117 | 118 | template 119 | auto format(const T &value, Context &ctx) -> decltype(ctx.out()) { 120 | basic_memory_buffer buffer; 121 | internal::format_value(buffer, value); 122 | basic_string_view str(buffer.data(), buffer.size()); 123 | return formatter, Char>::format(str, ctx); 124 | } 125 | }; 126 | 127 | template 128 | inline void vprint(std::basic_ostream &os, 129 | basic_string_view format_str, 130 | basic_format_args::type> args) { 131 | basic_memory_buffer buffer; 132 | vformat_to(buffer, format_str, args); 133 | internal::write(os, buffer); 134 | } 135 | /** 136 | \rst 137 | Prints formatted data to the stream *os*. 138 | 139 | **Example**:: 140 | 141 | fmt::print(cerr, "Don't {}!", "panic"); 142 | \endrst 143 | */ 144 | template 145 | inline void print(std::ostream &os, string_view format_str, 146 | const Args & ... args) { 147 | vprint(os, format_str, make_format_args(args...)); 148 | } 149 | 150 | template 151 | inline void print(std::wostream &os, wstring_view format_str, 152 | const Args & ... args) { 153 | vprint(os, format_str, make_format_args(args...)); 154 | } 155 | FMT_END_NAMESPACE 156 | 157 | #endif // FMT_OSTREAM_H_ 158 | -------------------------------------------------------------------------------- /ext/fmt-5.2.1/include/fmt/posix.h: -------------------------------------------------------------------------------- 1 | // A C++ interface to POSIX functions. 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_POSIX_H_ 9 | #define FMT_POSIX_H_ 10 | 11 | #if defined(__MINGW32__) || defined(__CYGWIN__) 12 | // Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/. 13 | # undef __STRICT_ANSI__ 14 | #endif 15 | 16 | #include 17 | #include // for O_RDONLY 18 | #include // for locale_t 19 | #include 20 | #include // for strtod_l 21 | 22 | #include 23 | 24 | #if defined __APPLE__ || defined(__FreeBSD__) 25 | # include // for LC_NUMERIC_MASK on OS X 26 | #endif 27 | 28 | #include "format.h" 29 | 30 | #ifndef FMT_POSIX 31 | # if defined(_WIN32) && !defined(__MINGW32__) 32 | // Fix warnings about deprecated symbols. 33 | # define FMT_POSIX(call) _##call 34 | # else 35 | # define FMT_POSIX(call) call 36 | # endif 37 | #endif 38 | 39 | // Calls to system functions are wrapped in FMT_SYSTEM for testability. 40 | #ifdef FMT_SYSTEM 41 | # define FMT_POSIX_CALL(call) FMT_SYSTEM(call) 42 | #else 43 | # define FMT_SYSTEM(call) call 44 | # ifdef _WIN32 45 | // Fix warnings about deprecated symbols. 46 | # define FMT_POSIX_CALL(call) ::_##call 47 | # else 48 | # define FMT_POSIX_CALL(call) ::call 49 | # endif 50 | #endif 51 | 52 | // Retries the expression while it evaluates to error_result and errno 53 | // equals to EINTR. 54 | #ifndef _WIN32 55 | # define FMT_RETRY_VAL(result, expression, error_result) \ 56 | do { \ 57 | result = (expression); \ 58 | } while (result == error_result && errno == EINTR) 59 | #else 60 | # define FMT_RETRY_VAL(result, expression, error_result) result = (expression) 61 | #endif 62 | 63 | #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) 64 | 65 | FMT_BEGIN_NAMESPACE 66 | 67 | /** 68 | \rst 69 | A reference to a null-terminated string. It can be constructed from a C 70 | string or ``std::string``. 71 | 72 | You can use one of the following typedefs for common character types: 73 | 74 | +---------------+-----------------------------+ 75 | | Type | Definition | 76 | +===============+=============================+ 77 | | cstring_view | basic_cstring_view | 78 | +---------------+-----------------------------+ 79 | | wcstring_view | basic_cstring_view | 80 | +---------------+-----------------------------+ 81 | 82 | This class is most useful as a parameter type to allow passing 83 | different types of strings to a function, for example:: 84 | 85 | template 86 | std::string format(cstring_view format_str, const Args & ... args); 87 | 88 | format("{}", 42); 89 | format(std::string("{}"), 42); 90 | \endrst 91 | */ 92 | template 93 | class basic_cstring_view { 94 | private: 95 | const Char *data_; 96 | 97 | public: 98 | /** Constructs a string reference object from a C string. */ 99 | basic_cstring_view(const Char *s) : data_(s) {} 100 | 101 | /** 102 | \rst 103 | Constructs a string reference from an ``std::string`` object. 104 | \endrst 105 | */ 106 | basic_cstring_view(const std::basic_string &s) : data_(s.c_str()) {} 107 | 108 | /** Returns the pointer to a C string. */ 109 | const Char *c_str() const { return data_; } 110 | }; 111 | 112 | typedef basic_cstring_view cstring_view; 113 | typedef basic_cstring_view wcstring_view; 114 | 115 | // An error code. 116 | class error_code { 117 | private: 118 | int value_; 119 | 120 | public: 121 | explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {} 122 | 123 | int get() const FMT_NOEXCEPT { return value_; } 124 | }; 125 | 126 | // A buffered file. 127 | class buffered_file { 128 | private: 129 | FILE *file_; 130 | 131 | friend class file; 132 | 133 | explicit buffered_file(FILE *f) : file_(f) {} 134 | 135 | public: 136 | // Constructs a buffered_file object which doesn't represent any file. 137 | buffered_file() FMT_NOEXCEPT : file_(FMT_NULL) {} 138 | 139 | // Destroys the object closing the file it represents if any. 140 | FMT_API ~buffered_file() FMT_DTOR_NOEXCEPT; 141 | 142 | private: 143 | buffered_file(const buffered_file &) = delete; 144 | void operator=(const buffered_file &) = delete; 145 | 146 | 147 | public: 148 | buffered_file(buffered_file &&other) FMT_NOEXCEPT : file_(other.file_) { 149 | other.file_ = FMT_NULL; 150 | } 151 | 152 | buffered_file& operator=(buffered_file &&other) { 153 | close(); 154 | file_ = other.file_; 155 | other.file_ = FMT_NULL; 156 | return *this; 157 | } 158 | 159 | // Opens a file. 160 | FMT_API buffered_file(cstring_view filename, cstring_view mode); 161 | 162 | // Closes the file. 163 | FMT_API void close(); 164 | 165 | // Returns the pointer to a FILE object representing this file. 166 | FILE *get() const FMT_NOEXCEPT { return file_; } 167 | 168 | // We place parentheses around fileno to workaround a bug in some versions 169 | // of MinGW that define fileno as a macro. 170 | FMT_API int (fileno)() const; 171 | 172 | void vprint(string_view format_str, format_args args) { 173 | fmt::vprint(file_, format_str, args); 174 | } 175 | 176 | template 177 | inline void print(string_view format_str, const Args & ... args) { 178 | vprint(format_str, make_format_args(args...)); 179 | } 180 | }; 181 | 182 | // A file. Closed file is represented by a file object with descriptor -1. 183 | // Methods that are not declared with FMT_NOEXCEPT may throw 184 | // fmt::system_error in case of failure. Note that some errors such as 185 | // closing the file multiple times will cause a crash on Windows rather 186 | // than an exception. You can get standard behavior by overriding the 187 | // invalid parameter handler with _set_invalid_parameter_handler. 188 | class file { 189 | private: 190 | int fd_; // File descriptor. 191 | 192 | // Constructs a file object with a given descriptor. 193 | explicit file(int fd) : fd_(fd) {} 194 | 195 | public: 196 | // Possible values for the oflag argument to the constructor. 197 | enum { 198 | RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. 199 | WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. 200 | RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing. 201 | }; 202 | 203 | // Constructs a file object which doesn't represent any file. 204 | file() FMT_NOEXCEPT : fd_(-1) {} 205 | 206 | // Opens a file and constructs a file object representing this file. 207 | FMT_API file(cstring_view path, int oflag); 208 | 209 | private: 210 | file(const file &) = delete; 211 | void operator=(const file &) = delete; 212 | 213 | public: 214 | file(file &&other) FMT_NOEXCEPT : fd_(other.fd_) { 215 | other.fd_ = -1; 216 | } 217 | 218 | file& operator=(file &&other) { 219 | close(); 220 | fd_ = other.fd_; 221 | other.fd_ = -1; 222 | return *this; 223 | } 224 | 225 | // Destroys the object closing the file it represents if any. 226 | FMT_API ~file() FMT_DTOR_NOEXCEPT; 227 | 228 | // Returns the file descriptor. 229 | int descriptor() const FMT_NOEXCEPT { return fd_; } 230 | 231 | // Closes the file. 232 | FMT_API void close(); 233 | 234 | // Returns the file size. The size has signed type for consistency with 235 | // stat::st_size. 236 | FMT_API long long size() const; 237 | 238 | // Attempts to read count bytes from the file into the specified buffer. 239 | FMT_API std::size_t read(void *buffer, std::size_t count); 240 | 241 | // Attempts to write count bytes from the specified buffer to the file. 242 | FMT_API std::size_t write(const void *buffer, std::size_t count); 243 | 244 | // Duplicates a file descriptor with the dup function and returns 245 | // the duplicate as a file object. 246 | FMT_API static file dup(int fd); 247 | 248 | // Makes fd be the copy of this file descriptor, closing fd first if 249 | // necessary. 250 | FMT_API void dup2(int fd); 251 | 252 | // Makes fd be the copy of this file descriptor, closing fd first if 253 | // necessary. 254 | FMT_API void dup2(int fd, error_code &ec) FMT_NOEXCEPT; 255 | 256 | // Creates a pipe setting up read_end and write_end file objects for reading 257 | // and writing respectively. 258 | FMT_API static void pipe(file &read_end, file &write_end); 259 | 260 | // Creates a buffered_file object associated with this file and detaches 261 | // this file object from the file. 262 | FMT_API buffered_file fdopen(const char *mode); 263 | }; 264 | 265 | // Returns the memory page size. 266 | long getpagesize(); 267 | 268 | #if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \ 269 | !defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__) && \ 270 | !defined(__NEWLIB_H__) 271 | # define FMT_LOCALE 272 | #endif 273 | 274 | #ifdef FMT_LOCALE 275 | // A "C" numeric locale. 276 | class Locale { 277 | private: 278 | # ifdef _MSC_VER 279 | typedef _locale_t locale_t; 280 | 281 | enum { LC_NUMERIC_MASK = LC_NUMERIC }; 282 | 283 | static locale_t newlocale(int category_mask, const char *locale, locale_t) { 284 | return _create_locale(category_mask, locale); 285 | } 286 | 287 | static void freelocale(locale_t locale) { 288 | _free_locale(locale); 289 | } 290 | 291 | static double strtod_l(const char *nptr, char **endptr, _locale_t locale) { 292 | return _strtod_l(nptr, endptr, locale); 293 | } 294 | # endif 295 | 296 | locale_t locale_; 297 | 298 | Locale(const Locale &) = delete; 299 | void operator=(const Locale &) = delete; 300 | 301 | public: 302 | typedef locale_t Type; 303 | 304 | Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) { 305 | if (!locale_) 306 | FMT_THROW(system_error(errno, "cannot create locale")); 307 | } 308 | ~Locale() { freelocale(locale_); } 309 | 310 | Type get() const { return locale_; } 311 | 312 | // Converts string to floating-point number and advances str past the end 313 | // of the parsed input. 314 | double strtod(const char *&str) const { 315 | char *end = FMT_NULL; 316 | double result = strtod_l(str, &end, locale_); 317 | str = end; 318 | return result; 319 | } 320 | }; 321 | #endif // FMT_LOCALE 322 | FMT_END_NAMESPACE 323 | 324 | #endif // FMT_POSIX_H_ 325 | -------------------------------------------------------------------------------- /ext/fmt-5.2.1/include/fmt/printf.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_PRINTF_H_ 9 | #define FMT_PRINTF_H_ 10 | 11 | #include // std::fill_n 12 | #include // std::numeric_limits 13 | 14 | #include "ostream.h" 15 | 16 | FMT_BEGIN_NAMESPACE 17 | namespace internal { 18 | 19 | // Checks if a value fits in int - used to avoid warnings about comparing 20 | // signed and unsigned integers. 21 | template 22 | struct int_checker { 23 | template 24 | static bool fits_in_int(T value) { 25 | unsigned max = std::numeric_limits::max(); 26 | return value <= max; 27 | } 28 | static bool fits_in_int(bool) { return true; } 29 | }; 30 | 31 | template <> 32 | struct int_checker { 33 | template 34 | static bool fits_in_int(T value) { 35 | return value >= std::numeric_limits::min() && 36 | value <= std::numeric_limits::max(); 37 | } 38 | static bool fits_in_int(int) { return true; } 39 | }; 40 | 41 | class printf_precision_handler: public function { 42 | public: 43 | template 44 | typename std::enable_if::value, int>::type 45 | operator()(T value) { 46 | if (!int_checker::is_signed>::fits_in_int(value)) 47 | FMT_THROW(format_error("number is too big")); 48 | return static_cast(value); 49 | } 50 | 51 | template 52 | typename std::enable_if::value, int>::type operator()(T) { 53 | FMT_THROW(format_error("precision is not integer")); 54 | return 0; 55 | } 56 | }; 57 | 58 | // An argument visitor that returns true iff arg is a zero integer. 59 | class is_zero_int: public function { 60 | public: 61 | template 62 | typename std::enable_if::value, bool>::type 63 | operator()(T value) { return value == 0; } 64 | 65 | template 66 | typename std::enable_if::value, bool>::type 67 | operator()(T) { return false; } 68 | }; 69 | 70 | template 71 | struct make_unsigned_or_bool : std::make_unsigned {}; 72 | 73 | template <> 74 | struct make_unsigned_or_bool { 75 | typedef bool type; 76 | }; 77 | 78 | template 79 | class arg_converter: public function { 80 | private: 81 | typedef typename Context::char_type Char; 82 | 83 | basic_format_arg &arg_; 84 | typename Context::char_type type_; 85 | 86 | public: 87 | arg_converter(basic_format_arg &arg, Char type) 88 | : arg_(arg), type_(type) {} 89 | 90 | void operator()(bool value) { 91 | if (type_ != 's') 92 | operator()(value); 93 | } 94 | 95 | template 96 | typename std::enable_if::value>::type 97 | operator()(U value) { 98 | bool is_signed = type_ == 'd' || type_ == 'i'; 99 | typedef typename std::conditional< 100 | std::is_same::value, U, T>::type TargetType; 101 | if (const_check(sizeof(TargetType) <= sizeof(int))) { 102 | // Extra casts are used to silence warnings. 103 | if (is_signed) { 104 | arg_ = internal::make_arg( 105 | static_cast(static_cast(value))); 106 | } else { 107 | typedef typename make_unsigned_or_bool::type Unsigned; 108 | arg_ = internal::make_arg( 109 | static_cast(static_cast(value))); 110 | } 111 | } else { 112 | if (is_signed) { 113 | // glibc's printf doesn't sign extend arguments of smaller types: 114 | // std::printf("%lld", -42); // prints "4294967254" 115 | // but we don't have to do the same because it's a UB. 116 | arg_ = internal::make_arg(static_cast(value)); 117 | } else { 118 | arg_ = internal::make_arg( 119 | static_cast::type>(value)); 120 | } 121 | } 122 | } 123 | 124 | template 125 | typename std::enable_if::value>::type operator()(U) { 126 | // No coversion needed for non-integral types. 127 | } 128 | }; 129 | 130 | // Converts an integer argument to T for printf, if T is an integral type. 131 | // If T is void, the argument is converted to corresponding signed or unsigned 132 | // type depending on the type specifier: 'd' and 'i' - signed, other - 133 | // unsigned). 134 | template 135 | void convert_arg(basic_format_arg &arg, Char type) { 136 | fmt::visit(arg_converter(arg, type), arg); 137 | } 138 | 139 | // Converts an integer argument to char for printf. 140 | template 141 | class char_converter: public function { 142 | private: 143 | basic_format_arg &arg_; 144 | 145 | public: 146 | explicit char_converter(basic_format_arg &arg) : arg_(arg) {} 147 | 148 | template 149 | typename std::enable_if::value>::type 150 | operator()(T value) { 151 | typedef typename Context::char_type Char; 152 | arg_ = internal::make_arg(static_cast(value)); 153 | } 154 | 155 | template 156 | typename std::enable_if::value>::type operator()(T) { 157 | // No coversion needed for non-integral types. 158 | } 159 | }; 160 | 161 | // Checks if an argument is a valid printf width specifier and sets 162 | // left alignment if it is negative. 163 | template 164 | class printf_width_handler: public function { 165 | private: 166 | typedef basic_format_specs format_specs; 167 | 168 | format_specs &spec_; 169 | 170 | public: 171 | explicit printf_width_handler(format_specs &spec) : spec_(spec) {} 172 | 173 | template 174 | typename std::enable_if::value, unsigned>::type 175 | operator()(T value) { 176 | typedef typename internal::int_traits::main_type UnsignedType; 177 | UnsignedType width = static_cast(value); 178 | if (internal::is_negative(value)) { 179 | spec_.align_ = ALIGN_LEFT; 180 | width = 0 - width; 181 | } 182 | unsigned int_max = std::numeric_limits::max(); 183 | if (width > int_max) 184 | FMT_THROW(format_error("number is too big")); 185 | return static_cast(width); 186 | } 187 | 188 | template 189 | typename std::enable_if::value, unsigned>::type 190 | operator()(T) { 191 | FMT_THROW(format_error("width is not integer")); 192 | return 0; 193 | } 194 | }; 195 | } // namespace internal 196 | 197 | template 198 | class printf_arg_formatter; 199 | 200 | template < 201 | typename OutputIt, typename Char, 202 | typename ArgFormatter = 203 | printf_arg_formatter>>> 204 | class basic_printf_context; 205 | 206 | /** 207 | \rst 208 | The ``printf`` argument formatter. 209 | \endrst 210 | */ 211 | template 212 | class printf_arg_formatter: 213 | public internal::function< 214 | typename internal::arg_formatter_base::iterator>, 215 | public internal::arg_formatter_base { 216 | private: 217 | typedef typename Range::value_type char_type; 218 | typedef decltype(internal::declval().begin()) iterator; 219 | typedef internal::arg_formatter_base base; 220 | typedef basic_printf_context context_type; 221 | 222 | context_type &context_; 223 | 224 | void write_null_pointer(char) { 225 | this->spec()->type_ = 0; 226 | this->write("(nil)"); 227 | } 228 | 229 | void write_null_pointer(wchar_t) { 230 | this->spec()->type_ = 0; 231 | this->write(L"(nil)"); 232 | } 233 | 234 | public: 235 | typedef typename base::format_specs format_specs; 236 | 237 | /** 238 | \rst 239 | Constructs an argument formatter object. 240 | *buffer* is a reference to the output buffer and *spec* contains format 241 | specifier information for standard argument types. 242 | \endrst 243 | */ 244 | printf_arg_formatter(internal::basic_buffer &buffer, 245 | format_specs &spec, context_type &ctx) 246 | : base(back_insert_range>(buffer), &spec), 247 | context_(ctx) {} 248 | 249 | template 250 | typename std::enable_if::value, iterator>::type 251 | operator()(T value) { 252 | // MSVC2013 fails to compile separate overloads for bool and char_type so 253 | // use std::is_same instead. 254 | if (std::is_same::value) { 255 | format_specs &fmt_spec = *this->spec(); 256 | if (fmt_spec.type_ != 's') 257 | return base::operator()(value ? 1 : 0); 258 | fmt_spec.type_ = 0; 259 | this->write(value != 0); 260 | } else if (std::is_same::value) { 261 | format_specs &fmt_spec = *this->spec(); 262 | if (fmt_spec.type_ && fmt_spec.type_ != 'c') 263 | return (*this)(static_cast(value)); 264 | fmt_spec.flags_ = 0; 265 | fmt_spec.align_ = ALIGN_RIGHT; 266 | return base::operator()(value); 267 | } else { 268 | return base::operator()(value); 269 | } 270 | return this->out(); 271 | } 272 | 273 | template 274 | typename std::enable_if::value, iterator>::type 275 | operator()(T value) { 276 | return base::operator()(value); 277 | } 278 | 279 | /** Formats a null-terminated C string. */ 280 | iterator operator()(const char *value) { 281 | if (value) 282 | base::operator()(value); 283 | else if (this->spec()->type_ == 'p') 284 | write_null_pointer(char_type()); 285 | else 286 | this->write("(null)"); 287 | return this->out(); 288 | } 289 | 290 | /** Formats a null-terminated wide C string. */ 291 | iterator operator()(const wchar_t *value) { 292 | if (value) 293 | base::operator()(value); 294 | else if (this->spec()->type_ == 'p') 295 | write_null_pointer(char_type()); 296 | else 297 | this->write(L"(null)"); 298 | return this->out(); 299 | } 300 | 301 | iterator operator()(basic_string_view value) { 302 | return base::operator()(value); 303 | } 304 | 305 | iterator operator()(monostate value) { 306 | return base::operator()(value); 307 | } 308 | 309 | /** Formats a pointer. */ 310 | iterator operator()(const void *value) { 311 | if (value) 312 | return base::operator()(value); 313 | this->spec()->type_ = 0; 314 | write_null_pointer(char_type()); 315 | return this->out(); 316 | } 317 | 318 | /** Formats an argument of a custom (user-defined) type. */ 319 | iterator operator()(typename basic_format_arg::handle handle) { 320 | handle.format(context_); 321 | return this->out(); 322 | } 323 | }; 324 | 325 | template 326 | struct printf_formatter { 327 | template 328 | auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { return ctx.begin(); } 329 | 330 | template 331 | auto format(const T &value, FormatContext &ctx) -> decltype(ctx.out()) { 332 | internal::format_value(internal::get_container(ctx.out()), value); 333 | return ctx.out(); 334 | } 335 | }; 336 | 337 | /** This template formats data and writes the output to a writer. */ 338 | template 339 | class basic_printf_context : 340 | // Inherit publicly as a workaround for the icc bug 341 | // https://software.intel.com/en-us/forums/intel-c-compiler/topic/783476. 342 | public internal::context_base< 343 | OutputIt, basic_printf_context, Char> { 344 | public: 345 | /** The character type for the output. */ 346 | typedef Char char_type; 347 | 348 | template 349 | struct formatter_type { typedef printf_formatter type; }; 350 | 351 | private: 352 | typedef internal::context_base base; 353 | typedef typename base::format_arg format_arg; 354 | typedef basic_format_specs format_specs; 355 | typedef internal::null_terminating_iterator iterator; 356 | 357 | void parse_flags(format_specs &spec, iterator &it); 358 | 359 | // Returns the argument with specified index or, if arg_index is equal 360 | // to the maximum unsigned value, the next argument. 361 | format_arg get_arg( 362 | iterator it, 363 | unsigned arg_index = (std::numeric_limits::max)()); 364 | 365 | // Parses argument index, flags and width and returns the argument index. 366 | unsigned parse_header(iterator &it, format_specs &spec); 367 | 368 | public: 369 | /** 370 | \rst 371 | Constructs a ``printf_context`` object. References to the arguments and 372 | the writer are stored in the context object so make sure they have 373 | appropriate lifetimes. 374 | \endrst 375 | */ 376 | basic_printf_context(OutputIt out, basic_string_view format_str, 377 | basic_format_args args) 378 | : base(out, format_str, args) {} 379 | 380 | using base::parse_context; 381 | using base::out; 382 | using base::advance_to; 383 | 384 | /** Formats stored arguments and writes the output to the range. */ 385 | void format(); 386 | }; 387 | 388 | template 389 | void basic_printf_context::parse_flags( 390 | format_specs &spec, iterator &it) { 391 | for (;;) { 392 | switch (*it++) { 393 | case '-': 394 | spec.align_ = ALIGN_LEFT; 395 | break; 396 | case '+': 397 | spec.flags_ |= SIGN_FLAG | PLUS_FLAG; 398 | break; 399 | case '0': 400 | spec.fill_ = '0'; 401 | break; 402 | case ' ': 403 | spec.flags_ |= SIGN_FLAG; 404 | break; 405 | case '#': 406 | spec.flags_ |= HASH_FLAG; 407 | break; 408 | default: 409 | --it; 410 | return; 411 | } 412 | } 413 | } 414 | 415 | template 416 | typename basic_printf_context::format_arg 417 | basic_printf_context::get_arg( 418 | iterator it, unsigned arg_index) { 419 | (void)it; 420 | if (arg_index == std::numeric_limits::max()) 421 | return this->do_get_arg(this->parse_context().next_arg_id()); 422 | return base::get_arg(arg_index - 1); 423 | } 424 | 425 | template 426 | unsigned basic_printf_context::parse_header( 427 | iterator &it, format_specs &spec) { 428 | unsigned arg_index = std::numeric_limits::max(); 429 | char_type c = *it; 430 | if (c >= '0' && c <= '9') { 431 | // Parse an argument index (if followed by '$') or a width possibly 432 | // preceded with '0' flag(s). 433 | internal::error_handler eh; 434 | unsigned value = parse_nonnegative_int(it, eh); 435 | if (*it == '$') { // value is an argument index 436 | ++it; 437 | arg_index = value; 438 | } else { 439 | if (c == '0') 440 | spec.fill_ = '0'; 441 | if (value != 0) { 442 | // Nonzero value means that we parsed width and don't need to 443 | // parse it or flags again, so return now. 444 | spec.width_ = value; 445 | return arg_index; 446 | } 447 | } 448 | } 449 | parse_flags(spec, it); 450 | // Parse width. 451 | if (*it >= '0' && *it <= '9') { 452 | internal::error_handler eh; 453 | spec.width_ = parse_nonnegative_int(it, eh); 454 | } else if (*it == '*') { 455 | ++it; 456 | spec.width_ = 457 | fmt::visit(internal::printf_width_handler(spec), get_arg(it)); 458 | } 459 | return arg_index; 460 | } 461 | 462 | template 463 | void basic_printf_context::format() { 464 | auto &buffer = internal::get_container(this->out()); 465 | auto start = iterator(this->parse_context()); 466 | auto it = start; 467 | using internal::pointer_from; 468 | while (*it) { 469 | char_type c = *it++; 470 | if (c != '%') continue; 471 | if (*it == c) { 472 | buffer.append(pointer_from(start), pointer_from(it)); 473 | start = ++it; 474 | continue; 475 | } 476 | buffer.append(pointer_from(start), pointer_from(it) - 1); 477 | 478 | format_specs spec; 479 | spec.align_ = ALIGN_RIGHT; 480 | 481 | // Parse argument index, flags and width. 482 | unsigned arg_index = parse_header(it, spec); 483 | 484 | // Parse precision. 485 | if (*it == '.') { 486 | ++it; 487 | if ('0' <= *it && *it <= '9') { 488 | internal::error_handler eh; 489 | spec.precision_ = static_cast(parse_nonnegative_int(it, eh)); 490 | } else if (*it == '*') { 491 | ++it; 492 | spec.precision_ = 493 | fmt::visit(internal::printf_precision_handler(), get_arg(it)); 494 | } else { 495 | spec.precision_ = 0; 496 | } 497 | } 498 | 499 | format_arg arg = get_arg(it, arg_index); 500 | if (spec.flag(HASH_FLAG) && fmt::visit(internal::is_zero_int(), arg)) 501 | spec.flags_ &= ~internal::to_unsigned(HASH_FLAG); 502 | if (spec.fill_ == '0') { 503 | if (arg.is_arithmetic()) 504 | spec.align_ = ALIGN_NUMERIC; 505 | else 506 | spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. 507 | } 508 | 509 | // Parse length and convert the argument to the required type. 510 | using internal::convert_arg; 511 | switch (*it++) { 512 | case 'h': 513 | if (*it == 'h') 514 | convert_arg(arg, *++it); 515 | else 516 | convert_arg(arg, *it); 517 | break; 518 | case 'l': 519 | if (*it == 'l') 520 | convert_arg(arg, *++it); 521 | else 522 | convert_arg(arg, *it); 523 | break; 524 | case 'j': 525 | convert_arg(arg, *it); 526 | break; 527 | case 'z': 528 | convert_arg(arg, *it); 529 | break; 530 | case 't': 531 | convert_arg(arg, *it); 532 | break; 533 | case 'L': 534 | // printf produces garbage when 'L' is omitted for long double, no 535 | // need to do the same. 536 | break; 537 | default: 538 | --it; 539 | convert_arg(arg, *it); 540 | } 541 | 542 | // Parse type. 543 | if (!*it) 544 | FMT_THROW(format_error("invalid format string")); 545 | spec.type_ = static_cast(*it++); 546 | if (arg.is_integral()) { 547 | // Normalize type. 548 | switch (spec.type_) { 549 | case 'i': case 'u': 550 | spec.type_ = 'd'; 551 | break; 552 | case 'c': 553 | // TODO: handle wchar_t better? 554 | fmt::visit(internal::char_converter(arg), arg); 555 | break; 556 | } 557 | } 558 | 559 | start = it; 560 | 561 | // Format argument. 562 | fmt::visit(AF(buffer, spec, *this), arg); 563 | } 564 | buffer.append(pointer_from(start), pointer_from(it)); 565 | } 566 | 567 | template 568 | void printf(internal::basic_buffer &buf, basic_string_view format, 569 | basic_format_args args) { 570 | Context(std::back_inserter(buf), format, args).format(); 571 | } 572 | 573 | template 574 | struct printf_context { 575 | typedef basic_printf_context< 576 | std::back_insert_iterator, typename Buffer::value_type> type; 577 | }; 578 | 579 | template 580 | inline format_arg_store::type, Args...> 581 | make_printf_args(const Args & ... args) { 582 | return format_arg_store::type, Args...>( 583 | args...); 584 | } 585 | typedef basic_format_args::type> printf_args; 586 | typedef basic_format_args::type> wprintf_args; 587 | 588 | inline std::string vsprintf(string_view format, printf_args args) { 589 | memory_buffer buffer; 590 | printf(buffer, format, args); 591 | return to_string(buffer); 592 | } 593 | 594 | /** 595 | \rst 596 | Formats arguments and returns the result as a string. 597 | 598 | **Example**:: 599 | 600 | std::string message = fmt::sprintf("The answer is %d", 42); 601 | \endrst 602 | */ 603 | template 604 | inline std::string sprintf(string_view format_str, const Args & ... args) { 605 | return vsprintf(format_str, 606 | make_format_args::type>(args...)); 607 | } 608 | 609 | inline std::wstring vsprintf(wstring_view format, wprintf_args args) { 610 | wmemory_buffer buffer; 611 | printf(buffer, format, args); 612 | return to_string(buffer); 613 | } 614 | 615 | template 616 | inline std::wstring sprintf(wstring_view format_str, const Args & ... args) { 617 | return vsprintf(format_str, 618 | make_format_args::type>(args...)); 619 | } 620 | 621 | template 622 | inline int vfprintf(std::FILE *f, basic_string_view format, 623 | basic_format_args>::type> args) { 625 | basic_memory_buffer buffer; 626 | printf(buffer, format, args); 627 | std::size_t size = buffer.size(); 628 | return std::fwrite( 629 | buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast(size); 630 | } 631 | 632 | /** 633 | \rst 634 | Prints formatted data to the file *f*. 635 | 636 | **Example**:: 637 | 638 | fmt::fprintf(stderr, "Don't %s!", "panic"); 639 | \endrst 640 | */ 641 | template 642 | inline int fprintf(std::FILE *f, string_view format_str, const Args & ... args) { 643 | auto vargs = make_format_args< 644 | typename printf_context::type>(args...); 645 | return vfprintf(f, format_str, vargs); 646 | } 647 | 648 | template 649 | inline int fprintf(std::FILE *f, wstring_view format_str, 650 | const Args & ... args) { 651 | return vfprintf(f, format_str, 652 | make_format_args::type>(args...)); 653 | } 654 | 655 | inline int vprintf(string_view format, printf_args args) { 656 | return vfprintf(stdout, format, args); 657 | } 658 | 659 | inline int vprintf(wstring_view format, wprintf_args args) { 660 | return vfprintf(stdout, format, args); 661 | } 662 | 663 | /** 664 | \rst 665 | Prints formatted data to ``stdout``. 666 | 667 | **Example**:: 668 | 669 | fmt::printf("Elapsed time: %.2f seconds", 1.23); 670 | \endrst 671 | */ 672 | template 673 | inline int printf(string_view format_str, const Args & ... args) { 674 | return vprintf(format_str, 675 | make_format_args::type>(args...)); 676 | } 677 | 678 | template 679 | inline int printf(wstring_view format_str, const Args & ... args) { 680 | return vprintf(format_str, 681 | make_format_args::type>(args...)); 682 | } 683 | 684 | inline int vfprintf(std::ostream &os, string_view format_str, 685 | printf_args args) { 686 | memory_buffer buffer; 687 | printf(buffer, format_str, args); 688 | internal::write(os, buffer); 689 | return static_cast(buffer.size()); 690 | } 691 | 692 | inline int vfprintf(std::wostream &os, wstring_view format_str, 693 | wprintf_args args) { 694 | wmemory_buffer buffer; 695 | printf(buffer, format_str, args); 696 | internal::write(os, buffer); 697 | return static_cast(buffer.size()); 698 | } 699 | 700 | /** 701 | \rst 702 | Prints formatted data to the stream *os*. 703 | 704 | **Example**:: 705 | 706 | fmt::fprintf(cerr, "Don't %s!", "panic"); 707 | \endrst 708 | */ 709 | template 710 | inline int fprintf(std::ostream &os, string_view format_str, 711 | const Args & ... args) { 712 | auto vargs = make_format_args< 713 | typename printf_context::type>(args...); 714 | return vfprintf(os, format_str, vargs); 715 | } 716 | 717 | template 718 | inline int fprintf(std::wostream &os, wstring_view format_str, 719 | const Args & ... args) { 720 | auto vargs = make_format_args< 721 | typename printf_context::type>(args...); 722 | return vfprintf(os, format_str, vargs); 723 | } 724 | FMT_END_NAMESPACE 725 | 726 | #endif // FMT_PRINTF_H_ 727 | -------------------------------------------------------------------------------- /ext/fmt-5.2.1/include/fmt/ranges.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - the core API 2 | // 3 | // Copyright (c) 2012 - present, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | // 8 | // Copyright (c) 2018 - present, Remotion (Igor Schulz) 9 | // All Rights Reserved 10 | // {fmt} support for ranges, containers and types tuple interface. 11 | 12 | #ifndef FMT_RANGES_H_ 13 | #define FMT_RANGES_H_ 14 | 15 | #include "format.h" 16 | #include 17 | 18 | // output only up to N items from the range. 19 | #ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT 20 | # define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256 21 | #endif 22 | 23 | FMT_BEGIN_NAMESPACE 24 | 25 | template 26 | struct formatting_base { 27 | template 28 | FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { 29 | return ctx.begin(); 30 | } 31 | }; 32 | 33 | template 34 | struct formatting_range : formatting_base { 35 | static FMT_CONSTEXPR_DECL const std::size_t range_length_limit = 36 | FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range. 37 | Char prefix; 38 | Char delimiter; 39 | Char postfix; 40 | formatting_range() : prefix('{'), delimiter(','), postfix('}') {} 41 | static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true; 42 | static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false; 43 | }; 44 | 45 | template 46 | struct formatting_tuple : formatting_base { 47 | Char prefix; 48 | Char delimiter; 49 | Char postfix; 50 | formatting_tuple() : prefix('('), delimiter(','), postfix(')') {} 51 | static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true; 52 | static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false; 53 | }; 54 | 55 | namespace internal { 56 | 57 | template 58 | void copy(const RangeT &range, OutputIterator out) { 59 | for (auto it = range.begin(), end = range.end(); it != end; ++it) 60 | *out++ = *it; 61 | } 62 | 63 | template 64 | void copy(const char *str, OutputIterator out) { 65 | const char *p_curr = str; 66 | while (*p_curr) { 67 | *out++ = *p_curr++; 68 | } 69 | } 70 | 71 | template 72 | void copy(char ch, OutputIterator out) { 73 | *out++ = ch; 74 | } 75 | 76 | /// Return true value if T has std::string interface, like std::string_view. 77 | template 78 | class is_like_std_string { 79 | template 80 | static auto check(U *p) -> 81 | decltype(p->find('a'), p->length(), p->data(), int()); 82 | template 83 | static void check(...); 84 | 85 | public: 86 | static FMT_CONSTEXPR_DECL const bool value = 87 | !std::is_void(FMT_NULL))>::value; 88 | }; 89 | 90 | template 91 | struct is_like_std_string> : std::true_type {}; 92 | 93 | template 94 | struct conditional_helper {}; 95 | 96 | template 97 | struct is_range_ : std::false_type {}; 98 | 99 | #if !FMT_MSC_VER || FMT_MSC_VER > 1800 100 | template 101 | struct is_range_().begin()), 104 | decltype(internal::declval().end())>, 105 | void>::type> : std::true_type {}; 106 | #endif 107 | 108 | /// tuple_size and tuple_element check. 109 | template 110 | class is_tuple_like_ { 111 | template 112 | static auto check(U *p) -> 113 | decltype(std::tuple_size::value, 114 | internal::declval::type>(), int()); 115 | template 116 | static void check(...); 117 | 118 | public: 119 | static FMT_CONSTEXPR_DECL const bool value = 120 | !std::is_void(FMT_NULL))>::value; 121 | }; 122 | 123 | // Check for integer_sequence 124 | #if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900 125 | template 126 | using integer_sequence = std::integer_sequence; 127 | template 128 | using index_sequence = std::index_sequence; 129 | template 130 | using make_index_sequence = std::make_index_sequence; 131 | #else 132 | template 133 | struct integer_sequence { 134 | typedef T value_type; 135 | 136 | static FMT_CONSTEXPR std::size_t size() { 137 | return sizeof...(N); 138 | } 139 | }; 140 | 141 | template 142 | using index_sequence = integer_sequence; 143 | 144 | template 145 | struct make_integer_sequence : make_integer_sequence {}; 146 | template 147 | struct make_integer_sequence : integer_sequence {}; 148 | 149 | template 150 | using make_index_sequence = make_integer_sequence; 151 | #endif 152 | 153 | template 154 | void for_each(index_sequence, Tuple &&tup, F &&f) FMT_NOEXCEPT { 155 | using std::get; 156 | // using free function get(T) now. 157 | const int _[] = {0, ((void)f(get(tup)), 0)...}; 158 | (void)_; // blocks warnings 159 | } 160 | 161 | template 162 | FMT_CONSTEXPR make_index_sequence::value> 163 | get_indexes(T const &) { return {}; } 164 | 165 | template 166 | void for_each(Tuple &&tup, F &&f) { 167 | const auto indexes = get_indexes(tup); 168 | for_each(indexes, std::forward(tup), std::forward(f)); 169 | } 170 | 171 | template 172 | FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&, 173 | typename std::enable_if< 174 | !is_like_std_string::type>::value>::type* = nullptr) { 175 | return add_space ? " {}" : "{}"; 176 | } 177 | 178 | template 179 | FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&, 180 | typename std::enable_if< 181 | is_like_std_string::type>::value>::type* = nullptr) { 182 | return add_space ? " \"{}\"" : "\"{}\""; 183 | } 184 | 185 | FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char*) { 186 | return add_space ? " \"{}\"" : "\"{}\""; 187 | } 188 | FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t*) { 189 | return add_space ? L" \"{}\"" : L"\"{}\""; 190 | } 191 | 192 | FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) { 193 | return add_space ? " '{}'" : "'{}'"; 194 | } 195 | FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) { 196 | return add_space ? L" '{}'" : L"'{}'"; 197 | } 198 | 199 | } // namespace internal 200 | 201 | template 202 | struct is_tuple_like { 203 | static FMT_CONSTEXPR_DECL const bool value = 204 | internal::is_tuple_like_::value && !internal::is_range_::value; 205 | }; 206 | 207 | template 208 | struct formatter::value>::type> { 210 | private: 211 | // C++11 generic lambda for format() 212 | template 213 | struct format_each { 214 | template 215 | void operator()(const T& v) { 216 | if (i > 0) { 217 | if (formatting.add_prepostfix_space) { 218 | *out++ = ' '; 219 | } 220 | internal::copy(formatting.delimiter, out); 221 | } 222 | format_to(out, 223 | internal::format_str_quoted( 224 | (formatting.add_delimiter_spaces && i > 0), v), 225 | v); 226 | ++i; 227 | } 228 | 229 | formatting_tuple& formatting; 230 | std::size_t& i; 231 | typename std::add_lvalue_reference().out())>::type out; 232 | }; 233 | 234 | public: 235 | formatting_tuple formatting; 236 | 237 | template 238 | FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { 239 | return formatting.parse(ctx); 240 | } 241 | 242 | template 243 | auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) { 244 | auto out = ctx.out(); 245 | std::size_t i = 0; 246 | internal::copy(formatting.prefix, out); 247 | 248 | internal::for_each(values, format_each{formatting, i, out}); 249 | if (formatting.add_prepostfix_space) { 250 | *out++ = ' '; 251 | } 252 | internal::copy(formatting.postfix, out); 253 | 254 | return ctx.out(); 255 | } 256 | }; 257 | 258 | template 259 | struct is_range { 260 | static FMT_CONSTEXPR_DECL const bool value = 261 | internal::is_range_::value && !internal::is_like_std_string::value; 262 | }; 263 | 264 | template 265 | struct formatter::value>::type> { 267 | 268 | formatting_range formatting; 269 | 270 | template 271 | FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { 272 | return formatting.parse(ctx); 273 | } 274 | 275 | template 276 | typename FormatContext::iterator format( 277 | const RangeT &values, FormatContext &ctx) { 278 | auto out = ctx.out(); 279 | internal::copy(formatting.prefix, out); 280 | std::size_t i = 0; 281 | for (auto it = values.begin(), end = values.end(); it != end; ++it) { 282 | if (i > 0) { 283 | if (formatting.add_prepostfix_space) { 284 | *out++ = ' '; 285 | } 286 | internal::copy(formatting.delimiter, out); 287 | } 288 | format_to(out, 289 | internal::format_str_quoted( 290 | (formatting.add_delimiter_spaces && i > 0), *it), 291 | *it); 292 | if (++i > formatting.range_length_limit) { 293 | format_to(out, " ... "); 294 | break; 295 | } 296 | } 297 | if (formatting.add_prepostfix_space) { 298 | *out++ = ' '; 299 | } 300 | internal::copy(formatting.postfix, out); 301 | return ctx.out(); 302 | } 303 | }; 304 | 305 | FMT_END_NAMESPACE 306 | 307 | #endif // FMT_RANGES_H_ 308 | 309 | -------------------------------------------------------------------------------- /ext/fmt-5.2.1/include/fmt/time.h: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ - time formatting 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #ifndef FMT_TIME_H_ 9 | #define FMT_TIME_H_ 10 | 11 | #include "format.h" 12 | #include 13 | 14 | FMT_BEGIN_NAMESPACE 15 | 16 | // Prevents expansion of a preceding token as a function-style macro. 17 | // Usage: f FMT_NOMACRO() 18 | #define FMT_NOMACRO 19 | 20 | namespace internal{ 21 | inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); } 22 | inline null<> localtime_s(...) { return null<>(); } 23 | inline null<> gmtime_r(...) { return null<>(); } 24 | inline null<> gmtime_s(...) { return null<>(); } 25 | } 26 | 27 | // Thread-safe replacement for std::localtime 28 | inline std::tm localtime(std::time_t time) { 29 | struct dispatcher { 30 | std::time_t time_; 31 | std::tm tm_; 32 | 33 | dispatcher(std::time_t t): time_(t) {} 34 | 35 | bool run() { 36 | using namespace fmt::internal; 37 | return handle(localtime_r(&time_, &tm_)); 38 | } 39 | 40 | bool handle(std::tm *tm) { return tm != FMT_NULL; } 41 | 42 | bool handle(internal::null<>) { 43 | using namespace fmt::internal; 44 | return fallback(localtime_s(&tm_, &time_)); 45 | } 46 | 47 | bool fallback(int res) { return res == 0; } 48 | 49 | bool fallback(internal::null<>) { 50 | using namespace fmt::internal; 51 | std::tm *tm = std::localtime(&time_); 52 | if (tm) tm_ = *tm; 53 | return tm != FMT_NULL; 54 | } 55 | }; 56 | dispatcher lt(time); 57 | if (lt.run()) 58 | return lt.tm_; 59 | // Too big time values may be unsupported. 60 | FMT_THROW(format_error("time_t value out of range")); 61 | } 62 | 63 | // Thread-safe replacement for std::gmtime 64 | inline std::tm gmtime(std::time_t time) { 65 | struct dispatcher { 66 | std::time_t time_; 67 | std::tm tm_; 68 | 69 | dispatcher(std::time_t t): time_(t) {} 70 | 71 | bool run() { 72 | using namespace fmt::internal; 73 | return handle(gmtime_r(&time_, &tm_)); 74 | } 75 | 76 | bool handle(std::tm *tm) { return tm != FMT_NULL; } 77 | 78 | bool handle(internal::null<>) { 79 | using namespace fmt::internal; 80 | return fallback(gmtime_s(&tm_, &time_)); 81 | } 82 | 83 | bool fallback(int res) { return res == 0; } 84 | 85 | bool fallback(internal::null<>) { 86 | std::tm *tm = std::gmtime(&time_); 87 | if (tm) tm_ = *tm; 88 | return tm != FMT_NULL; 89 | } 90 | }; 91 | dispatcher gt(time); 92 | if (gt.run()) 93 | return gt.tm_; 94 | // Too big time values may be unsupported. 95 | FMT_THROW(format_error("time_t value out of range")); 96 | } 97 | 98 | namespace internal { 99 | inline std::size_t strftime(char *str, std::size_t count, const char *format, 100 | const std::tm *time) { 101 | return std::strftime(str, count, format, time); 102 | } 103 | 104 | inline std::size_t strftime(wchar_t *str, std::size_t count, 105 | const wchar_t *format, const std::tm *time) { 106 | return std::wcsftime(str, count, format, time); 107 | } 108 | } 109 | 110 | template 111 | struct formatter { 112 | template 113 | auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { 114 | auto it = internal::null_terminating_iterator(ctx); 115 | if (*it == ':') 116 | ++it; 117 | auto end = it; 118 | while (*end && *end != '}') 119 | ++end; 120 | tm_format.reserve(end - it + 1); 121 | using internal::pointer_from; 122 | tm_format.append(pointer_from(it), pointer_from(end)); 123 | tm_format.push_back('\0'); 124 | return pointer_from(end); 125 | } 126 | 127 | template 128 | auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) { 129 | internal::basic_buffer &buf = internal::get_container(ctx.out()); 130 | std::size_t start = buf.size(); 131 | for (;;) { 132 | std::size_t size = buf.capacity() - start; 133 | std::size_t count = 134 | internal::strftime(&buf[start], size, &tm_format[0], &tm); 135 | if (count != 0) { 136 | buf.resize(start + count); 137 | break; 138 | } 139 | if (size >= tm_format.size() * 256) { 140 | // If the buffer is 256 times larger than the format string, assume 141 | // that `strftime` gives an empty result. There doesn't seem to be a 142 | // better way to distinguish the two cases: 143 | // https://github.com/fmtlib/fmt/issues/367 144 | break; 145 | } 146 | const std::size_t MIN_GROWTH = 10; 147 | buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); 148 | } 149 | return ctx.out(); 150 | } 151 | 152 | basic_memory_buffer tm_format; 153 | }; 154 | FMT_END_NAMESPACE 155 | 156 | #endif // FMT_TIME_H_ 157 | -------------------------------------------------------------------------------- /ext/fmt-5.2.1/src/format.cc: -------------------------------------------------------------------------------- 1 | // Formatting library for C++ 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | #include "fmt/format-inl.h" 9 | 10 | FMT_BEGIN_NAMESPACE 11 | template struct internal::basic_data; 12 | 13 | // Explicit instantiations for char. 14 | 15 | template FMT_API char internal::thousands_sep(locale_provider *lp); 16 | 17 | template void internal::basic_buffer::append(const char *, const char *); 18 | 19 | template void basic_fixed_buffer::grow(std::size_t); 20 | 21 | template void internal::arg_map::init( 22 | const basic_format_args &args); 23 | 24 | template FMT_API int internal::char_traits::format_float( 25 | char *, std::size_t, const char *, int, double); 26 | 27 | template FMT_API int internal::char_traits::format_float( 28 | char *, std::size_t, const char *, int, long double); 29 | 30 | template FMT_API std::string internal::vformat( 31 | string_view, basic_format_args); 32 | 33 | // Explicit instantiations for wchar_t. 34 | 35 | template FMT_API wchar_t internal::thousands_sep(locale_provider *); 36 | 37 | template void internal::basic_buffer::append( 38 | const wchar_t *, const wchar_t *); 39 | 40 | template void basic_fixed_buffer::grow(std::size_t); 41 | 42 | template void internal::arg_map::init( 43 | const basic_format_args &); 44 | 45 | template FMT_API int internal::char_traits::format_float( 46 | wchar_t *, std::size_t, const wchar_t *, int, double); 47 | 48 | template FMT_API int internal::char_traits::format_float( 49 | wchar_t *, std::size_t, const wchar_t *, int, long double); 50 | 51 | template FMT_API std::wstring internal::vformat( 52 | wstring_view, basic_format_args); 53 | FMT_END_NAMESPACE 54 | -------------------------------------------------------------------------------- /ext/fmt-5.2.1/src/posix.cc: -------------------------------------------------------------------------------- 1 | // A C++ interface to POSIX functions. 2 | // 3 | // Copyright (c) 2012 - 2016, Victor Zverovich 4 | // All rights reserved. 5 | // 6 | // For the license information refer to format.h. 7 | 8 | // Disable bogus MSVC warnings. 9 | #if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER) 10 | # define _CRT_SECURE_NO_WARNINGS 11 | #endif 12 | 13 | #include "fmt/posix.h" 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #ifndef _WIN32 20 | # include 21 | #else 22 | # ifndef WIN32_LEAN_AND_MEAN 23 | # define WIN32_LEAN_AND_MEAN 24 | # endif 25 | # include 26 | # include 27 | 28 | # define O_CREAT _O_CREAT 29 | # define O_TRUNC _O_TRUNC 30 | 31 | # ifndef S_IRUSR 32 | # define S_IRUSR _S_IREAD 33 | # endif 34 | 35 | # ifndef S_IWUSR 36 | # define S_IWUSR _S_IWRITE 37 | # endif 38 | 39 | # ifdef __MINGW32__ 40 | # define _SH_DENYNO 0x40 41 | # endif 42 | 43 | #endif // _WIN32 44 | 45 | #ifdef fileno 46 | # undef fileno 47 | #endif 48 | 49 | namespace { 50 | #ifdef _WIN32 51 | // Return type of read and write functions. 52 | typedef int RWResult; 53 | 54 | // On Windows the count argument to read and write is unsigned, so convert 55 | // it from size_t preventing integer overflow. 56 | inline unsigned convert_rwcount(std::size_t count) { 57 | return count <= UINT_MAX ? static_cast(count) : UINT_MAX; 58 | } 59 | #else 60 | // Return type of read and write functions. 61 | typedef ssize_t RWResult; 62 | 63 | inline std::size_t convert_rwcount(std::size_t count) { return count; } 64 | #endif 65 | } 66 | 67 | FMT_BEGIN_NAMESPACE 68 | 69 | buffered_file::~buffered_file() FMT_NOEXCEPT { 70 | if (file_ && FMT_SYSTEM(fclose(file_)) != 0) 71 | report_system_error(errno, "cannot close file"); 72 | } 73 | 74 | buffered_file::buffered_file(cstring_view filename, cstring_view mode) { 75 | FMT_RETRY_VAL(file_, 76 | FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), FMT_NULL); 77 | if (!file_) 78 | FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str())); 79 | } 80 | 81 | void buffered_file::close() { 82 | if (!file_) 83 | return; 84 | int result = FMT_SYSTEM(fclose(file_)); 85 | file_ = FMT_NULL; 86 | if (result != 0) 87 | FMT_THROW(system_error(errno, "cannot close file")); 88 | } 89 | 90 | // A macro used to prevent expansion of fileno on broken versions of MinGW. 91 | #define FMT_ARGS 92 | 93 | int buffered_file::fileno() const { 94 | int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_)); 95 | if (fd == -1) 96 | FMT_THROW(system_error(errno, "cannot get file descriptor")); 97 | return fd; 98 | } 99 | 100 | file::file(cstring_view path, int oflag) { 101 | int mode = S_IRUSR | S_IWUSR; 102 | #if defined(_WIN32) && !defined(__MINGW32__) 103 | fd_ = -1; 104 | FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode)); 105 | #else 106 | FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode))); 107 | #endif 108 | if (fd_ == -1) 109 | FMT_THROW(system_error(errno, "cannot open file {}", path.c_str())); 110 | } 111 | 112 | file::~file() FMT_NOEXCEPT { 113 | // Don't retry close in case of EINTR! 114 | // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html 115 | if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0) 116 | report_system_error(errno, "cannot close file"); 117 | } 118 | 119 | void file::close() { 120 | if (fd_ == -1) 121 | return; 122 | // Don't retry close in case of EINTR! 123 | // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html 124 | int result = FMT_POSIX_CALL(close(fd_)); 125 | fd_ = -1; 126 | if (result != 0) 127 | FMT_THROW(system_error(errno, "cannot close file")); 128 | } 129 | 130 | long long file::size() const { 131 | #ifdef _WIN32 132 | // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT 133 | // is less than 0x0500 as is the case with some default MinGW builds. 134 | // Both functions support large file sizes. 135 | DWORD size_upper = 0; 136 | HANDLE handle = reinterpret_cast(_get_osfhandle(fd_)); 137 | DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper)); 138 | if (size_lower == INVALID_FILE_SIZE) { 139 | DWORD error = GetLastError(); 140 | if (error != NO_ERROR) 141 | FMT_THROW(windows_error(GetLastError(), "cannot get file size")); 142 | } 143 | unsigned long long long_size = size_upper; 144 | return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; 145 | #else 146 | typedef struct stat Stat; 147 | Stat file_stat = Stat(); 148 | if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) 149 | FMT_THROW(system_error(errno, "cannot get file attributes")); 150 | static_assert(sizeof(long long) >= sizeof(file_stat.st_size), 151 | "return type of file::size is not large enough"); 152 | return file_stat.st_size; 153 | #endif 154 | } 155 | 156 | std::size_t file::read(void *buffer, std::size_t count) { 157 | RWResult result = 0; 158 | FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); 159 | if (result < 0) 160 | FMT_THROW(system_error(errno, "cannot read from file")); 161 | return internal::to_unsigned(result); 162 | } 163 | 164 | std::size_t file::write(const void *buffer, std::size_t count) { 165 | RWResult result = 0; 166 | FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); 167 | if (result < 0) 168 | FMT_THROW(system_error(errno, "cannot write to file")); 169 | return internal::to_unsigned(result); 170 | } 171 | 172 | file file::dup(int fd) { 173 | // Don't retry as dup doesn't return EINTR. 174 | // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html 175 | int new_fd = FMT_POSIX_CALL(dup(fd)); 176 | if (new_fd == -1) 177 | FMT_THROW(system_error(errno, "cannot duplicate file descriptor {}", fd)); 178 | return file(new_fd); 179 | } 180 | 181 | void file::dup2(int fd) { 182 | int result = 0; 183 | FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); 184 | if (result == -1) { 185 | FMT_THROW(system_error(errno, 186 | "cannot duplicate file descriptor {} to {}", fd_, fd)); 187 | } 188 | } 189 | 190 | void file::dup2(int fd, error_code &ec) FMT_NOEXCEPT { 191 | int result = 0; 192 | FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); 193 | if (result == -1) 194 | ec = error_code(errno); 195 | } 196 | 197 | void file::pipe(file &read_end, file &write_end) { 198 | // Close the descriptors first to make sure that assignments don't throw 199 | // and there are no leaks. 200 | read_end.close(); 201 | write_end.close(); 202 | int fds[2] = {}; 203 | #ifdef _WIN32 204 | // Make the default pipe capacity same as on Linux 2.6.11+. 205 | enum { DEFAULT_CAPACITY = 65536 }; 206 | int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY)); 207 | #else 208 | // Don't retry as the pipe function doesn't return EINTR. 209 | // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html 210 | int result = FMT_POSIX_CALL(pipe(fds)); 211 | #endif 212 | if (result != 0) 213 | FMT_THROW(system_error(errno, "cannot create pipe")); 214 | // The following assignments don't throw because read_fd and write_fd 215 | // are closed. 216 | read_end = file(fds[0]); 217 | write_end = file(fds[1]); 218 | } 219 | 220 | buffered_file file::fdopen(const char *mode) { 221 | // Don't retry as fdopen doesn't return EINTR. 222 | FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode)); 223 | if (!f) 224 | FMT_THROW(system_error(errno, 225 | "cannot associate stream with file descriptor")); 226 | buffered_file bf(f); 227 | fd_ = -1; 228 | return bf; 229 | } 230 | 231 | long getpagesize() { 232 | #ifdef _WIN32 233 | SYSTEM_INFO si; 234 | GetSystemInfo(&si); 235 | return si.dwPageSize; 236 | #else 237 | long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE)); 238 | if (size < 0) 239 | FMT_THROW(system_error(errno, "cannot get memory page size")); 240 | return size; 241 | #endif 242 | } 243 | FMT_END_NAMESPACE 244 | 245 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('simplesockets', 'cpp', default_options : ['cpp_std=c++17']) 2 | 3 | fmt_dep = dependency('fmt', version: '>9', static: true) 4 | 5 | executable('testrunner', 'test.cc', 'sclasses.cc', 'swrappers.cc', 'comboaddress.cc', 6 | dependencies: [fmt_dep]) 7 | 8 | 9 | 10 | simplesockets_lib = library( 11 | 'simplesockets', 12 | 'comboaddress.cc', 'swrappers.cc', 'sclasses.cc', 13 | install: false, 14 | include_directories: '', 15 | dependencies: [fmt_dep] 16 | ) 17 | 18 | simplesockets_dep = declare_dependency( 19 | link_with: simplesockets_lib, 20 | include_directories: '', 21 | ) 22 | 23 | 24 | 25 | if meson.version().version_compare('>=0.54.0') 26 | meson.override_dependency('simplesockets', simplesockets_dep) 27 | endif 28 | -------------------------------------------------------------------------------- /sclasses.cc: -------------------------------------------------------------------------------- 1 | #include "sclasses.hh" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int waitForRWData(int fd, bool waitForRead, double* timeout, bool* error, bool* disconnected) 8 | { 9 | int ret; 10 | 11 | struct pollfd pfd; 12 | memset(&pfd, 0, sizeof(pfd)); 13 | pfd.fd = fd; 14 | 15 | if(waitForRead) 16 | pfd.events=POLLIN; 17 | else 18 | pfd.events=POLLOUT; 19 | 20 | ret = poll(&pfd, 1, timeout ? (*timeout * 1000) : -1); 21 | if ( ret == -1 ) { 22 | throw std::runtime_error("Waiting for data: "+std::string(strerror(errno))); 23 | } 24 | if(ret > 0) { 25 | if (error && (pfd.revents & POLLERR)) { 26 | *error = true; 27 | } 28 | if (disconnected && (pfd.revents & POLLHUP)) { 29 | *disconnected = true; 30 | } 31 | 32 | } 33 | return ret; 34 | } 35 | 36 | int waitForData(int fd, double* timeout) 37 | { 38 | return waitForRWData(fd, true, timeout); 39 | } 40 | 41 | int SConnectWithTimeout(int sockfd, const ComboAddress& remote, double timeout=-1) 42 | { 43 | int ret = connect(sockfd, (struct sockaddr*)&remote, remote.getSocklen()); 44 | if(ret < 0) { 45 | int savederrno = errno; 46 | if (savederrno == EINPROGRESS) { 47 | /* we wait until the connection has been established */ 48 | bool error = false; 49 | bool disconnected = false; 50 | int res = waitForRWData(sockfd, false, &timeout, &error, &disconnected); 51 | if (res == 1) { 52 | if (error) { 53 | savederrno = 0; 54 | socklen_t errlen = sizeof(savederrno); 55 | if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&savederrno, &errlen) == 0) { 56 | throw std::runtime_error(fmt::sprintf("connecting to %s failed: %s", remote.toStringWithPort(), strerror(savederrno))); 57 | } 58 | else { 59 | throw std::runtime_error(fmt::sprintf("connecting to %s failed", remote.toStringWithPort())); 60 | } 61 | } 62 | if (disconnected) { 63 | throw std::runtime_error(fmt::sprintf("%s closed the connection", remote.toStringWithPort()));; 64 | } 65 | return 0; 66 | } 67 | else if (res == 0) { 68 | throw std::runtime_error(fmt::sprintf("timeout while connecting to %s", remote.toStringWithPort())); 69 | } else if (res < 0) { 70 | savederrno = errno; 71 | throw std::runtime_error(fmt::sprintf("waiting to connect to %s: %s", remote.toStringWithPort(), strerror(savederrno))); 72 | } 73 | } 74 | else { 75 | throw std::runtime_error(fmt::sprintf("connecting to %s: %s", remote.toStringWithPort(), strerror(savederrno))); 76 | } 77 | } 78 | 79 | return ret; 80 | } 81 | 82 | 83 | bool ReadBuffer::getMoreData() 84 | { 85 | assert(d_pos == d_endpos); 86 | double timeout = d_timeout; 87 | for(;;) { 88 | int res = read(d_fd, &d_buffer[0], d_buffer.size()); 89 | if(res < 0 && errno == EAGAIN) { 90 | waitForData(d_fd, &timeout); 91 | continue; 92 | } 93 | if(res < 0) 94 | throw std::runtime_error("Getting more data: " + std::string(strerror(errno))); 95 | if(!res) 96 | return false; 97 | d_endpos = res; 98 | d_pos=0; 99 | break; 100 | } 101 | return true; 102 | } 103 | 104 | bool SocketCommunicator::getLine(std::string& line) 105 | { 106 | line.clear(); 107 | char c; 108 | while(d_rb.getChar(&c)) { 109 | line.append(1, c); 110 | if(c=='\n') 111 | return true; 112 | } 113 | return !line.empty(); 114 | } 115 | 116 | void SocketCommunicator::writen(const std::string& content) 117 | { 118 | unsigned int pos=0; 119 | 120 | int res; 121 | while(pos < content.size()) { 122 | res=write(d_fd, &content[pos], content.size()-pos); 123 | if(res < 0) { 124 | if(errno == EAGAIN) { 125 | waitForRWData(d_fd, false); 126 | continue; 127 | } 128 | throw std::runtime_error("Writing to socket: "+std::string(strerror(errno))); 129 | } 130 | if(res==0) 131 | throw std::runtime_error("EOF on write"); 132 | pos += res; 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /sclasses.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "swrappers.hh" 3 | #include 4 | 5 | int SConnectWithTimeout(int sockfd, const ComboAddress& remote, double timeout); 6 | 7 | struct Socket 8 | { 9 | Socket(int fd) : d_fd(fd){} 10 | Socket(int domain, int type, int protocol=0) 11 | { 12 | d_fd = SSocket(domain, type, protocol); 13 | } 14 | 15 | Socket(const Socket&) = delete; 16 | Socket& operator=(const Socket&) = delete; 17 | Socket(Socket&& rhs) 18 | { 19 | d_fd = rhs.d_fd; 20 | rhs.d_fd = -1; 21 | } 22 | 23 | operator int() 24 | { 25 | return d_fd; 26 | } 27 | 28 | void release() 29 | { 30 | d_fd=-1; 31 | } 32 | ~Socket() 33 | { 34 | if(d_fd >= 0) 35 | close(d_fd); 36 | } 37 | int d_fd; 38 | }; 39 | 40 | /** Simple buffered reader for use on a non-blocking socket. 41 | Has only one method to access data, getChar() which either gets you a character or it doesn't. 42 | If the internal buffer is empty, SimpleBuffer will attempt to get up to bufsize bytes more in one go. 43 | Optionally, with setTimeout(seconds) a timeout can be set. 44 | 45 | WARNING: Only use ReadBuffer on a non-blocking socket! Otherwise it will 46 | block indefinitely to read 'bufsize' bytes, even if you only wanted one! 47 | */ 48 | 49 | class ReadBuffer 50 | { 51 | public: 52 | //! Instantiate on a non-blocking filedescriptor, with a given buffer size in bytes 53 | explicit ReadBuffer(int fd, int bufsize=2048) : d_fd(fd), d_buffer(bufsize) 54 | {} 55 | 56 | //! Set timeout in seconds 57 | void setTimeout(double timeout) 58 | { 59 | d_timeout = timeout; 60 | } 61 | 62 | //! Gets you a character in c, or false in case of EOF 63 | inline bool getChar(char* c) 64 | { 65 | if(d_pos == d_endpos && !getMoreData()) 66 | return false; 67 | *c=d_buffer[d_pos++]; 68 | return true; 69 | } 70 | 71 | inline bool haveData() const 72 | { 73 | return d_pos != d_endpos; 74 | } 75 | 76 | private: 77 | bool getMoreData(); //!< returns false on EOF 78 | int d_fd; 79 | std::vector d_buffer; 80 | unsigned int d_pos{0}; 81 | unsigned int d_endpos{0}; 82 | double d_timeout=-1; 83 | }; 84 | 85 | /** Convenience class that requires a non-blocking socket as input and supports commonly used operations. 86 | SocketCommunicator will modify your socket to be non-blocking. This class 87 | will not close or otherwise modify your socket. 88 | Note that since SocketCommunicator instantiates a buffered reader on your socket, you should not attempt concurrent reads on the socket as long as SocketCommunicator is active. 89 | */ 90 | class SocketCommunicator 91 | { 92 | public: 93 | //! Instantiate on top of this file descriptor, which will be set to non-blocking 94 | explicit SocketCommunicator(int fd) : d_rb(fd), d_fd(fd) 95 | { 96 | SetNonBlocking(fd); 97 | } 98 | //! Connect to an address, with the default timeout (which may be infinite) 99 | void connect(const ComboAddress& a) 100 | { 101 | SConnectWithTimeout(d_fd, a, d_timeout); 102 | } 103 | //! Get a while line of text. Returns false on EOF. Will return a partial last line. With timeout. 104 | bool getLine(std::string& line); 105 | 106 | //! Fully write out a message, even in the face of partial writes. With timeout. 107 | void writen(const std::string& message); 108 | 109 | //! Set the timeout (in seconds) 110 | void setTimeout(double timeout) { d_timeout = timeout; } 111 | private: 112 | ReadBuffer d_rb; 113 | int d_fd; 114 | double d_timeout{-1}; 115 | }; 116 | 117 | // returns -1 in case if error, 0 if no data is available, 1 if there is 118 | // negative time = infinity, timeout is in seconds 119 | // should, but does not, decrement timeout 120 | int waitForRWData(int fd, bool waitForRead, double* timeout=0, bool* error=0, bool* disconnected=0); 121 | 122 | // should, but does not, decrement timeout. timeout in seconds 123 | int waitForData(int fd, double* timeout=0); 124 | -------------------------------------------------------------------------------- /socket-api.md: -------------------------------------------------------------------------------- 1 | # The sockets API 2 | I trawled the web and asked Twitter for a brief introduction on how network sockets actually work in POSIX. I know of very long and thorough explanations ([Stevens](https://www.amazon.com/W.-Richard-Stevens/e/B000AP9GV4)), medium length explanations ([Beej](http://beej.us/guide/bgnet/)), but no "tl;dr"-grade page. Here goes. 3 | 4 | The goal is to provide a quick intro to sufficient parts of the socket API so that one can write competent and robust TCP or UDP client or server programs in any language that offers access to this API. 5 | 6 | NOTE: This document is a companion to an [easy to use set of C++ helpers](https://github.com/ahupowerdns/simplesocket) that give you the exact socket API, but with less typing. 7 | 8 | The following assumes you know what IP addresses & ports are, and roughly the difference between UDP and TCP. 9 | 10 | However, even if you know the basics of the protocols, it turns out the API to the network is not obvious and full of traps. As an example, you can ask your operating system to transmit 100KB of data over TCP/IP, and almost always, it will do that. However, a few percent of the time it only transmits 90KB. And if you did not check for that, your application is now subtly broken. 11 | 12 | If this is the kind of thing you need to know about, read on. 13 | 14 | ## Core concepts 15 | The socket is the core concept. It is a file descriptor, just like you'd get from opening a file. To some degree, a socket works like a file except when it doesn't. 16 | 17 | Unlike files, sockets can be blocking or non-blocking. A non-blocking socket will never make you wait, and might not do everything you asked of it. A blocking socket will make you wait but might STILL not do everything you asked of it. In this document we start with the default of blocking sockets. 18 | 19 | We'll only be discussing datagram (UDP) or stream (TCP) sockets here. You will have read that UDP is unreliable, but it turns out TCP is not reliable either. If you write something to a TCP socket, there is no guarantee at all that anything happened to it, except that the kernel will do its best to get the data across. For UDP you don't even get that promise. This is in marked contrast to files where a `write()` and a `sync()` give you actual guarantees (if these work depends on your hardware). 20 | 21 | ## Error codes 22 | With the exception of the address resolution functions, all socket relevant system calls adhere to the C/POSIX/UNIX principle that a negative return code is an error. A 0 return code usually denotes EOF ('your connection is now gone'), a positive return tells you how much data got sent. 23 | 24 | There is not a single socket call where you do not need to check the return code. All of them, including `close()` frequently return errors you need to know about. 25 | 26 | ## Making a socket & disposing of it 27 | You make a socket with the `socket(family, type, options)` call. Family can be `AF_INET` for IPv4, `AF_INET6` for IPv6. Type is `SOCK_DGRAM` for UDP and `SOCK_STREAM` for TCP. Ignore the options for now. 28 | 29 | Once done with a socket, you can call `close()` on it. There is usually no need to call `shutdown()` on a socket, nor might this do anything useful. 30 | 31 | ## Addresses 32 | Network addresses, including port number & other parameters (for IPv6) live in `struct sockaddr_in` and `struct sockaddr_in6`. Since C does not do inheritance or polymorphism, this is emulated. Both structs start the same, and all calls accept a pointer to a `struct sockaddr` and a length field. From this, the operating system learns if it is looking at an IPv4 or an IPv6 (or another) address. 33 | 34 | Filling out these sockaddr structs is far more complicated than you'd expect, but we'll get to that. 35 | 36 | ## Anchoring a socket 37 | Once you have a socket, it can be anchored at both ends: you can bind it to a local address, and connect it to a remote one. Anchoring is sometimes optional (UDP) and sometimes mandatory (TCP). 38 | 39 | ### UDP 40 | A UDP socket is ready for use once created with `socket()`. With `sendto(sock, content, contentlen, flags, sockaddr*, sockaddrlength)` you can start lobbing datagrams (which can end up as multiple packets due to IP fragmentation). A packet either gets sent or it does not. `sendto()` will let you know if it is sure it failed by returning negative. If it returns positive, well, it tried to send your packet is the best you know. 41 | 42 | Receiving a packet can happen with `recvfrom(sock, content, room, sockaddr*, sockaddrlen*)`. This will give you the contents of the received datagram and where it came from. NOTE: You will frequently get an error code instead of a packet. This happens for example if a packet did arrive, but on copying it to userspace, the kernel found the packet malformed somehow, but it will still wake up your program. 43 | 44 | UDP sockets can also be anchored on one end or both ends. With `bind(sock, sockaddr*, sockadrlen)` the local end can be bound to an IP address and/or port number. With `connect()` and the same parameters, the other end is fixed. No actual packet gets sent to set up this 'connection', but there are benefits to a connected() UDP socket anyhow, like far better error reporting. 45 | 46 | ### TCP client (blocking) 47 | TCP sockets need to be `connect()`-ed before you can send on them. In the words used above, this means you must anchor the remote end. Such a `connect()` can take significant time, minutes. More about this later. You can anchor the local end as well with `bind()` if you want to pick the IP address or source port. 48 | 49 | ### TCP server (blocking) 50 | To receive incoming connections, a TCP socket must first be anchored locally with `bind(sock, sockaddr*, sockaddrlen)`. Then we must inform the kernel we want to `listen(s, amount)` to incoming connections. Finally, we can then call `accept(sock, sockaddr*, sockaddrlen*)` to get new sockets that represent incoming connections. 51 | 52 | NOTE: See the remark about `SO_REUSEADDR` below. 53 | 54 | NOTE: like `recvfrom()` and other socket calls, `accept()` will frequently surprise you with unexpected errors. This happens for example when a valid connection arrived, but it got disconnected before `accept()` returns. Typically, `accept()` is also the call that tells you you ran out of file descriptors, and there is no recovery from that. Naive code will retry `accept()` on `EMFILE` and thus make a bad situation worse. 55 | 56 | #### Sending (blocking) 57 | Sending data over TCP is remarkably complicated. You can use `write()` or `send()` on a TCP socket (the latter has some more options). And frequently, if you ask it to send X bytes, it will actually queue up X bytes for transmission. However, also frequently, it will return it queued up only 0.1*X bytes. 58 | 59 | So the rule is: for any call to `write()`, you must check the return code for ALL THREE conditions: 60 | 61 | * < 0: there was an actual error 62 | * 0: EOF, the connection is closed 63 | * \> 0: Some data was sent, but was it all of the data? 64 | 65 | No matter how seasoned a programmer, you WILL forget about that last case from time to time. And this will lead to hard to debug issues that only crop up under heavy load and during the holiday season. No call to `write()` on a TCP socket can get away without dealing with partial writes! 66 | 67 | Once `write()` or `send()` returns you have zero guarantees about what actually happened. The data might be sent, it might not be sent, the remote connection might have gone away. Reliable, eh? 68 | 69 | #### Receiving (blocking) 70 | Receiving data is the exact same story, but in reverse. All three error conditions must again be checked, as it is entirely possible you did not get all the data you asked for. 71 | 72 | A common mistake is to forget that TCP/IP is actually a 'stream' protocol. So if you `write()` two lines of text on the sending side, this may show up on the receiving side all in one `read()`, or `read()` might first give you the first line and on the second invocation the second line, or even give you 0.5 and then 1.5 line. 73 | 74 | In other words, the data has no envelope. The information contained in the `write()`-boundaries is not reliably retained, if at all. 75 | 76 | #### Receiving a line of text 77 | This is a ton of work to do reliably. If you do something like `read(s, buf, 1024)` in hopes of reading a line of at most 1024 characters, nothing will happen. That call will wait, for months if need be, until all 1024 bytes are in. If the line of text is only 80 characters long, you'll be waiting indefinitely. 78 | 79 | The only way to do this reliably on a blocking TCP socket is.. to read one character at a time, and stop reading once you hit '\\n'. This is astoundingly inefficient, but for now it is the only way. 80 | 81 | ## Non-blocking sockets 82 | Blocking sockets will make you wait, but might not do everything you ask of them anyhow. Non-blocking sockets only promise to not make you wait. In a sense, this makes them easier to use as they will disappoint you far quicker and break your bad code in obvious ways. 83 | 84 | To make a socket non-blocking in a portable way, do: 85 | ``` 86 | flags=fcntl(sock, F_GETFL, 0); // DO CHECK ERRORS! 87 | flags |= O_NONBLOCK; 88 | flags=fcntl(sock, F_SETFL, flags); // SERIOUSLY 89 | ``` 90 | ### TCP (non-blocking) 91 | If you try to read from a non-blocking TCP socket, you instantly get data or an error code. No matter how much data you asked for, the call could return just 1 byte. If there is no data for you, it will not respond with 0. 0 always means EOF. If there is no data, you'll receive a negative return, and `errno` will be set to `EAGAIN`. 92 | 93 | The exact same thing happens on a write. Either at least 1 byte was submitted for transmission, and the amount submitted gets returned, or you get 0 denoting EOF, or you get an error condition and `EAGAIN`. 94 | 95 | Of course you could still get all the other error conditions as well. 96 | 97 | So, if you try to read a full line of text (as described above), you can now safely ask for 1024 bytes, and if there is any data for you, you'll get it. The call will not block. You might get two lines of text though, or only a part of the line. But there is no more need to read one byte at a time. 98 | 99 | ### UDP (non-blocking) 100 | This works much like blocking UDP, alhough you might now also get `EAGAIN` when trying to receive data. At least there is no waiting. 101 | 102 | ## Waiting 103 | So, if we got EAGAIN, now what? Almost all sample code will tell you to use `select()` to wait on a socket, but no one should ever be using `select()` ever again, since this call breaks violently if you use more than x file descriptors. You'll find out x at 3AM one day. Use `poll()` instead, or one of the more modern variants (epoll, kqueue). 104 | 105 | It is important to note that POSIX takes a broad view of what denotes 'readable' or 'writable' on a socket. For example, EOF is both. So `poll()` might return and tell you a socket is readable, but when you try, it gives you EOF. 106 | 107 | In addition, like many other functions, `poll()` frequently changes its mind. If it says a socket is readable or writable, this may no longer be the case by the time you try. For this reason, do not EVER use `poll()` on a blocking socket. You might block. 108 | 109 | One can also do non-blocking `connect()` but the details are arcane. The error code of a failed connect needs to be retrieved with additional work. Sample code is in [SimpleSocket](https://github.com/ahupowerdns/simplesocket/blob/ed53be41f5bf5722cda428ae32205b4fe9576d4e/sclasses.cc#L44). 110 | 111 | ## Filling out struct sockaddr_in and struct sockaddr_in6 112 | To actually connect or send something, we'll need to fill out these sockaddr structs. This is surprisingly tricky. 113 | First, you must make sure the IPv6 struct is zeroed out as it is full of fields that need to be set to safe defaults. 114 | 115 | Secondly, the function recommended to fill out these structs (`getaddrinfo()`) has suffered from mission creep. It is safer to use the older functions inet_pton and inet_aton if you can get away with them. Sample code: 116 | 117 | ``` 118 | struct sockaddr_in ret; 119 | inet_aton("127.0.0.1", &ret.sin_addr); // DO CHECK FOR ERRORS 120 | ret.sin.sin_port = htons(80); // htons has historical reasons 121 | ``` 122 | 123 | And for IPv6: 124 | ``` 125 | struct sockaddr_in6 ret; 126 | memset(&ret, 0, sizeof(ret)); 127 | inet_pton(AF_INET6, "::1", (void*)&ret.sin6_addr); 128 | ret.sin6.sin6_port = htons(80); 129 | ``` 130 | 131 | `inet_pton` however does not deal with scoped IPv6 addresses. The full horror of converting IPv6 addresses is explained [here](https://blog.powerdns.com/2014/05/21/a-surprising-discovery-on-converting-ipv6-addresses-we-no-longer-prefer-getaddrinfo/) 132 | 133 | ## A note on reliability and "flushing" or "syncing" data 134 | No matter how you do it, the socket API will never guarantee you that your data arrived. In fact it will not even guarantee you that it got _sent_. There are various system calls that make it *more likely* that your data hit the wire. But no promises. If you ever want to be sure your data made it to the other end, the only way to find that out is if the other end actually confirms this to you. 135 | 136 | Some useful and simple tricks to make this happen can be found [here](https://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable) 137 | 138 | ## Some vital historical code 139 | You will need to run the following in all network code: 140 | ``` 141 | signal(SIGPIPE, SIG_IGN); 142 | ``` 143 | Otherwise your code will silently die occasionally for reasons that arre hard to explain. Just say no. 144 | 145 | Additionally, for any TCP socket you call `listen()` on, you must first set the socket option SO_REUSEADDR to 1. This too has valid historical reasons which are hard to explain, but just do it. 146 | 147 | ``` 148 | int one=1; 149 | setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,(char*)&one,sizeof one); 150 | ``` 151 | 152 | ## If you want to know more 153 | This page, by design, only gives an introduction to the basics. Thousand page books have been written about networking, however. 154 | 155 | [Beej](http://beej.us/guide/bgnet/) goes into intermediate depth. The glorious books by [Stevens](https://www.amazon.com/W.-Richard-Stevens/e/B000AP9GV4) are fantastic. The Open Group manpages for the various calls are exhaustive, as is [The Linux Programming Interface](http://man7.org/tlpi/). 156 | 157 | 158 | -------------------------------------------------------------------------------- /swrappers.cc: -------------------------------------------------------------------------------- 1 | #include "swrappers.hh" 2 | #include "sclasses.hh" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | /** these functions provide a very lightweight wrapper to the Berkeley sockets API. Errors -> exceptions! */ 12 | 13 | static void RuntimeError(const std::string& fmt) 14 | { 15 | throw std::runtime_error(fmt); 16 | } 17 | 18 | 19 | int SSocket(int family, int type, int flags) 20 | { 21 | int ret = socket(family, type, flags); 22 | if(ret < 0) 23 | RuntimeError(fmt::sprintf("creating socket of type %d: %s", family, strerror(errno))); 24 | return ret; 25 | } 26 | 27 | int SConnect(int sockfd, const ComboAddress& remote) 28 | { 29 | int ret = connect(sockfd, (struct sockaddr*)&remote, remote.getSocklen()); 30 | if(ret < 0) { 31 | int savederrno = errno; 32 | RuntimeError(fmt::sprintf("connecting socket to %s: %s", remote.toStringWithPort(), strerror(savederrno))); 33 | } 34 | return ret; 35 | } 36 | 37 | int SBind(int sockfd, const ComboAddress& local) 38 | { 39 | int ret = bind(sockfd, (struct sockaddr*)&local, local.getSocklen()); 40 | if(ret < 0) { 41 | int savederrno = errno; 42 | RuntimeError(fmt::sprintf("binding socket to %s: %s", local.toStringWithPort(), strerror(savederrno))); 43 | } 44 | return ret; 45 | } 46 | 47 | int SAccept(int sockfd, ComboAddress& remote) 48 | { 49 | socklen_t remlen = remote.getSocklen(); 50 | 51 | int ret = accept(sockfd, (struct sockaddr*)&remote, &remlen); 52 | if(ret < 0) 53 | RuntimeError(fmt::sprintf("accepting new connection on socket: %s", strerror(errno))); 54 | return ret; 55 | } 56 | 57 | int SListen(int sockfd, int limit) 58 | { 59 | int ret = listen(sockfd, limit); 60 | if(ret < 0) 61 | RuntimeError(fmt::sprintf("setting socket to listen: %s", strerror(errno))); 62 | return ret; 63 | } 64 | 65 | int SSetsockopt(int sockfd, int level, int opname, int value) 66 | { 67 | int ret = setsockopt(sockfd, level, opname, &value, sizeof(value)); 68 | if(ret < 0) 69 | RuntimeError(fmt::sprintf("setsockopt for level %d and opname %d to %d failed: %s", level, opname, value, strerror(errno))); 70 | return ret; 71 | } 72 | 73 | void SWrite(int sockfd, const std::string& content, std::string::size_type *wrlen) 74 | { 75 | int res = write(sockfd, &content[0], content.size()); 76 | if(res < 0) 77 | RuntimeError(fmt::sprintf("Write to socket: %s", strerror(errno))); 78 | if(wrlen) 79 | *wrlen = res; 80 | 81 | if(res != (int)content.size()) { 82 | if(wrlen) { 83 | return; 84 | } 85 | RuntimeError(fmt::sprintf("Partial write to socket: wrote %d bytes out of %d", res, content.size())); 86 | } 87 | } 88 | 89 | void SWriten(int sockfd, const std::string& content) 90 | { 91 | std::string::size_type pos=0; 92 | for(;;) { 93 | int res = write(sockfd, &content[pos], content.size()-pos); 94 | if(res < 0) 95 | RuntimeError(fmt::sprintf("Write to socket: %s", strerror(errno))); 96 | if(!res) 97 | RuntimeError(fmt::sprintf("EOF on writen")); 98 | pos += res; 99 | if(pos == content.size()) 100 | break; 101 | } 102 | } 103 | 104 | std::string SRead(int sockfd, std::string::size_type limit) 105 | { 106 | std::string ret; 107 | char buffer[1024]; 108 | std::string::size_type leftToRead=limit; 109 | for(; leftToRead;) { 110 | auto chunk = sizeof(buffer) < leftToRead ? sizeof(buffer) : leftToRead; 111 | int res = read(sockfd, buffer, chunk); 112 | if(res < 0) 113 | RuntimeError(fmt::sprintf("Read from socket: %s", strerror(errno))); 114 | if(!res) 115 | break; 116 | ret.append(buffer, res); 117 | leftToRead -= res; 118 | } 119 | return ret; 120 | } 121 | 122 | void SSendto(int sockfd, const std::string& content, const ComboAddress& dest, int flags) 123 | { 124 | int ret = sendto(sockfd, &content[0], content.size(), flags, (struct sockaddr*)&dest, dest.getSocklen()); 125 | if(ret < 0) 126 | RuntimeError(fmt::sprintf("Sending datagram with SSendto: %s", strerror(errno))); 127 | } 128 | 129 | int SSend(int sockfd, const std::string& content, int flags) 130 | { 131 | int ret = send(sockfd, &content[0], content.size(), flags); 132 | if(ret < 0) 133 | RuntimeError(fmt::sprintf("Sending with SSend: %s", strerror(errno))); 134 | return ret; 135 | } 136 | 137 | 138 | std::string SRecvfrom(int sockfd, std::string::size_type limit, ComboAddress& dest, int flags) 139 | { 140 | std::string ret; 141 | ret.resize(limit); 142 | 143 | socklen_t slen = dest.getSocklen(); 144 | int res = recvfrom(sockfd, &ret[0], ret.size(), flags, (struct sockaddr*)&dest, &slen); 145 | 146 | if(res < 0) 147 | RuntimeError(fmt::sprintf("Receiving datagram with SRecvfrom: %s", strerror(errno))); 148 | 149 | ret.resize(res); 150 | return ret; 151 | } 152 | 153 | void SGetsockname(int sock, ComboAddress& orig) 154 | { 155 | socklen_t slen=orig.getSocklen(); 156 | if(getsockname(sock, (struct sockaddr*)&orig, &slen) < 0) 157 | RuntimeError(fmt::sprintf("Error retrieving sockname of socket: %s", strerror(errno))); 158 | } 159 | 160 | 161 | void SetNonBlocking(int sock, bool to) 162 | { 163 | int flags=fcntl(sock,F_GETFL,0); 164 | if(flags<0) 165 | RuntimeError(fmt::sprintf("Retrieving socket flags: %s", strerror(errno))); 166 | 167 | // so we could optimize to not do it if nonblocking already set, but that would be.. semantics 168 | if(to) { 169 | flags |= O_NONBLOCK; 170 | } 171 | else 172 | flags &= (~O_NONBLOCK); 173 | 174 | if(fcntl(sock, F_SETFL, flags) < 0) 175 | RuntimeError(fmt::sprintf("Setting socket flags: %s", strerror(errno))); 176 | } 177 | 178 | std::map SPoll(const std::vector&rdfds, const std::vector&wrfds, double timeout) 179 | { 180 | std::vector pfds; 181 | std::map inputs; 182 | for(const auto& i : rdfds) { 183 | inputs[i]|=POLLIN; 184 | } 185 | for(const auto& i : wrfds) { 186 | inputs[i]|=POLLOUT; 187 | } 188 | for(const auto& p : inputs) { 189 | pfds.push_back({p.first, p.second, 0}); 190 | } 191 | int res = poll(&pfds[0], pfds.size(), timeout*1000); 192 | if(res < 0) 193 | RuntimeError(fmt::sprintf("Setting up poll: %s", strerror(errno))); 194 | inputs.clear(); 195 | if(res) { 196 | for(const auto& pfd : pfds) { 197 | if((pfd.revents & pfd.events) || pfd.revents==POLLERR ) 198 | inputs[pfd.fd]=pfd.revents; 199 | } 200 | } 201 | return inputs; 202 | } 203 | 204 | std::vector resolveName(const std::string& name, bool ipv4, bool ipv6) 205 | { 206 | std::vector ret; 207 | 208 | try { 209 | ComboAddress attempt(name); 210 | ret.push_back(attempt); 211 | return ret; 212 | } 213 | catch(...){} 214 | 215 | // if we are here, it is a name, format: name:port 216 | 217 | 218 | int port=0; 219 | std::string rname; 220 | auto pos = name.find(':'); 221 | if(pos != std::string::npos) { 222 | rname = name.substr(0, pos); 223 | port = atoi(&name[pos+1]); 224 | } 225 | else 226 | rname = name; 227 | 228 | for(int n = 0; n < 2; ++n) { 229 | struct addrinfo* res; 230 | struct addrinfo hints; 231 | memset(&hints, 0, sizeof(hints)); 232 | hints.ai_socktype = SOCK_STREAM; 233 | hints.ai_family = n ? AF_INET : AF_INET6; 234 | if(hints.ai_family == AF_INET && !ipv4) 235 | continue; 236 | if(hints.ai_family == AF_INET6 && !ipv6) 237 | continue; 238 | 239 | ComboAddress remote; 240 | remote.sin4.sin_family = AF_INET6; 241 | if(!getaddrinfo(&rname[0], 0, &hints, &res)) { // this is how the getaddrinfo return code works 242 | struct addrinfo* address = res; 243 | do { 244 | if (address->ai_addrlen <= sizeof(remote)) { 245 | memcpy(&remote, (void*)address->ai_addr, address->ai_addrlen); 246 | remote.sin4.sin_port = htons(port); 247 | ret.push_back(remote); 248 | } 249 | } while((address = address->ai_next)); 250 | freeaddrinfo(res); 251 | } 252 | } 253 | return ret; 254 | } 255 | /* 256 | static auto xSecondsFromNow(double seconds) 257 | { 258 | auto now = std::chrono::steady_clock::now(); 259 | now += std::chrono::milliseconds((unsigned int)(seconds*1000)); 260 | return now; 261 | } 262 | 263 | static int msecLeft(const std::chrono::steady_clock::time_point& deadline) 264 | { 265 | auto now = std::chrono::steady_clock::now(); 266 | return std::chrono::duration_cast(deadline - now).count(); 267 | } 268 | 269 | */ 270 | std::string SReadWithDeadline(int sock, int num, const std::chrono::steady_clock::time_point& deadline) 271 | { 272 | std::string ret; 273 | char buffer[1024]; 274 | std::string::size_type leftToRead=num; 275 | 276 | for(; leftToRead;) { 277 | auto now = std::chrono::steady_clock::now(); 278 | 279 | auto msecs = std::chrono::duration_cast(deadline-now); 280 | if(msecs.count() <= 0) 281 | throw std::runtime_error("Timeout"); 282 | 283 | double toseconds = msecs.count()/1000.0; 284 | int res = waitForRWData(sock, true, &toseconds); // 0 = timeout, 1 = data, -1 error 285 | if(res == 0) 286 | throw std::runtime_error("Timeout"); 287 | if(res < 0) 288 | throw std::runtime_error("Reading with deadline: "+ std::string(strerror(errno))); 289 | 290 | auto chunk = sizeof(buffer) < leftToRead ? sizeof(buffer) : leftToRead; 291 | res = read(sock, buffer, chunk); 292 | if(res < 0) 293 | throw std::runtime_error(fmt::sprintf("Read from socket: %s", strerror(errno))); 294 | if(!res) 295 | throw std::runtime_error(fmt::sprintf("Unexpected EOF")); 296 | ret.append(buffer, res); 297 | leftToRead -= res; 298 | } 299 | return ret; 300 | } 301 | -------------------------------------------------------------------------------- /swrappers.hh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "comboaddress.hh" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /** \mainpage Simple Sockets Intro 10 | \section intro_sec Introduction 11 | From C++ the full POSIX and OS socket functions are available. These are very powerful, offer well known semantics, but are somewhat of a pain to use. 12 | 13 | Various libraries have attempted to offer "C++ native" socket environments, but most of these offer different semantics that are less well known, or frankly, obvious. 14 | 15 | This set of files offers the BSD/POSIX socket API relatively unadorned, with the original semantics, and fully interoperable 16 | with the usual system calls. 17 | 18 | To find out more about Simple Sockets, please also consult its [GitHub](https://github.com/ahuPowerDNS/simplesocket) page. 19 | 20 | \section Basic Basic example code 21 | Note that the 'raw' socket code below is just as reliable as the original socket API. In other words, it is recommended to use 22 | higher level functions. 23 | \code{.cpp} 24 | #include "swrappers.hh" 25 | 26 | int main() 27 | { 28 | int s = SSocket(AF_INET, SOCK_STREAM); 29 | ComboAddress webserver("52.48.64.3", 80); 30 | SConnect(s, webserver); 31 | SWrite(s, "GET / HTTP/1.1\r\nHost: ds9a.nl\r\nConnection: Close\r\n\r\n"); // will throw on partial write 32 | std::string response = SRead(s); // will read the entire universe into RAM 33 | cout<< response << endl; 34 | close(s); 35 | } 36 | \endcode 37 | 38 | \section Medium Slightly higher level code 39 | This sample code uses some functions that are not just wrappers, and offer more useful semantics: 40 | \code{.cpp} 41 | #include "swrappers.hh" 42 | 43 | int main() 44 | { 45 | int s = SSocket(AF_INET, SOCK_STREAM); 46 | SConnect(s, "52.48.64.3:80"_ipv4); // user literal! with constexpr! 47 | SWriten(s, "GET / HTTP/1.1\r\nHost: ds9a.nl\r\nConnection: Close\r\n\r\n"); // deals with partial writes 48 | std::string response = SRead(s, 100000); // reads at most 100k 49 | cout<< response << endl; 50 | close(s); 51 | } 52 | \endcode 53 | 54 | \section higher Some sample code using the higher-level classes 55 | \code{.cpp} 56 | auto addresses=resolveName("ds9a.nl"); // this retrieves IPv4 and IPv6 57 | 58 | for(auto& a : addresses) { 59 | a.setPort(80); 60 | cout << "Connecting to: " << a.toStringWithPort() << endl; 61 | 62 | Socket rs(a.sin.sin_family, SOCK_STREAM); 63 | SocketCommunicator sc(rs); 64 | sc.connect(a); 65 | sc.writen("GET / HTTP/1.1\r\nHost: ds9a.nl\r\nConnection: Close\r\n\r\n"); 66 | 67 | std::string line; 68 | while(sc.getLine(line)) { 69 | cout<<"Got: "<::max()); 117 | 118 | //! Set a socket to (non) blocking mode. Error = exception. 119 | void SetNonBlocking(int sockfd, bool to=true); 120 | 121 | 122 | std::map SPoll(const std::vector&rdfds, const std::vector&wrfds, double timeout); 123 | 124 | //! Use system facilities to resolve a name into addresses. If no address found, returns empty vector 125 | std::vector resolveName(const std::string& name, bool ipv4=true, bool ipv6=true); 126 | 127 | std::string SReadWithDeadline(int sock, int num, const std::chrono::steady_clock::time_point& deadline); 128 | -------------------------------------------------------------------------------- /test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "comboaddress.hh" 3 | #include "swrappers.hh" 4 | #include "sclasses.hh" 5 | #include 6 | #include 7 | using std::cout; 8 | using std::endl; 9 | 10 | void test0() 11 | { 12 | int s = SSocket(AF_INET, SOCK_STREAM); 13 | ComboAddress webserver("52.48.64.3", 80); 14 | SConnect(s, webserver); 15 | SWrite(s, "GET / HTTP/1.1\r\nHost: ds9a.nl\r\nConnection: Close\r\n\r\n"); // will throw on partial write 16 | std::string response = SRead(s); 17 | cout<< response << endl; 18 | close(s); 19 | } 20 | 21 | void test1() 22 | { 23 | int s = SSocket(AF_INET, SOCK_STREAM, 0); 24 | 25 | SBind(s, "0.0.0.0:1024"_ipv4); 26 | ComboAddress remote("52.48.64.3", 80); 27 | SConnect(s, "52.48.64.3:80"_ipv4); 28 | SetNonBlocking(s); 29 | SocketCommunicator sc(s); 30 | sc.writen("GET / HTTP/1.1\r\nHost: ds9a.nl\r\nConnection: Close\r\n\r\n"); 31 | std::string line; 32 | while(sc.getLine(line)) { 33 | cout<<"Got: "< listeners; 62 | for(int n=10000; n < 10003; ++n) { 63 | Socket sock(AF_INET6, SOCK_STREAM); 64 | SSetsockopt(sock, SOL_SOCKET, SO_REUSEADDR, true); 65 | SBind(sock, ComboAddress("::1", n)); 66 | SListen(sock, 10); 67 | listeners.push_back(std::move(sock)); 68 | } 69 | 70 | for(int t=0; t < 5; ++t) { 71 | auto av = SPoll({listeners[0], listeners[1], listeners[2]}, {}, 1.0); 72 | for(auto& a : av) { 73 | ComboAddress remote; 74 | remote.sin.sin_family = AF_INET6; 75 | Socket rs=SAccept(a.first, remote); 76 | SWriten(rs, "Hello!\r\n"); 77 | } 78 | } 79 | } 80 | 81 | void test4() 82 | { 83 | auto addresses = resolveName("www.timeapi.org"); // gets IPv4 and IPv6 84 | if(addresses.empty()) { 85 | std::cout <<"Could not resove www.timeapi.org name\n"; 86 | return; 87 | } 88 | for(auto& a : addresses) { 89 | try { 90 | a.setPort(80); 91 | Socket rs(a.sin.sin_family, SOCK_STREAM); 92 | 93 | SocketCommunicator sc(rs); 94 | sc.setTimeout(1.5); 95 | sc.connect(a); 96 | sc.writen("GET /utc/now HTTP/1.1\r\nHost: www.timeapi.org\r\nUser-Agent: simplesocket\r\nReferer: http://www.timeapi.org/\r\nConnection: Close\r\n\r\n"); 97 | std::string line; 98 | bool inheader=true; 99 | while(sc.getLine(line)) { 100 | auto pos = line.find_last_of(" \r\n"); 101 | if(pos != std::string::npos) 102 | line.resize(pos); 103 | 104 | if(inheader && line.empty()) { 105 | inheader=false; 106 | continue; 107 | } 108 | if(!inheader) 109 | std::cout << line << std::endl; 110 | } 111 | return; 112 | } 113 | catch(std::exception& e) { 114 | std::cerr <<"Failed to retrieve time from "<