summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/mfluadir/otfcc/dep
diff options
context:
space:
mode:
authorLuigi Scarso <luigi.scarso@gmail.com>2021-01-10 20:13:26 +0000
committerLuigi Scarso <luigi.scarso@gmail.com>2021-01-10 20:13:26 +0000
commit1a73c52220cf76a3e48179a1f63bc50f760ff759 (patch)
treed320a0c2c5fc1da23b18e482d74b2139fb3ea475 /Build/source/texk/web2c/mfluadir/otfcc/dep
parentb95b4fce2de8a05a4cc6e91eae12ccc164a90a30 (diff)
MFLua 1.0.0-alpha
git-svn-id: svn://tug.org/texlive/trunk@57374 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/mfluadir/otfcc/dep')
-rw-r--r--Build/source/texk/web2c/mfluadir/otfcc/dep/extern/emyg-dtoa/emyg-dtoa.c437
-rw-r--r--Build/source/texk/web2c/mfluadir/otfcc/dep/extern/emyg-dtoa/emyg-dtoa.h6
-rw-r--r--Build/source/texk/web2c/mfluadir/otfcc/dep/extern/json-builder.c889
-rw-r--r--Build/source/texk/web2c/mfluadir/otfcc/dep/extern/json.c1039
-rw-r--r--Build/source/texk/web2c/mfluadir/otfcc/dep/extern/sds.c1264
-rw-r--r--Build/source/texk/web2c/mfluadir/otfcc/dep/extern/sdsalloc.h41
6 files changed, 3676 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/emyg-dtoa/emyg-dtoa.c b/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/emyg-dtoa/emyg-dtoa.c
new file mode 100644
index 00000000000..37d328f4d37
--- /dev/null
+++ b/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/emyg-dtoa/emyg-dtoa.c
@@ -0,0 +1,437 @@
+/* emyg_dtoa.c
+** Copyright (C) 2015 Doug Currie
+** based on dtoa_milo.h
+** Copyright (C) 2014 Milo Yip
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+*/
+
+/* This code is a mostly mechanical translation of Milo Yip's C++ version of
+** Grisu2 to C. For algorithm information, see Loitsch, Florian. "Printing
+** floating-point numbers quickly and accurately with integers." ACM Sigplan
+** Notices 45.6 (2010): 233-243.
+*/
+
+#include <assert.h>
+#include <math.h>
+
+#if defined(_MSC_VER)
+#include <intrin.h>
+#endif
+
+#include <stdint.h>
+
+#include <string.h>
+
+#include "emyg-dtoa.h"
+
+#define UINT64_C2(h, l) (((uint64_t)(h) << 32) | (uint64_t)(l))
+
+typedef struct DiyFp_s {
+ uint64_t f;
+ int e;
+} DiyFp;
+
+static const int kDiySignificandSize = 64;
+static const int kDpSignificandSize = 52;
+static const int kDpExponentBias = 0x3FF + 52;
+static const int kDpMinExponent = -0x3FF - 52;
+static const uint64_t kDpExponentMask = UINT64_C2(0x7FF00000, 0x00000000);
+static const uint64_t kDpSignificandMask = UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
+static const uint64_t kDpHiddenBit = UINT64_C2(0x00100000, 0x00000000);
+
+static inline DiyFp DiyFp_from_parts(uint64_t f, int e) {
+ DiyFp fp;
+ fp.f = f;
+ fp.e = e;
+ return fp;
+}
+
+static inline DiyFp DiyFp_from_double(double d) {
+ union {
+ double d;
+ uint64_t u64;
+ } u = {d};
+ DiyFp res;
+
+ int biased_e = (int)((u.u64 & kDpExponentMask) >> kDpSignificandSize);
+ uint64_t significand = (u.u64 & kDpSignificandMask);
+ if (biased_e != 0) {
+ res.f = significand + kDpHiddenBit;
+ res.e = biased_e - kDpExponentBias;
+ } else {
+ res.f = significand;
+ res.e = kDpMinExponent + 1;
+ }
+ return res;
+}
+
+static inline DiyFp DiyFp_subtract(const DiyFp lhs, const DiyFp rhs) {
+ assert(lhs.e == rhs.e);
+ assert(lhs.f >= rhs.f);
+ return DiyFp_from_parts(lhs.f - rhs.f, lhs.e);
+}
+
+static inline DiyFp DiyFp_multiply(const DiyFp lhs, const DiyFp rhs) {
+#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__clang__)
+ uint64_t h;
+ uint64_t l = _umul128(lhs.f, rhs.f, &h);
+ if (l & ((uint64_t)(1) << 63)) { // rounding
+ h++;
+ }
+ return DiyFp_from_parts(h, lhs.e + rhs.e + 64);
+#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) && !defined(_MSC_VER)
+ unsigned __int128 p = (unsigned __int128)(lhs.f) * (unsigned __int128)(rhs.f);
+ uint64_t h = p >> 64;
+ uint64_t l = (uint64_t)(p);
+ if (l & ((uint64_t)(1) << 63)) // rounding
+ h++;
+ return DiyFp_from_parts(h, lhs.e + rhs.e + 64);
+#else
+ const uint64_t M32 = 0xFFFFFFFF;
+ const uint64_t a = lhs.f >> 32;
+ const uint64_t b = lhs.f & M32;
+ const uint64_t c = rhs.f >> 32;
+ const uint64_t d = rhs.f & M32;
+ const uint64_t ac = a * c;
+ const uint64_t bc = b * c;
+ const uint64_t ad = a * d;
+ const uint64_t bd = b * d;
+ uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
+ tmp += 1U << 31; /// mult_round
+ return DiyFp_from_parts(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), lhs.e + rhs.e + 64);
+#endif
+}
+
+static inline DiyFp Normalize(const DiyFp lhs) {
+#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__clang__)
+ unsigned long index;
+ _BitScanReverse64(&index, lhs.f);
+ return DiyFp_from_parts(lhs.f << (63 - index), lhs.e - (63 - index));
+#elif defined(__GNUC__) && !defined(_MSC_VER)
+ int s = __builtin_clzll(lhs.f);
+ return DiyFp_from_parts(lhs.f << s, lhs.e - s);
+#else
+ DiyFp res = lhs;
+ while (!(res.f & kDpHiddenBit)) {
+ res.f <<= 1;
+ res.e--;
+ }
+ res.f <<= (kDiySignificandSize - kDpSignificandSize - 1);
+ res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 1);
+ return res;
+#endif
+}
+
+static inline DiyFp NormalizeBoundary(const DiyFp lhs) {
+#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__clang__)
+ unsigned long index;
+ _BitScanReverse64(&index, lhs.f);
+ return DiyFp_from_parts(lhs.f << (63 - index), lhs.e - (63 - index));
+#else
+ DiyFp res = lhs;
+ while (!(res.f & (kDpHiddenBit << 1))) {
+ res.f <<= 1;
+ res.e--;
+ }
+ res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
+ res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
+ return res;
+#endif
+}
+
+static inline void NormalizedBoundaries(DiyFp lhs, DiyFp *minus, DiyFp *plus) {
+ DiyFp pl = NormalizeBoundary(DiyFp_from_parts((lhs.f << 1) + 1, lhs.e - 1));
+ DiyFp mi = (lhs.f == kDpHiddenBit) ? DiyFp_from_parts((lhs.f << 2) - 1, lhs.e - 2)
+ : DiyFp_from_parts((lhs.f << 1) - 1, lhs.e - 1);
+ mi.f <<= mi.e - pl.e;
+ mi.e = pl.e;
+ *plus = pl;
+ *minus = mi;
+}
+
+static inline DiyFp GetCachedPower(int e, int *K) {
+ // 10^-348, 10^-340, ..., 10^340
+ static const uint64_t kCachedPowers_F[] = {
+ UINT64_C2(0xfa8fd5a0, 0x081c0288), UINT64_C2(0xbaaee17f, 0xa23ebf76), UINT64_C2(0x8b16fb20, 0x3055ac76),
+ UINT64_C2(0xcf42894a, 0x5dce35ea), UINT64_C2(0x9a6bb0aa, 0x55653b2d), UINT64_C2(0xe61acf03, 0x3d1a45df),
+ UINT64_C2(0xab70fe17, 0xc79ac6ca), UINT64_C2(0xff77b1fc, 0xbebcdc4f), UINT64_C2(0xbe5691ef, 0x416bd60c),
+ UINT64_C2(0x8dd01fad, 0x907ffc3c), UINT64_C2(0xd3515c28, 0x31559a83), UINT64_C2(0x9d71ac8f, 0xada6c9b5),
+ UINT64_C2(0xea9c2277, 0x23ee8bcb), UINT64_C2(0xaecc4991, 0x4078536d), UINT64_C2(0x823c1279, 0x5db6ce57),
+ UINT64_C2(0xc2109436, 0x4dfb5637), UINT64_C2(0x9096ea6f, 0x3848984f), UINT64_C2(0xd77485cb, 0x25823ac7),
+ UINT64_C2(0xa086cfcd, 0x97bf97f4), UINT64_C2(0xef340a98, 0x172aace5), UINT64_C2(0xb23867fb, 0x2a35b28e),
+ UINT64_C2(0x84c8d4df, 0xd2c63f3b), UINT64_C2(0xc5dd4427, 0x1ad3cdba), UINT64_C2(0x936b9fce, 0xbb25c996),
+ UINT64_C2(0xdbac6c24, 0x7d62a584), UINT64_C2(0xa3ab6658, 0x0d5fdaf6), UINT64_C2(0xf3e2f893, 0xdec3f126),
+ UINT64_C2(0xb5b5ada8, 0xaaff80b8), UINT64_C2(0x87625f05, 0x6c7c4a8b), UINT64_C2(0xc9bcff60, 0x34c13053),
+ UINT64_C2(0x964e858c, 0x91ba2655), UINT64_C2(0xdff97724, 0x70297ebd), UINT64_C2(0xa6dfbd9f, 0xb8e5b88f),
+ UINT64_C2(0xf8a95fcf, 0x88747d94), UINT64_C2(0xb9447093, 0x8fa89bcf), UINT64_C2(0x8a08f0f8, 0xbf0f156b),
+ UINT64_C2(0xcdb02555, 0x653131b6), UINT64_C2(0x993fe2c6, 0xd07b7fac), UINT64_C2(0xe45c10c4, 0x2a2b3b06),
+ UINT64_C2(0xaa242499, 0x697392d3), UINT64_C2(0xfd87b5f2, 0x8300ca0e), UINT64_C2(0xbce50864, 0x92111aeb),
+ UINT64_C2(0x8cbccc09, 0x6f5088cc), UINT64_C2(0xd1b71758, 0xe219652c), UINT64_C2(0x9c400000, 0x00000000),
+ UINT64_C2(0xe8d4a510, 0x00000000), UINT64_C2(0xad78ebc5, 0xac620000), UINT64_C2(0x813f3978, 0xf8940984),
+ UINT64_C2(0xc097ce7b, 0xc90715b3), UINT64_C2(0x8f7e32ce, 0x7bea5c70), UINT64_C2(0xd5d238a4, 0xabe98068),
+ UINT64_C2(0x9f4f2726, 0x179a2245), UINT64_C2(0xed63a231, 0xd4c4fb27), UINT64_C2(0xb0de6538, 0x8cc8ada8),
+ UINT64_C2(0x83c7088e, 0x1aab65db), UINT64_C2(0xc45d1df9, 0x42711d9a), UINT64_C2(0x924d692c, 0xa61be758),
+ UINT64_C2(0xda01ee64, 0x1a708dea), UINT64_C2(0xa26da399, 0x9aef774a), UINT64_C2(0xf209787b, 0xb47d6b85),
+ UINT64_C2(0xb454e4a1, 0x79dd1877), UINT64_C2(0x865b8692, 0x5b9bc5c2), UINT64_C2(0xc83553c5, 0xc8965d3d),
+ UINT64_C2(0x952ab45c, 0xfa97a0b3), UINT64_C2(0xde469fbd, 0x99a05fe3), UINT64_C2(0xa59bc234, 0xdb398c25),
+ UINT64_C2(0xf6c69a72, 0xa3989f5c), UINT64_C2(0xb7dcbf53, 0x54e9bece), UINT64_C2(0x88fcf317, 0xf22241e2),
+ UINT64_C2(0xcc20ce9b, 0xd35c78a5), UINT64_C2(0x98165af3, 0x7b2153df), UINT64_C2(0xe2a0b5dc, 0x971f303a),
+ UINT64_C2(0xa8d9d153, 0x5ce3b396), UINT64_C2(0xfb9b7cd9, 0xa4a7443c), UINT64_C2(0xbb764c4c, 0xa7a44410),
+ UINT64_C2(0x8bab8eef, 0xb6409c1a), UINT64_C2(0xd01fef10, 0xa657842c), UINT64_C2(0x9b10a4e5, 0xe9913129),
+ UINT64_C2(0xe7109bfb, 0xa19c0c9d), UINT64_C2(0xac2820d9, 0x623bf429), UINT64_C2(0x80444b5e, 0x7aa7cf85),
+ UINT64_C2(0xbf21e440, 0x03acdd2d), UINT64_C2(0x8e679c2f, 0x5e44ff8f), UINT64_C2(0xd433179d, 0x9c8cb841),
+ UINT64_C2(0x9e19db92, 0xb4e31ba9), UINT64_C2(0xeb96bf6e, 0xbadf77d9), UINT64_C2(0xaf87023b, 0x9bf0ee6b)};
+ static const int16_t kCachedPowers_E[] = {
+ -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, -927, -901, -874, -847,
+ -821, -794, -768, -741, -715, -688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
+ -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, -50,
+ -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
+ 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, 641, 667, 694, 720, 747,
+ 774, 800, 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066};
+
+ // int k = (int )(ceil((-61 - e) * 0.30102999566398114)) + 374;
+ double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
+ int k = (int)(dk);
+ if (k != dk) k++;
+
+ unsigned index = (unsigned)((k >> 3) + 1);
+ *K = -(-348 + (int)(index << 3)); // decimal exponent no need lookup table
+
+ assert(index < sizeof(kCachedPowers_F) / sizeof(kCachedPowers_F[0]));
+ return DiyFp_from_parts(kCachedPowers_F[index], kCachedPowers_E[index]);
+}
+
+static inline void GrisuRound(char *buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
+ while (rest < wp_w && delta - rest >= ten_kappa && (rest + ten_kappa < wp_w || /// closer
+ wp_w - rest > rest + ten_kappa - wp_w)) {
+ buffer[len - 1]--;
+ rest += ten_kappa;
+ }
+}
+
+static inline unsigned CountDecimalDigit32(uint32_t n) {
+ // Simple pure C++ implementation was faster than __builtin_clz version in this situation.
+ if (n < 10) return 1;
+ if (n < 100) return 2;
+ if (n < 1000) return 3;
+ if (n < 10000) return 4;
+ if (n < 100000) return 5;
+ if (n < 1000000) return 6;
+ if (n < 10000000) return 7;
+ if (n < 100000000) return 8;
+ if (n < 1000000000) return 9;
+ return 10;
+}
+
+static inline void DigitGen(const DiyFp W, const DiyFp Mp, uint64_t delta, char *buffer, int *len, int *K) {
+ static const uint32_t kPow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
+ const DiyFp one = DiyFp_from_parts((uint64_t)(1) << -Mp.e, Mp.e);
+ const DiyFp wp_w = DiyFp_subtract(Mp, W);
+ uint32_t p1 = (uint32_t)(Mp.f >> -one.e);
+ uint64_t p2 = Mp.f & (one.f - 1);
+ int kappa = (int)(CountDecimalDigit32(p1));
+ *len = 0;
+
+ while (kappa > 0) {
+ uint32_t d = 0;
+ switch (kappa) {
+ case 10:
+ d = p1 / 1000000000;
+ p1 %= 1000000000;
+ break;
+ case 9:
+ d = p1 / 100000000;
+ p1 %= 100000000;
+ break;
+ case 8:
+ d = p1 / 10000000;
+ p1 %= 10000000;
+ break;
+ case 7:
+ d = p1 / 1000000;
+ p1 %= 1000000;
+ break;
+ case 6:
+ d = p1 / 100000;
+ p1 %= 100000;
+ break;
+ case 5:
+ d = p1 / 10000;
+ p1 %= 10000;
+ break;
+ case 4:
+ d = p1 / 1000;
+ p1 %= 1000;
+ break;
+ case 3:
+ d = p1 / 100;
+ p1 %= 100;
+ break;
+ case 2:
+ d = p1 / 10;
+ p1 %= 10;
+ break;
+ case 1:
+ d = p1;
+ p1 = 0;
+ break;
+ default:
+#if defined(_MSC_VER)
+ __assume(0);
+#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+ __builtin_unreachable();
+#else
+ d = 0;
+#endif
+ }
+ if (d || *len) buffer[(*len)++] = '0' + (char)(d);
+ kappa--;
+ uint64_t tmp = ((uint64_t)(p1) << -one.e) + p2;
+ if (tmp <= delta) {
+ *K += kappa;
+ GrisuRound(buffer, *len, delta, tmp, (uint64_t)(kPow10[kappa]) << -one.e, wp_w.f);
+ return;
+ }
+ }
+
+ // kappa = 0
+ for (;;) {
+ p2 *= 10;
+ delta *= 10;
+ char d = (char)(p2 >> -one.e);
+ if (d || *len) buffer[(*len)++] = '0' + d;
+ p2 &= one.f - 1;
+ kappa--;
+ if (p2 < delta) {
+ *K += kappa;
+ GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]);
+ return;
+ }
+ }
+}
+
+static inline void Grisu2(double value, char *buffer, int *length, int *K) {
+ const DiyFp v = DiyFp_from_double(value);
+ DiyFp w_m, w_p;
+ NormalizedBoundaries(v, &w_m, &w_p);
+
+ const DiyFp c_mk = GetCachedPower(w_p.e, K);
+ const DiyFp W = DiyFp_multiply(Normalize(v), c_mk);
+ DiyFp Wp = DiyFp_multiply(w_p, c_mk);
+ DiyFp Wm = DiyFp_multiply(w_m, c_mk);
+ Wm.f++;
+ Wp.f--;
+ DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
+}
+
+static inline const char *GetDigitsLut() {
+ static const char cDigitsLut[200] = {
+ '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
+ '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
+ '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
+ '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
+ '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
+ '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
+ '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
+ '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
+ '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
+ '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'};
+ return cDigitsLut;
+}
+
+static inline void WriteExponent(int K, char *buffer) {
+ if (K < 0) {
+ *buffer++ = '-';
+ K = -K;
+ }
+
+ if (K >= 100) {
+ *buffer++ = '0' + (char)(K / 100);
+ K %= 100;
+ const char *d = GetDigitsLut() + K * 2;
+ *buffer++ = d[0];
+ *buffer++ = d[1];
+ } else if (K >= 10) {
+ const char *d = GetDigitsLut() + K * 2;
+ *buffer++ = d[0];
+ *buffer++ = d[1];
+ } else
+ *buffer++ = '0' + (char)(K);
+
+ *buffer = '\0';
+}
+
+static inline void Prettify(char *buffer, int length, int k) {
+ const int kk = length + k; // 10^(kk-1) <= v < 10^kk
+
+ if (length <= kk && kk <= 21) {
+ // 1234e7 -> 12340000000
+ for (int i = length; i < kk; i++)
+ buffer[i] = '0';
+ buffer[kk] = '.';
+ buffer[kk + 1] = '0';
+ buffer[kk + 2] = '\0';
+ } else if (0 < kk && kk <= 21) {
+ // 1234e-2 -> 12.34
+ memmove(&buffer[kk + 1], &buffer[kk], length - kk);
+ buffer[kk] = '.';
+ buffer[length + 1] = '\0';
+ } else if (-6 < kk && kk <= 0) {
+ // 1234e-6 -> 0.001234
+ const int offset = 2 - kk;
+ memmove(&buffer[offset], &buffer[0], length);
+ buffer[0] = '0';
+ buffer[1] = '.';
+ for (int i = 2; i < offset; i++)
+ buffer[i] = '0';
+ buffer[length + offset] = '\0';
+ } else if (length == 1) {
+ // 1e30
+ buffer[1] = 'e';
+ WriteExponent(kk - 1, &buffer[2]);
+ } else {
+ // 1234e30 -> 1.234e33
+ memmove(&buffer[2], &buffer[1], length - 1);
+ buffer[1] = '.';
+ buffer[length + 1] = 'e';
+ WriteExponent(kk - 1, &buffer[0 + length + 2]);
+ }
+}
+
+void emyg_dtoa(double value, char *buffer) {
+ // Not handling NaN and inf
+ assert(!isnan(value));
+ assert(!isinf(value));
+
+ if (value == 0) {
+ buffer[0] = '0';
+ buffer[1] = '.';
+ buffer[2] = '0';
+ buffer[3] = '\0';
+ } else {
+ if (value < 0) {
+ *buffer++ = '-';
+ value = -value;
+ }
+ int length, K;
+ Grisu2(value, buffer, &length, &K);
+ Prettify(buffer, length, K);
+ }
+}
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/emyg-dtoa/emyg-dtoa.h b/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/emyg-dtoa/emyg-dtoa.h
new file mode 100644
index 00000000000..f9ff35bede8
--- /dev/null
+++ b/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/emyg-dtoa/emyg-dtoa.h
@@ -0,0 +1,6 @@
+#ifndef CARYLL_DEP_EMYG_DTOA_H
+#define CARYLL_DEP_EMYG_DTOA_H
+
+void emyg_dtoa(double value, char *buffer);
+
+#endif
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/json-builder.c b/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/json-builder.c
new file mode 100644
index 00000000000..9e36667bafd
--- /dev/null
+++ b/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/json-builder.c
@@ -0,0 +1,889 @@
+
+/* vim: set et ts=3 sw=3 sts=3 ft=c:
+ *
+ * Copyright (C) 2014 James McLaughlin. All rights reserved.
+ * https://github.com/udp/json-builder
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "json-builder.h"
+#include "emyg-dtoa/emyg-dtoa.h"
+
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include <math.h>
+
+#ifdef _MSC_VER
+#define snprintf _snprintf
+#endif
+
+const static json_serialize_opts default_opts = {
+ json_serialize_mode_single_line, 0, 3 /* indent_size */
+};
+
+typedef struct json_builder_value {
+ json_value value;
+
+ int is_builder_value;
+
+ size_t additional_length_allocated;
+ size_t length_iterated;
+
+} json_builder_value;
+
+static int builderize(json_value *value) {
+ if (((json_builder_value *)value)->is_builder_value) return 1;
+
+ if (value->type == json_object) {
+ unsigned int i;
+
+ /* Values straight out of the parser have the names of object entries
+ * allocated in the same allocation as the values array itself. This is
+ * not desirable when manipulating values because the names would be easy
+ * to clobber.
+ */
+ for (i = 0; i < value->u.object.length; ++i) {
+ json_char *name_copy;
+ json_object_entry *entry = &value->u.object.values[i];
+
+ if (!(name_copy = (json_char *)malloc((entry->name_length + 1) * sizeof(json_char)))) return 0;
+
+ memcpy(name_copy, entry->name, entry->name_length + 1);
+ entry->name = name_copy;
+ }
+ }
+
+ ((json_builder_value *)value)->is_builder_value = 1;
+
+ return 1;
+}
+
+const size_t json_builder_extra = sizeof(json_builder_value) - sizeof(json_value);
+
+/* These flags are set up from the opts before serializing to make the
+ * serializer conditions simpler.
+ */
+const int f_spaces_around_brackets = (1 << 0);
+const int f_spaces_after_commas = (1 << 1);
+const int f_spaces_after_colons = (1 << 2);
+const int f_tabs = (1 << 3);
+
+static int get_serialize_flags(json_serialize_opts opts) {
+ int flags = 0;
+
+ if (opts.mode == json_serialize_mode_packed) return 0;
+
+ if (opts.mode == json_serialize_mode_multiline) {
+ if (opts.opts & json_serialize_opt_use_tabs) flags |= f_tabs;
+ } else {
+ if (!(opts.opts & json_serialize_opt_pack_brackets)) flags |= f_spaces_around_brackets;
+
+ if (!(opts.opts & json_serialize_opt_no_space_after_comma)) flags |= f_spaces_after_commas;
+ }
+
+ if (!(opts.opts & json_serialize_opt_no_space_after_colon)) flags |= f_spaces_after_colons;
+
+ return flags;
+}
+
+json_value *json_array_new(size_t length) {
+ json_value *value = (json_value *)calloc(1, sizeof(json_builder_value));
+
+ if (!value) return NULL;
+
+ ((json_builder_value *)value)->is_builder_value = 1;
+
+ value->type = json_array;
+
+ if (!(value->u.array.values = (json_value **)malloc(length * sizeof(json_value *)))) {
+ free(value);
+ return NULL;
+ }
+
+ ((json_builder_value *)value)->additional_length_allocated = length;
+
+ return value;
+}
+
+json_value *json_array_push(json_value *array, json_value *value) {
+ assert(array->type == json_array);
+
+ if (!builderize(array) || !builderize(value)) return NULL;
+
+ if (((json_builder_value *)array)->additional_length_allocated > 0) {
+ --((json_builder_value *)array)->additional_length_allocated;
+ } else {
+ json_value **values_new =
+ (json_value **)realloc(array->u.array.values, sizeof(json_value *) * (array->u.array.length + 1));
+
+ if (!values_new) return NULL;
+
+ array->u.array.values = values_new;
+ }
+
+ array->u.array.values[array->u.array.length] = value;
+ ++array->u.array.length;
+
+ value->parent = array;
+
+ return value;
+}
+
+json_value *json_object_new(size_t length) {
+ json_value *value = (json_value *)calloc(1, sizeof(json_builder_value));
+
+ if (!value) return NULL;
+
+ ((json_builder_value *)value)->is_builder_value = 1;
+
+ value->type = json_object;
+
+ if (!(value->u.object.values = (json_object_entry *)calloc(length, sizeof(*value->u.object.values)))) {
+ free(value);
+ return NULL;
+ }
+
+ ((json_builder_value *)value)->additional_length_allocated = length;
+
+ return value;
+}
+
+json_value *json_object_push(json_value *object, const json_char *name, json_value *value) {
+ return json_object_push_length(object, strlen(name), name, value);
+}
+
+json_value *json_object_push_length(json_value *object, unsigned int name_length, const json_char *name,
+ json_value *value) {
+ json_char *name_copy;
+
+ assert(object->type == json_object);
+
+ if (!(name_copy = (json_char *)malloc((name_length + 1) * sizeof(json_char)))) return NULL;
+
+ memcpy(name_copy, name, name_length * sizeof(json_char));
+ name_copy[name_length] = 0;
+
+ if (!json_object_push_nocopy(object, name_length, name_copy, value)) {
+ free(name_copy);
+ return NULL;
+ }
+
+ return value;
+}
+
+json_value *json_object_push_nocopy(json_value *object, unsigned int name_length, json_char *name, json_value *value) {
+ json_object_entry *entry;
+
+ assert(object->type == json_object);
+
+ if (!builderize(object) || !builderize(value)) return NULL;
+
+ if (((json_builder_value *)object)->additional_length_allocated > 0) {
+ --((json_builder_value *)object)->additional_length_allocated;
+ } else {
+ json_object_entry *values_new = (json_object_entry *)realloc(
+ object->u.object.values, sizeof(*object->u.object.values) * (object->u.object.length + 1));
+
+ if (!values_new) return NULL;
+
+ object->u.object.values = values_new;
+ }
+
+ entry = object->u.object.values + object->u.object.length;
+
+ entry->name_length = name_length;
+ entry->name = name;
+ entry->value = value;
+
+ ++object->u.object.length;
+
+ value->parent = object;
+
+ return value;
+}
+
+json_value *json_string_new(const json_char *buf) {
+ return json_string_new_length(strlen(buf), buf);
+}
+
+json_value *json_string_new_length(unsigned int length, const json_char *buf) {
+ json_value *value;
+ json_char *copy = (json_char *)malloc((length + 1) * sizeof(json_char));
+
+ if (!copy) return NULL;
+
+ memcpy(copy, buf, length * sizeof(json_char));
+ copy[length] = 0;
+
+ if (!(value = json_string_new_nocopy(length, copy))) {
+ free(copy);
+ return NULL;
+ }
+
+ return value;
+}
+
+json_value *json_string_new_nocopy(unsigned int length, json_char *buf) {
+ json_value *value = (json_value *)calloc(1, sizeof(json_builder_value));
+
+ if (!value) return NULL;
+
+ ((json_builder_value *)value)->is_builder_value = 1;
+
+ value->type = json_string;
+ value->u.string.length = length;
+ value->u.string.ptr = buf;
+
+ return value;
+}
+
+json_value *json_integer_new(json_int_t integer) {
+ json_value *value = (json_value *)calloc(1, sizeof(json_builder_value));
+
+ if (!value) return NULL;
+
+ ((json_builder_value *)value)->is_builder_value = 1;
+
+ value->type = json_integer;
+ value->u.integer = integer;
+
+ return value;
+}
+
+json_value *json_double_new(double dbl) {
+ json_value *value = (json_value *)calloc(1, sizeof(json_builder_value));
+
+ if (!value) return NULL;
+
+ ((json_builder_value *)value)->is_builder_value = 1;
+
+ value->type = json_double;
+ value->u.dbl = dbl;
+
+ return value;
+}
+
+json_value *json_boolean_new(int b) {
+ json_value *value = (json_value *)calloc(1, sizeof(json_builder_value));
+
+ if (!value) return NULL;
+
+ ((json_builder_value *)value)->is_builder_value = 1;
+
+ value->type = json_boolean;
+ value->u.boolean = b;
+
+ return value;
+}
+
+json_value *json_null_new(void) {
+ json_value *value = (json_value *)calloc(1, sizeof(json_builder_value));
+
+ if (!value) return NULL;
+
+ ((json_builder_value *)value)->is_builder_value = 1;
+
+ value->type = json_null;
+
+ return value;
+}
+
+void json_object_sort(json_value *object, json_value *proto) {
+ unsigned int i, out_index = 0;
+
+ if (!builderize(object)) return; /* TODO error */
+
+ assert(object->type == json_object);
+ assert(proto->type == json_object);
+
+ for (i = 0; i < proto->u.object.length; ++i) {
+ unsigned int j;
+ json_object_entry proto_entry = proto->u.object.values[i];
+
+ for (j = 0; j < object->u.object.length; ++j) {
+ json_object_entry entry = object->u.object.values[j];
+
+ if (entry.name_length != proto_entry.name_length) continue;
+
+ if (memcmp(entry.name, proto_entry.name, entry.name_length) != 0) continue;
+
+ object->u.object.values[j] = object->u.object.values[out_index];
+ object->u.object.values[out_index] = entry;
+
+ ++out_index;
+ }
+ }
+}
+
+json_value *json_object_merge(json_value *objectA, json_value *objectB) {
+ unsigned int i;
+
+ assert(objectA->type == json_object);
+ assert(objectB->type == json_object);
+ assert(objectA != objectB);
+
+ if (!builderize(objectA) || !builderize(objectB)) return NULL;
+
+ if (objectB->u.object.length <= ((json_builder_value *)objectA)->additional_length_allocated) {
+ ((json_builder_value *)objectA)->additional_length_allocated -= objectB->u.object.length;
+ } else {
+ json_object_entry *values_new;
+
+ unsigned int alloc = objectA->u.object.length + ((json_builder_value *)objectA)->additional_length_allocated +
+ objectB->u.object.length;
+
+ if (!(values_new = (json_object_entry *)realloc(objectA->u.object.values, sizeof(json_object_entry) * alloc))) {
+ return NULL;
+ }
+
+ objectA->u.object.values = values_new;
+ }
+
+ for (i = 0; i < objectB->u.object.length; ++i) {
+ json_object_entry *entry = &objectA->u.object.values[objectA->u.object.length + i];
+
+ *entry = objectB->u.object.values[i];
+ entry->value->parent = objectA;
+ }
+
+ objectA->u.object.length += objectB->u.object.length;
+
+ free(objectB->u.object.values);
+ free(objectB);
+
+ return objectA;
+}
+
+static size_t measure_string(unsigned int length, const json_char *str) {
+ unsigned int i;
+ size_t measured_length = 0;
+
+ for (i = 0; i < length; ++i) {
+ json_char c = str[i];
+
+ switch (c) {
+ case 0:
+ case 0xb:
+ measured_length += 6;
+ break;
+ case '"':
+ case '\\':
+ case '\b':
+ case '\f':
+ case '\n':
+ case '\r':
+ case '\t':
+
+ measured_length += 2;
+ break;
+
+ default:
+
+ ++measured_length;
+ break;
+ };
+ };
+
+ return measured_length;
+}
+
+#define PRINT_ESCAPED(c) \
+ do { \
+ *buf++ = '\\'; \
+ *buf++ = (c); \
+ } while (0);
+
+static size_t serialize_string(json_char *buf, unsigned int length, const json_char *str) {
+ json_char *orig_buf = buf;
+ unsigned int i;
+
+ for (i = 0; i < length; ++i) {
+ json_char c = str[i];
+
+ switch (c) {
+ case 0:
+ *buf++ = '\\';
+ *buf++ = 'u';
+ *buf++ = '0';
+ *buf++ = '0';
+ *buf++ = '0';
+ *buf++ = '0';
+ continue;
+ case '"':
+ PRINT_ESCAPED('\"');
+ continue;
+ case '\\':
+ PRINT_ESCAPED('\\');
+ continue;
+ case '\b':
+ PRINT_ESCAPED('b');
+ continue;
+ case '\f':
+ PRINT_ESCAPED('f');
+ continue;
+ case '\n':
+ PRINT_ESCAPED('n');
+ continue;
+ case '\r':
+ PRINT_ESCAPED('r');
+ continue;
+ case '\t':
+ PRINT_ESCAPED('t');
+ continue;
+ case 0xb:
+ *buf++ = '\\';
+ *buf++ = 'u';
+ *buf++ = '0';
+ *buf++ = '0';
+ *buf++ = '0';
+ *buf++ = 'b';
+ continue;
+
+ default:
+
+ *buf++ = c;
+ break;
+ };
+ };
+
+ return buf - orig_buf;
+}
+
+size_t json_measure(json_value *value) {
+ return json_measure_ex(value, default_opts);
+}
+
+#define MEASURE_NEWLINE() \
+ do { \
+ ++newlines; \
+ indents += depth; \
+ } while (0);
+
+size_t json_measure_ex(json_value *value, json_serialize_opts opts) {
+ size_t total = 1; /* null terminator */
+ size_t newlines = 0;
+ size_t depth = 0;
+ size_t indents = 0;
+ int flags;
+ int bracket_size, comma_size, colon_size;
+
+ flags = get_serialize_flags(opts);
+
+ /* to reduce branching
+ */
+ bracket_size = flags & f_spaces_around_brackets ? 2 : 1;
+ comma_size = flags & f_spaces_after_commas ? 2 : 1;
+ colon_size = flags & f_spaces_after_colons ? 2 : 1;
+
+ while (value) {
+ json_int_t integer;
+ json_object_entry *entry;
+
+ switch (value->type) {
+ case json_array:
+
+ if (((json_builder_value *)value)->length_iterated == 0) {
+ if (value->u.array.length == 0) {
+ total += 2; /* `[]` */
+ break;
+ }
+
+ total += bracket_size; /* `[` */
+
+ ++depth;
+ MEASURE_NEWLINE(); /* \n after [ */
+ }
+
+ if (((json_builder_value *)value)->length_iterated == value->u.array.length) {
+ --depth;
+ MEASURE_NEWLINE();
+ total += bracket_size; /* `]` */
+
+ ((json_builder_value *)value)->length_iterated = 0;
+ break;
+ }
+
+ if (((json_builder_value *)value)->length_iterated > 0) {
+ total += comma_size; /* `, ` */
+
+ MEASURE_NEWLINE();
+ }
+
+ ((json_builder_value *)value)->length_iterated++;
+ value = value->u.array.values[((json_builder_value *)value)->length_iterated - 1];
+ continue;
+
+ case json_object:
+
+ if (((json_builder_value *)value)->length_iterated == 0) {
+ if (value->u.object.length == 0) {
+ total += 2; /* `{}` */
+ break;
+ }
+
+ total += bracket_size; /* `{` */
+
+ ++depth;
+ MEASURE_NEWLINE(); /* \n after { */
+ }
+
+ if (((json_builder_value *)value)->length_iterated == value->u.object.length) {
+ --depth;
+ MEASURE_NEWLINE();
+ total += bracket_size; /* `}` */
+
+ ((json_builder_value *)value)->length_iterated = 0;
+ break;
+ }
+
+ if (((json_builder_value *)value)->length_iterated > 0) {
+ total += comma_size; /* `, ` */
+ MEASURE_NEWLINE();
+ }
+
+ entry = value->u.object.values + (((json_builder_value *)value)->length_iterated++);
+
+ total += 2 + colon_size; /* `"": ` */
+ total += measure_string(entry->name_length, entry->name);
+
+ value = entry->value;
+ continue;
+#ifdef CARYLL_USE_PRE_SERIALIZED
+ case json_pre_serialized:
+
+ total += value->u.string.length;
+ break;
+#endif
+ case json_string:
+ total += 2; /* `""` */
+ total += measure_string(value->u.string.length, value->u.string.ptr);
+ break;
+
+ case json_integer:
+
+ integer = value->u.integer;
+
+ if (integer < 0) {
+ total += 1; /* `-` */
+ integer = -integer;
+ }
+
+ ++total; /* first digit */
+
+ while (integer >= 10) {
+ ++total; /* another digit */
+ integer /= 10;
+ }
+
+ break;
+
+ case json_double: {
+ char buffer[256];
+ emyg_dtoa(value->u.dbl, buffer);
+ total += strlen(buffer);
+ break;
+ }
+
+ case json_boolean:
+
+ total += value->u.boolean ? 4 : /* `true` */
+ 5; /* `false` */
+
+ break;
+
+ case json_null:
+
+ total += 4; /* `null` */
+ break;
+
+ default:
+ break;
+ };
+
+ value = value->parent;
+ }
+
+ if (opts.mode == json_serialize_mode_multiline) {
+ total += newlines * (((opts.opts & json_serialize_opt_CRLF) ? 2 : 1) + opts.indent_size);
+ total += indents * opts.indent_size;
+ }
+
+ return total;
+}
+
+void json_serialize(json_char *buf, json_value *value) {
+ json_serialize_ex(buf, value, default_opts);
+}
+
+#define PRINT_NEWLINE() \
+ do { \
+ if (opts.mode == json_serialize_mode_multiline) { \
+ if (opts.opts & json_serialize_opt_CRLF) *buf++ = '\r'; \
+ *buf++ = '\n'; \
+ for (i = 0; i < indent; ++i) \
+ *buf++ = indent_char; \
+ } \
+ } while (0);
+
+#define PRINT_OPENING_BRACKET(c) \
+ do { \
+ *buf++ = (c); \
+ if (flags & f_spaces_around_brackets) *buf++ = ' '; \
+ } while (0);
+
+#define PRINT_CLOSING_BRACKET(c) \
+ do { \
+ if (flags & f_spaces_around_brackets) *buf++ = ' '; \
+ *buf++ = (c); \
+ } while (0);
+
+void json_serialize_ex(json_char *buf, json_value *value, json_serialize_opts opts) {
+ json_int_t integer, orig_integer;
+ json_object_entry *entry;
+ json_char *ptr;
+ int indent = 0;
+ char indent_char;
+ int i;
+ int flags;
+
+ flags = get_serialize_flags(opts);
+
+ indent_char = flags & f_tabs ? '\t' : ' ';
+
+ while (value) {
+ switch (value->type) {
+ case json_array:
+
+ if (((json_builder_value *)value)->length_iterated == 0) {
+ if (value->u.array.length == 0) {
+ *buf++ = '[';
+ *buf++ = ']';
+
+ break;
+ }
+
+ PRINT_OPENING_BRACKET('[');
+
+ indent += opts.indent_size;
+ PRINT_NEWLINE();
+ }
+
+ if (((json_builder_value *)value)->length_iterated == value->u.array.length) {
+ indent -= opts.indent_size;
+ PRINT_NEWLINE();
+ PRINT_CLOSING_BRACKET(']');
+
+ ((json_builder_value *)value)->length_iterated = 0;
+ break;
+ }
+
+ if (((json_builder_value *)value)->length_iterated > 0) {
+ *buf++ = ',';
+
+ if (flags & f_spaces_after_commas) *buf++ = ' ';
+
+ PRINT_NEWLINE();
+ }
+
+ ((json_builder_value *)value)->length_iterated++;
+ value = value->u.array.values[((json_builder_value *)value)->length_iterated - 1];
+ continue;
+
+ case json_object:
+
+ if (((json_builder_value *)value)->length_iterated == 0) {
+ if (value->u.object.length == 0) {
+ *buf++ = '{';
+ *buf++ = '}';
+
+ break;
+ }
+
+ PRINT_OPENING_BRACKET('{');
+
+ indent += opts.indent_size;
+ PRINT_NEWLINE();
+ }
+
+ if (((json_builder_value *)value)->length_iterated == value->u.object.length) {
+ indent -= opts.indent_size;
+ PRINT_NEWLINE();
+ PRINT_CLOSING_BRACKET('}');
+
+ ((json_builder_value *)value)->length_iterated = 0;
+ break;
+ }
+
+ if (((json_builder_value *)value)->length_iterated > 0) {
+ *buf++ = ',';
+
+ if (flags & f_spaces_after_commas) *buf++ = ' ';
+
+ PRINT_NEWLINE();
+ }
+
+ entry = value->u.object.values + (((json_builder_value *)value)->length_iterated++);
+
+ *buf++ = '\"';
+ buf += serialize_string(buf, entry->name_length, entry->name);
+ *buf++ = '\"';
+ *buf++ = ':';
+
+ if (flags & f_spaces_after_colons) *buf++ = ' ';
+
+ value = entry->value;
+ continue;
+#ifdef CARYLL_USE_PRE_SERIALIZED
+ case json_pre_serialized:
+ memcpy(buf, value->u.string.ptr, value->u.string.length);
+ buf += value->u.string.length;
+ break;
+#endif
+ case json_string:
+
+ *buf++ = '\"';
+ buf += serialize_string(buf, value->u.string.length, value->u.string.ptr);
+ *buf++ = '\"';
+ break;
+
+ case json_integer:
+
+ integer = value->u.integer;
+
+ if (integer < 0) {
+ *buf++ = '-';
+ integer = -integer;
+ }
+
+ orig_integer = integer;
+
+ ++buf;
+
+ while (integer >= 10) {
+ ++buf;
+ integer /= 10;
+ }
+
+ integer = orig_integer;
+ ptr = buf;
+
+ do {
+ *--ptr = "0123456789"[integer % 10];
+ } while ((integer /= 10) > 0);
+
+ break;
+
+ case json_double: {
+ char tmp[256];
+ emyg_dtoa(value->u.dbl, tmp);
+ memcpy(buf, tmp, strlen(tmp));
+ buf += strlen(tmp);
+ break;
+ }
+
+ case json_boolean:
+
+ if (value->u.boolean) {
+ memcpy(buf, "true", 4);
+ buf += 4;
+ } else {
+ memcpy(buf, "false", 5);
+ buf += 5;
+ }
+
+ break;
+
+ case json_null:
+
+ memcpy(buf, "null", 4);
+ buf += 4;
+ break;
+
+ default:
+ break;
+ };
+
+ value = value->parent;
+ }
+
+ *buf = 0;
+}
+
+void json_builder_free(json_value *value) {
+ json_value *cur_value;
+
+ if (!value) return;
+
+ value->parent = 0;
+
+ while (value) {
+ switch (value->type) {
+ case json_array:
+
+ if (!value->u.array.length) {
+ free(value->u.array.values);
+ break;
+ }
+
+ value = value->u.array.values[--value->u.array.length];
+ continue;
+
+ case json_object:
+
+ if (!value->u.object.length) {
+ free(value->u.object.values);
+ break;
+ }
+
+ --value->u.object.length;
+
+ if (((json_builder_value *)value)->is_builder_value) {
+ /* Names are allocated separately for builder values. In parser
+ * values, they are part of the same allocation as the values array
+ * itself.
+ */
+ free(value->u.object.values[value->u.object.length].name);
+ }
+
+ value = value->u.object.values[value->u.object.length].value;
+ continue;
+
+ case json_string:
+#ifdef CARYLL_USE_PRE_SERIALIZED
+ case json_pre_serialized:
+#endif
+ free(value->u.string.ptr);
+ break;
+
+ default:
+ break;
+ };
+
+ cur_value = value;
+ value = value->parent;
+ free(cur_value);
+ }
+}
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/json.c b/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/json.c
new file mode 100644
index 00000000000..4f6bcfe8d50
--- /dev/null
+++ b/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/json.c
@@ -0,0 +1,1039 @@
+/* vim: set et ts=3 sw=3 sts=3 ft=c:
+ *
+ * Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved.
+ * https://github.com/udp/json-parser
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "json.h"
+
+#ifdef _MSC_VER
+ #ifndef _CRT_SECURE_NO_WARNINGS
+ #define _CRT_SECURE_NO_WARNINGS
+ #endif
+#endif
+
+const struct _json_value json_value_none;
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+
+typedef unsigned int json_uchar;
+
+static unsigned char hex_value (json_char c)
+{
+ if (isdigit(c))
+ return c - '0';
+
+ switch (c) {
+ case 'a': case 'A': return 0x0A;
+ case 'b': case 'B': return 0x0B;
+ case 'c': case 'C': return 0x0C;
+ case 'd': case 'D': return 0x0D;
+ case 'e': case 'E': return 0x0E;
+ case 'f': case 'F': return 0x0F;
+ default: return 0xFF;
+ }
+}
+
+typedef struct
+{
+ unsigned long used_memory;
+
+ unsigned int uint_max;
+ unsigned long ulong_max;
+
+ json_settings settings;
+ int first_pass;
+
+ const json_char * ptr;
+ unsigned int cur_line, cur_col;
+
+} json_state;
+
+static void * default_alloc (size_t size, int zero, void * user_data)
+{
+ return zero ? calloc (1, size) : malloc (size);
+}
+
+static void default_free (void * ptr, void * user_data)
+{
+ free (ptr);
+}
+
+static void * json_alloc (json_state * state, unsigned long size, int zero)
+{
+ if ((state->ulong_max - state->used_memory) < size)
+ return 0;
+
+ if (state->settings.max_memory
+ && (state->used_memory += size) > state->settings.max_memory)
+ {
+ return 0;
+ }
+
+ return state->settings.mem_alloc (size, zero, state->settings.user_data);
+}
+
+static int new_value (json_state * state,
+ json_value ** top, json_value ** root, json_value ** alloc,
+ json_type type)
+{
+ json_value * value;
+ int values_size;
+
+ if (!state->first_pass)
+ {
+ value = *top = *alloc;
+ *alloc = (*alloc)->_reserved.next_alloc;
+
+ if (!*root)
+ *root = value;
+
+ switch (value->type)
+ {
+ case json_array:
+
+ if (value->u.array.length == 0)
+ break;
+
+ if (! (value->u.array.values = (json_value **) json_alloc
+ (state, value->u.array.length * sizeof (json_value *), 0)) )
+ {
+ return 0;
+ }
+
+ value->u.array.length = 0;
+ break;
+
+ case json_object:
+
+ if (value->u.object.length == 0)
+ break;
+
+ values_size = sizeof (*value->u.object.values) * value->u.object.length;
+
+ if (! (value->u.object.values = (json_object_entry *) json_alloc
+ (state, values_size + ((uintptr_t) value->u.object.values), 0)) )
+ {
+ return 0;
+ }
+
+ value->_reserved.object_mem = (*(char **) &value->u.object.values) + values_size;
+
+ value->u.object.length = 0;
+ break;
+
+ case json_string:
+
+ if (! (value->u.string.ptr = (json_char *) json_alloc
+ (state, (value->u.string.length + 1) * sizeof (json_char), 0)) )
+ {
+ return 0;
+ }
+
+ value->u.string.length = 0;
+ break;
+
+ default:
+ break;
+ };
+
+ return 1;
+ }
+
+ if (! (value = (json_value *) json_alloc
+ (state, sizeof (json_value) + state->settings.value_extra, 1)))
+ {
+ return 0;
+ }
+
+ if (!*root)
+ *root = value;
+
+ value->type = type;
+ value->parent = *top;
+
+ #ifdef JSON_TRACK_SOURCE
+ value->line = state->cur_line;
+ value->col = state->cur_col;
+ #endif
+
+ if (*alloc)
+ (*alloc)->_reserved.next_alloc = value;
+
+ *alloc = *top = value;
+
+ return 1;
+}
+
+#define whitespace \
+ case '\n': ++ state.cur_line; state.cur_col = 0; \
+ case ' ': case '\t': case '\r'
+
+#define string_add(b) \
+ do { if (!state.first_pass) string [string_length] = b; ++ string_length; } while (0);
+
+#define line_and_col \
+ state.cur_line, state.cur_col
+
+static const long
+ flag_next = 1 << 0,
+ flag_reproc = 1 << 1,
+ flag_need_comma = 1 << 2,
+ flag_seek_value = 1 << 3,
+ flag_escaped = 1 << 4,
+ flag_string = 1 << 5,
+ flag_need_colon = 1 << 6,
+ flag_done = 1 << 7,
+ flag_num_negative = 1 << 8,
+ flag_num_zero = 1 << 9,
+ flag_num_e = 1 << 10,
+ flag_num_e_got_sign = 1 << 11,
+ flag_num_e_negative = 1 << 12,
+ flag_line_comment = 1 << 13,
+ flag_block_comment = 1 << 14;
+
+json_value * json_parse_ex (json_settings * settings,
+ const json_char * json,
+ size_t length,
+ char * error_buf)
+{
+ json_char error [json_error_max];
+ const json_char * end;
+ json_value * top, * root, * alloc = 0;
+ json_state state;
+ state.used_memory = 0;
+ state.uint_max = 0;
+ state.ulong_max = 0;
+ state.settings.max_memory = 0;
+ state.settings.mem_alloc = NULL;
+ state.settings.mem_free = NULL;
+ state.settings.settings = 0;
+ state.settings.user_data = NULL;
+ state.settings.value_extra = 0;
+ state.first_pass = 0;
+ state.ptr = NULL;
+ state.cur_col = 0;
+ state.cur_line = 0;
+
+ long flags;
+ long num_digits = 0, num_e = 0;
+ json_int_t num_fraction = 0;
+
+ /* Skip UTF-8 BOM
+ */
+ if (length >= 3 && ((unsigned char) json [0]) == 0xEF
+ && ((unsigned char) json [1]) == 0xBB
+ && ((unsigned char) json [2]) == 0xBF)
+ {
+ json += 3;
+ length -= 3;
+ }
+
+ error[0] = '\0';
+ end = (json + length);
+
+ memcpy (&state.settings, settings, sizeof (json_settings));
+
+ if (!state.settings.mem_alloc)
+ state.settings.mem_alloc = default_alloc;
+
+ if (!state.settings.mem_free)
+ state.settings.mem_free = default_free;
+
+ memset (&state.uint_max, 0xFF, sizeof (state.uint_max));
+ memset (&state.ulong_max, 0xFF, sizeof (state.ulong_max));
+
+ state.uint_max -= 8; /* limit of how much can be added before next check */
+ state.ulong_max -= 8;
+
+ for (state.first_pass = 1; state.first_pass >= 0; -- state.first_pass)
+ {
+ json_uchar uchar;
+ unsigned char uc_b1, uc_b2, uc_b3, uc_b4;
+ json_char * string = 0;
+ unsigned int string_length = 0;
+
+ top = root = 0;
+ flags = flag_seek_value;
+
+ state.cur_line = 1;
+
+ for (state.ptr = json ;; ++ state.ptr)
+ {
+ json_char b = (state.ptr == end ? 0 : *state.ptr);
+
+ if (flags & flag_string)
+ {
+ if (!b)
+ { sprintf (error, "Unexpected EOF in string (at %d:%d)", line_and_col);
+ goto e_failed;
+ }
+
+ if (string_length > state.uint_max)
+ goto e_overflow;
+
+ if (flags & flag_escaped)
+ {
+ flags &= ~ flag_escaped;
+
+ switch (b)
+ {
+ case 'b': string_add ('\b'); break;
+ case 'f': string_add ('\f'); break;
+ case 'n': string_add ('\n'); break;
+ case 'r': string_add ('\r'); break;
+ case 't': string_add ('\t'); break;
+ case 'u':
+
+ if (end - state.ptr < 4 ||
+ (uc_b1 = hex_value (*++ state.ptr)) == 0xFF ||
+ (uc_b2 = hex_value (*++ state.ptr)) == 0xFF ||
+ (uc_b3 = hex_value (*++ state.ptr)) == 0xFF ||
+ (uc_b4 = hex_value (*++ state.ptr)) == 0xFF)
+ {
+ sprintf (error, "Invalid character value `%c` (at %d:%d)", b, line_and_col);
+ goto e_failed;
+ }
+
+ uc_b1 = (uc_b1 << 4) | uc_b2;
+ uc_b2 = (uc_b3 << 4) | uc_b4;
+ uchar = (uc_b1 << 8) | uc_b2;
+
+ if ((uchar & 0xF800) == 0xD800) {
+ json_uchar uchar2;
+
+ if (end - state.ptr < 6 || (*++ state.ptr) != '\\' || (*++ state.ptr) != 'u' ||
+ (uc_b1 = hex_value (*++ state.ptr)) == 0xFF ||
+ (uc_b2 = hex_value (*++ state.ptr)) == 0xFF ||
+ (uc_b3 = hex_value (*++ state.ptr)) == 0xFF ||
+ (uc_b4 = hex_value (*++ state.ptr)) == 0xFF)
+ {
+ sprintf (error, "Invalid character value `%c` (at %d:%d)", b, line_and_col);
+ goto e_failed;
+ }
+
+ uc_b1 = (uc_b1 << 4) | uc_b2;
+ uc_b2 = (uc_b3 << 4) | uc_b4;
+ uchar2 = (uc_b1 << 8) | uc_b2;
+
+ uchar = 0x010000 + ((uchar & 0x3FF) << 10) | (uchar2 & 0x3FF);
+ }
+
+ if (sizeof (json_char) >= sizeof (json_uchar) || (uchar <= 0x7F))
+ {
+ string_add ((json_char) uchar);
+ break;
+ }
+
+ if (uchar <= 0x7FF)
+ {
+ if (state.first_pass)
+ string_length += 2;
+ else
+ { string [string_length ++] = 0xC0 | (uchar >> 6);
+ string [string_length ++] = 0x80 | (uchar & 0x3F);
+ }
+
+ break;
+ }
+
+ if (uchar <= 0xFFFF) {
+ if (state.first_pass)
+ string_length += 3;
+ else
+ { string [string_length ++] = 0xE0 | (uchar >> 12);
+ string [string_length ++] = 0x80 | ((uchar >> 6) & 0x3F);
+ string [string_length ++] = 0x80 | (uchar & 0x3F);
+ }
+
+ break;
+ }
+
+ if (state.first_pass)
+ string_length += 4;
+ else
+ { string [string_length ++] = 0xF0 | (uchar >> 18);
+ string [string_length ++] = 0x80 | ((uchar >> 12) & 0x3F);
+ string [string_length ++] = 0x80 | ((uchar >> 6) & 0x3F);
+ string [string_length ++] = 0x80 | (uchar & 0x3F);
+ }
+
+ break;
+
+ default:
+ string_add (b);
+ };
+
+ continue;
+ }
+
+ if (b == '\\')
+ {
+ flags |= flag_escaped;
+ continue;
+ }
+
+ if (b == '"')
+ {
+ if (!state.first_pass)
+ string [string_length] = 0;
+
+ flags &= ~ flag_string;
+ string = 0;
+
+ switch (top->type)
+ {
+ case json_string:
+
+ top->u.string.length = string_length;
+ flags |= flag_next;
+
+ break;
+
+ case json_object:
+
+ if (state.first_pass)
+ (*(json_char **) &top->u.object.values) += string_length + 1;
+ else
+ {
+ top->u.object.values [top->u.object.length].name
+ = (json_char *) top->_reserved.object_mem;
+
+ top->u.object.values [top->u.object.length].name_length
+ = string_length;
+
+ (*(json_char **) &top->_reserved.object_mem) += string_length + 1;
+ }
+
+ flags |= flag_seek_value | flag_need_colon;
+ continue;
+
+ default:
+ break;
+ };
+ }
+ else
+ {
+ string_add (b);
+ continue;
+ }
+ }
+
+ if (state.settings.settings & json_enable_comments)
+ {
+ if (flags & (flag_line_comment | flag_block_comment))
+ {
+ if (flags & flag_line_comment)
+ {
+ if (b == '\r' || b == '\n' || !b)
+ {
+ flags &= ~ flag_line_comment;
+ -- state.ptr; /* so null can be reproc'd */
+ }
+
+ continue;
+ }
+
+ if (flags & flag_block_comment)
+ {
+ if (!b)
+ { sprintf (error, "%d:%d: Unexpected EOF in block comment", line_and_col);
+ goto e_failed;
+ }
+
+ if (b == '*' && state.ptr < (end - 1) && state.ptr [1] == '/')
+ {
+ flags &= ~ flag_block_comment;
+ ++ state.ptr; /* skip closing sequence */
+ }
+
+ continue;
+ }
+ }
+ else if (b == '/')
+ {
+ if (! (flags & (flag_seek_value | flag_done)) && top->type != json_object)
+ { sprintf (error, "%d:%d: Comment not allowed here", line_and_col);
+ goto e_failed;
+ }
+
+ if (++ state.ptr == end)
+ { sprintf (error, "%d:%d: EOF unexpected", line_and_col);
+ goto e_failed;
+ }
+
+ switch (b = *state.ptr)
+ {
+ case '/':
+ flags |= flag_line_comment;
+ continue;
+
+ case '*':
+ flags |= flag_block_comment;
+ continue;
+
+ default:
+ sprintf (error, "%d:%d: Unexpected `%c` in comment opening sequence", line_and_col, b);
+ goto e_failed;
+ };
+ }
+ }
+
+ if (flags & flag_done)
+ {
+ if (!b)
+ break;
+
+ switch (b)
+ {
+ whitespace:
+ continue;
+
+ default:
+
+ sprintf (error, "%d:%d: Trailing garbage: `%c`",
+ state.cur_line, state.cur_col, b);
+
+ goto e_failed;
+ };
+ }
+
+ if (flags & flag_seek_value)
+ {
+ switch (b)
+ {
+ whitespace:
+ continue;
+
+ case ']':
+
+ if (top && top->type == json_array)
+ flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next;
+ else
+ { sprintf (error, "%d:%d: Unexpected ]", line_and_col);
+ goto e_failed;
+ }
+
+ break;
+
+ default:
+
+ if (flags & flag_need_comma)
+ {
+ if (b == ',')
+ { flags &= ~ flag_need_comma;
+ continue;
+ }
+ else
+ {
+ sprintf (error, "%d:%d: Expected , before %c",
+ state.cur_line, state.cur_col, b);
+
+ goto e_failed;
+ }
+ }
+
+ if (flags & flag_need_colon)
+ {
+ if (b == ':')
+ { flags &= ~ flag_need_colon;
+ continue;
+ }
+ else
+ {
+ sprintf (error, "%d:%d: Expected : before %c",
+ state.cur_line, state.cur_col, b);
+
+ goto e_failed;
+ }
+ }
+
+ flags &= ~ flag_seek_value;
+
+ switch (b)
+ {
+ case '{':
+
+ if (!new_value (&state, &top, &root, &alloc, json_object))
+ goto e_alloc_failure;
+
+ continue;
+
+ case '[':
+
+ if (!new_value (&state, &top, &root, &alloc, json_array))
+ goto e_alloc_failure;
+
+ flags |= flag_seek_value;
+ continue;
+
+ case '"':
+
+ if (!new_value (&state, &top, &root, &alloc, json_string))
+ goto e_alloc_failure;
+
+ flags |= flag_string;
+
+ string = top->u.string.ptr;
+ string_length = 0;
+
+ continue;
+
+ case 't':
+
+ if ((end - state.ptr) < 3 || *(++ state.ptr) != 'r' ||
+ *(++ state.ptr) != 'u' || *(++ state.ptr) != 'e')
+ {
+ goto e_unknown_value;
+ }
+
+ if (!new_value (&state, &top, &root, &alloc, json_boolean))
+ goto e_alloc_failure;
+
+ top->u.boolean = 1;
+
+ flags |= flag_next;
+ break;
+
+ case 'f':
+
+ if ((end - state.ptr) < 4 || *(++ state.ptr) != 'a' ||
+ *(++ state.ptr) != 'l' || *(++ state.ptr) != 's' ||
+ *(++ state.ptr) != 'e')
+ {
+ goto e_unknown_value;
+ }
+
+ if (!new_value (&state, &top, &root, &alloc, json_boolean))
+ goto e_alloc_failure;
+
+ flags |= flag_next;
+ break;
+
+ case 'n':
+
+ if ((end - state.ptr) < 3 || *(++ state.ptr) != 'u' ||
+ *(++ state.ptr) != 'l' || *(++ state.ptr) != 'l')
+ {
+ goto e_unknown_value;
+ }
+
+ if (!new_value (&state, &top, &root, &alloc, json_null))
+ goto e_alloc_failure;
+
+ flags |= flag_next;
+ break;
+
+ default:
+
+ if (isdigit (b) || b == '-')
+ {
+ if (!new_value (&state, &top, &root, &alloc, json_integer))
+ goto e_alloc_failure;
+
+ if (!state.first_pass)
+ {
+ while (isdigit (b) || b == '+' || b == '-'
+ || b == 'e' || b == 'E' || b == '.')
+ {
+ if ( (++ state.ptr) == end)
+ {
+ b = 0;
+ break;
+ }
+
+ b = *state.ptr;
+ }
+
+ flags |= flag_next | flag_reproc;
+ break;
+ }
+
+ flags &= ~ (flag_num_negative | flag_num_e |
+ flag_num_e_got_sign | flag_num_e_negative |
+ flag_num_zero);
+
+ num_digits = 0;
+ num_fraction = 0;
+ num_e = 0;
+
+ if (b != '-')
+ {
+ flags |= flag_reproc;
+ break;
+ }
+
+ flags |= flag_num_negative;
+ continue;
+ }
+ else
+ { sprintf (error, "%d:%d: Unexpected %c when seeking value", line_and_col, b);
+ goto e_failed;
+ }
+ };
+ };
+ }
+ else
+ {
+ switch (top->type)
+ {
+ case json_object:
+
+ switch (b)
+ {
+ whitespace:
+ continue;
+
+ case '"':
+
+ if (flags & flag_need_comma)
+ { sprintf (error, "%d:%d: Expected , before \"", line_and_col);
+ goto e_failed;
+ }
+
+ flags |= flag_string;
+
+ string = (json_char *) top->_reserved.object_mem;
+ string_length = 0;
+
+ break;
+
+ case '}':
+
+ flags = (flags & ~ flag_need_comma) | flag_next;
+ break;
+
+ case ',':
+
+ if (flags & flag_need_comma)
+ {
+ flags &= ~ flag_need_comma;
+ break;
+ }
+
+ default:
+ sprintf (error, "%d:%d: Unexpected `%c` in object", line_and_col, b);
+ goto e_failed;
+ };
+
+ break;
+
+ case json_integer:
+ case json_double:
+
+ if (isdigit (b))
+ {
+ ++ num_digits;
+
+ if (top->type == json_integer || flags & flag_num_e)
+ {
+ if (! (flags & flag_num_e))
+ {
+ if (flags & flag_num_zero)
+ { sprintf (error, "%d:%d: Unexpected `0` before `%c`", line_and_col, b);
+ goto e_failed;
+ }
+
+ if (num_digits == 1 && b == '0')
+ flags |= flag_num_zero;
+ }
+ else
+ {
+ flags |= flag_num_e_got_sign;
+ num_e = (num_e * 10) + (b - '0');
+ continue;
+ }
+
+ top->u.integer = (top->u.integer * 10) + (b - '0');
+ continue;
+ }
+
+ num_fraction = (num_fraction * 10) + (b - '0');
+ continue;
+ }
+
+ if (b == '+' || b == '-')
+ {
+ if ( (flags & flag_num_e) && !(flags & flag_num_e_got_sign))
+ {
+ flags |= flag_num_e_got_sign;
+
+ if (b == '-')
+ flags |= flag_num_e_negative;
+
+ continue;
+ }
+ }
+ else if (b == '.' && top->type == json_integer)
+ {
+ if (!num_digits)
+ { sprintf (error, "%d:%d: Expected digit before `.`", line_and_col);
+ goto e_failed;
+ }
+
+ top->type = json_double;
+ top->u.dbl = (double) top->u.integer;
+
+ num_digits = 0;
+ continue;
+ }
+
+ if (! (flags & flag_num_e))
+ {
+ if (top->type == json_double)
+ {
+ if (!num_digits)
+ { sprintf (error, "%d:%d: Expected digit after `.`", line_and_col);
+ goto e_failed;
+ }
+
+ top->u.dbl += ((double) num_fraction) / (pow (10.0, (double) num_digits));
+ }
+
+ if (b == 'e' || b == 'E')
+ {
+ flags |= flag_num_e;
+
+ if (top->type == json_integer)
+ {
+ top->type = json_double;
+ top->u.dbl = (double) top->u.integer;
+ }
+
+ num_digits = 0;
+ flags &= ~ flag_num_zero;
+
+ continue;
+ }
+ }
+ else
+ {
+ if (!num_digits)
+ { sprintf (error, "%d:%d: Expected digit after `e`", line_and_col);
+ goto e_failed;
+ }
+
+ top->u.dbl *= pow (10.0, (double)
+ (flags & flag_num_e_negative ? - num_e : num_e));
+ }
+
+ if (flags & flag_num_negative)
+ {
+ if (top->type == json_integer)
+ top->u.integer = - top->u.integer;
+ else
+ top->u.dbl = - top->u.dbl;
+ }
+
+ flags |= flag_next | flag_reproc;
+ break;
+
+ default:
+ break;
+ };
+ }
+
+ if (flags & flag_reproc)
+ {
+ flags &= ~ flag_reproc;
+ -- state.ptr;
+ }
+
+ if (flags & flag_next)
+ {
+ flags = (flags & ~ flag_next) | flag_need_comma;
+
+ if (!top->parent)
+ {
+ /* root value done */
+
+ flags |= flag_done;
+ continue;
+ }
+
+ if (top->parent->type == json_array)
+ flags |= flag_seek_value;
+
+ if (!state.first_pass)
+ {
+ json_value * parent = top->parent;
+
+ switch (parent->type)
+ {
+ case json_object:
+
+ parent->u.object.values
+ [parent->u.object.length].value = top;
+
+ break;
+
+ case json_array:
+
+ parent->u.array.values
+ [parent->u.array.length] = top;
+
+ break;
+
+ default:
+ break;
+ };
+ }
+
+ if ( (++ top->parent->u.array.length) > state.uint_max)
+ goto e_overflow;
+
+ top = top->parent;
+
+ continue;
+ }
+ }
+
+ alloc = root;
+ }
+
+ return root;
+
+e_unknown_value:
+
+ sprintf (error, "%d:%d: Unknown value", line_and_col);
+ goto e_failed;
+
+e_alloc_failure:
+
+ strcpy (error, "Memory allocation failure");
+ goto e_failed;
+
+e_overflow:
+
+ sprintf (error, "%d:%d: Too long (caught overflow)", line_and_col);
+ goto e_failed;
+
+e_failed:
+
+ if (error_buf)
+ {
+ if (*error)
+ strcpy (error_buf, error);
+ else
+ strcpy (error_buf, "Unknown error");
+ }
+
+ if (state.first_pass)
+ alloc = root;
+
+ while (alloc)
+ {
+ top = alloc->_reserved.next_alloc;
+ state.settings.mem_free (alloc, state.settings.user_data);
+ alloc = top;
+ }
+
+ if (!state.first_pass)
+ json_value_free_ex (&state.settings, root);
+
+ return 0;
+}
+
+json_value * json_parse (const json_char * json, size_t length)
+{
+ json_settings settings;
+ settings.max_memory = 0;
+ settings.settings = 0;
+ settings.mem_alloc = NULL;
+ settings.mem_free = NULL;
+ settings.user_data = NULL;
+ settings.value_extra = 0;
+ return json_parse_ex (&settings, json, length, 0);
+}
+
+void json_value_free_ex (json_settings * settings, json_value * value)
+{
+ json_value * cur_value;
+
+ if (!value)
+ return;
+
+ value->parent = 0;
+
+ while (value)
+ {
+ switch (value->type)
+ {
+ case json_array:
+
+ if (!value->u.array.length)
+ {
+ settings->mem_free (value->u.array.values, settings->user_data);
+ break;
+ }
+
+ value = value->u.array.values [-- value->u.array.length];
+ continue;
+
+ case json_object:
+
+ if (!value->u.object.length)
+ {
+ settings->mem_free (value->u.object.values, settings->user_data);
+ break;
+ }
+
+ value = value->u.object.values [-- value->u.object.length].value;
+ continue;
+
+ case json_string:
+#ifdef CARYLL_USE_PRE_SERIALIZED
+ case json_pre_serialized:
+#endif
+ settings->mem_free (value->u.string.ptr, settings->user_data);
+ break;
+
+ default:
+ break;
+ };
+
+ cur_value = value;
+ value = value->parent;
+ settings->mem_free (cur_value, settings->user_data);
+ }
+}
+
+void json_value_free (json_value * value)
+{
+ json_settings settings;
+ settings.max_memory = 0;
+ settings.settings = 0;
+ settings.mem_alloc = NULL;
+ settings.mem_free = NULL;
+ settings.user_data = NULL;
+ settings.value_extra = 0;
+ settings.mem_free = default_free;
+ json_value_free_ex (&settings, value);
+}
+
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/sds.c b/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/sds.c
new file mode 100644
index 00000000000..fbb90ebbf1d
--- /dev/null
+++ b/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/sds.c
@@ -0,0 +1,1264 @@
+/* SDSLib 2.0 -- A C dynamic strings library
+ *
+ * Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2015, Redis Labs, Inc
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Redis nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include "sds.h"
+#include "sdsalloc.h"
+
+static inline int sdsHdrSize(char type) {
+ switch(type&SDS_TYPE_MASK) {
+ case SDS_TYPE_5:
+ return sizeof(struct sdshdr5);
+ case SDS_TYPE_8:
+ return sizeof(struct sdshdr8);
+ case SDS_TYPE_16:
+ return sizeof(struct sdshdr16);
+ case SDS_TYPE_32:
+ return sizeof(struct sdshdr32);
+ case SDS_TYPE_64:
+ return sizeof(struct sdshdr64);
+ }
+ return 0;
+}
+
+static inline char sdsReqType(size_t string_size) {
+ if (string_size < 32)
+ return SDS_TYPE_5;
+ if (string_size < 0xff)
+ return SDS_TYPE_8;
+ if (string_size < 0xffff)
+ return SDS_TYPE_16;
+ if (string_size < 0xffffffff)
+ return SDS_TYPE_32;
+ return SDS_TYPE_64;
+}
+
+/* Create a new sds string with the content specified by the 'init' pointer
+ * and 'initlen'.
+ * If NULL is used for 'init' the string is initialized with zero bytes.
+ *
+ * The string is always null-termined (all the sds strings are, always) so
+ * even if you create an sds string with:
+ *
+ * mystring = sdsnewlen("abc",3);
+ *
+ * You can print the string with printf() as there is an implicit \0 at the
+ * end of the string. However the string is binary safe and can contain
+ * \0 characters in the middle, as the length is stored in the sds header. */
+sds sdsnewlen(const void *init, size_t initlen) {
+ void *sh;
+ sds s;
+ char type = sdsReqType(initlen);
+ /* Empty strings are usually created in order to append. Use type 8
+ * since type 5 is not good at this. */
+ if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8;
+ int hdrlen = sdsHdrSize(type);
+ unsigned char *fp; /* flags pointer. */
+
+ sh = s_malloc(hdrlen+initlen+1);
+ if (!init)
+ memset(sh, 0, hdrlen+initlen+1);
+ if (sh == NULL) return NULL;
+ s = (char*)sh+hdrlen;
+ fp = ((unsigned char*)s)-1;
+ switch(type) {
+ case SDS_TYPE_5: {
+ *fp = type | (initlen << SDS_TYPE_BITS);
+ break;
+ }
+ case SDS_TYPE_8: {
+ SDS_HDR_VAR(8,s);
+ sh->len = initlen;
+ sh->alloc = initlen;
+ *fp = type;
+ break;
+ }
+ case SDS_TYPE_16: {
+ SDS_HDR_VAR(16,s);
+ sh->len = initlen;
+ sh->alloc = initlen;
+ *fp = type;
+ break;
+ }
+ case SDS_TYPE_32: {
+ SDS_HDR_VAR(32,s);
+ sh->len = initlen;
+ sh->alloc = initlen;
+ *fp = type;
+ break;
+ }
+ case SDS_TYPE_64: {
+ SDS_HDR_VAR(64,s);
+ sh->len = initlen;
+ sh->alloc = initlen;
+ *fp = type;
+ break;
+ }
+ }
+ if (initlen && init)
+ memcpy(s, init, initlen);
+ s[initlen] = '\0';
+ return s;
+}
+
+/* Create an empty (zero length) sds string. Even in this case the string
+ * always has an implicit null term. */
+sds sdsempty(void) {
+ return sdsnewlen("",0);
+}
+
+/* Create a new sds string starting from a null terminated C string. */
+sds sdsnew(const char *init) {
+ size_t initlen = (init == NULL) ? 0 : strlen(init);
+ return sdsnewlen(init, initlen);
+}
+
+/* Duplicate an sds string. */
+sds sdsdup(const sds s) {
+ return sdsnewlen(s, sdslen(s));
+}
+
+/* Free an sds string. No operation is performed if 's' is NULL. */
+void sdsfree(sds s) {
+ if (s == NULL) return;
+ s_free((char*)s-sdsHdrSize(s[-1]));
+}
+
+/* Set the sds string length to the length as obtained with strlen(), so
+ * considering as content only up to the first null term character.
+ *
+ * This function is useful when the sds string is hacked manually in some
+ * way, like in the following example:
+ *
+ * s = sdsnew("foobar");
+ * s[2] = '\0';
+ * sdsupdatelen(s);
+ * printf("%d\n", sdslen(s));
+ *
+ * The output will be "2", but if we comment out the call to sdsupdatelen()
+ * the output will be "6" as the string was modified but the logical length
+ * remains 6 bytes. */
+void sdsupdatelen(sds s) {
+ int reallen = strlen(s);
+ sdssetlen(s, reallen);
+}
+
+/* Modify an sds string in-place to make it empty (zero length).
+ * However all the existing buffer is not discarded but set as free space
+ * so that next append operations will not require allocations up to the
+ * number of bytes previously available. */
+void sdsclear(sds s) {
+ sdssetlen(s, 0);
+ s[0] = '\0';
+}
+
+/* Enlarge the free space at the end of the sds string so that the caller
+ * is sure that after calling this function can overwrite up to addlen
+ * bytes after the end of the string, plus one more byte for nul term.
+ *
+ * Note: this does not change the *length* of the sds string as returned
+ * by sdslen(), but only the free buffer space we have. */
+sds sdsMakeRoomFor(sds s, size_t addlen) {
+ void *sh, *newsh;
+ size_t avail = sdsavail(s);
+ size_t len, newlen;
+ char type, oldtype = s[-1] & SDS_TYPE_MASK;
+ int hdrlen;
+
+ /* Return ASAP if there is enough space left. */
+ if (avail >= addlen) return s;
+
+ len = sdslen(s);
+ sh = (char*)s-sdsHdrSize(oldtype);
+ newlen = (len+addlen);
+ if (newlen < SDS_MAX_PREALLOC)
+ newlen *= 2;
+ else
+ newlen += SDS_MAX_PREALLOC;
+
+ type = sdsReqType(newlen);
+
+ /* Don't use type 5: the user is appending to the string and type 5 is
+ * not able to remember empty space, so sdsMakeRoomFor() must be called
+ * at every appending operation. */
+ if (type == SDS_TYPE_5) type = SDS_TYPE_8;
+
+ hdrlen = sdsHdrSize(type);
+ if (oldtype==type) {
+ newsh = s_realloc(sh, hdrlen+newlen+1);
+ if (newsh == NULL) return NULL;
+ s = (char*)newsh+hdrlen;
+ } else {
+ /* Since the header size changes, need to move the string forward,
+ * and can't use realloc */
+ newsh = s_malloc(hdrlen+newlen+1);
+ if (newsh == NULL) return NULL;
+ memcpy((char*)newsh+hdrlen, s, len+1);
+ s_free(sh);
+ s = (char*)newsh+hdrlen;
+ s[-1] = type;
+ sdssetlen(s, len);
+ }
+ sdssetalloc(s, newlen);
+ return s;
+}
+
+/* Reallocate the sds string so that it has no free space at the end. The
+ * contained string remains not altered, but next concatenation operations
+ * will require a reallocation.
+ *
+ * After the call, the passed sds string is no longer valid and all the
+ * references must be substituted with the new pointer returned by the call. */
+sds sdsRemoveFreeSpace(sds s) {
+ void *sh, *newsh;
+ char type, oldtype = s[-1] & SDS_TYPE_MASK;
+ int hdrlen;
+ size_t len = sdslen(s);
+ sh = (char*)s-sdsHdrSize(oldtype);
+
+ type = sdsReqType(len);
+ hdrlen = sdsHdrSize(type);
+ if (oldtype==type) {
+ newsh = s_realloc(sh, hdrlen+len+1);
+ if (newsh == NULL) return NULL;
+ s = (char*)newsh+hdrlen;
+ } else {
+ newsh = s_malloc(hdrlen+len+1);
+ if (newsh == NULL) return NULL;
+ memcpy((char*)newsh+hdrlen, s, len+1);
+ s_free(sh);
+ s = (char*)newsh+hdrlen;
+ s[-1] = type;
+ sdssetlen(s, len);
+ }
+ sdssetalloc(s, len);
+ return s;
+}
+
+/* Return the total size of the allocation of the specifed sds string,
+ * including:
+ * 1) The sds header before the pointer.
+ * 2) The string.
+ * 3) The free buffer at the end if any.
+ * 4) The implicit null term.
+ */
+size_t sdsAllocSize(sds s) {
+ size_t alloc = sdsalloc(s);
+ return sdsHdrSize(s[-1])+alloc+1;
+}
+
+/* Return the pointer of the actual SDS allocation (normally SDS strings
+ * are referenced by the start of the string buffer). */
+void *sdsAllocPtr(sds s) {
+ return (void*) (s-sdsHdrSize(s[-1]));
+}
+
+/* Increment the sds length and decrements the left free space at the
+ * end of the string according to 'incr'. Also set the null term
+ * in the new end of the string.
+ *
+ * This function is used in order to fix the string length after the
+ * user calls sdsMakeRoomFor(), writes something after the end of
+ * the current string, and finally needs to set the new length.
+ *
+ * Note: it is possible to use a negative increment in order to
+ * right-trim the string.
+ *
+ * Usage example:
+ *
+ * Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the
+ * following schema, to cat bytes coming from the kernel to the end of an
+ * sds string without copying into an intermediate buffer:
+ *
+ * oldlen = sdslen(s);
+ * s = sdsMakeRoomFor(s, BUFFER_SIZE);
+ * nread = read(fd, s+oldlen, BUFFER_SIZE);
+ * ... check for nread <= 0 and handle it ...
+ * sdsIncrLen(s, nread);
+ */
+void sdsIncrLen(sds s, int incr) {
+ unsigned char flags = s[-1];
+ size_t len;
+ switch(flags&SDS_TYPE_MASK) {
+ case SDS_TYPE_5: {
+ unsigned char *fp = ((unsigned char*)s)-1;
+ unsigned char oldlen = SDS_TYPE_5_LEN(flags);
+ assert((incr > 0 && oldlen+incr < 32) || (incr < 0 && oldlen >= (unsigned int)(-incr)));
+ *fp = SDS_TYPE_5 | ((oldlen+incr) << SDS_TYPE_BITS);
+ len = oldlen+incr;
+ break;
+ }
+ case SDS_TYPE_8: {
+ SDS_HDR_VAR(8,s);
+ assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
+ len = (sh->len += incr);
+ break;
+ }
+ case SDS_TYPE_16: {
+ SDS_HDR_VAR(16,s);
+ assert((incr >= 0 && sh->alloc-sh->len >= incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
+ len = (sh->len += incr);
+ break;
+ }
+ case SDS_TYPE_32: {
+ SDS_HDR_VAR(32,s);
+ assert((incr >= 0 && sh->alloc-sh->len >= (unsigned int)incr) || (incr < 0 && sh->len >= (unsigned int)(-incr)));
+ len = (sh->len += incr);
+ break;
+ }
+ case SDS_TYPE_64: {
+ SDS_HDR_VAR(64,s);
+ assert((incr >= 0 && sh->alloc-sh->len >= (uint64_t)incr) || (incr < 0 && sh->len >= (uint64_t)(-incr)));
+ len = (sh->len += incr);
+ break;
+ }
+ default: len = 0; /* Just to avoid compilation warnings. */
+ }
+ s[len] = '\0';
+}
+
+/* Grow the sds to have the specified length. Bytes that were not part of
+ * the original length of the sds will be set to zero.
+ *
+ * if the specified length is smaller than the current length, no operation
+ * is performed. */
+sds sdsgrowzero(sds s, size_t len) {
+ size_t curlen = sdslen(s);
+
+ if (len <= curlen) return s;
+ s = sdsMakeRoomFor(s,len-curlen);
+ if (s == NULL) return NULL;
+
+ /* Make sure added region doesn't contain garbage */
+ memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */
+ sdssetlen(s, len);
+ return s;
+}
+
+/* Append the specified binary-safe string pointed by 't' of 'len' bytes to the
+ * end of the specified sds string 's'.
+ *
+ * After the call, the passed sds string is no longer valid and all the
+ * references must be substituted with the new pointer returned by the call. */
+sds sdscatlen(sds s, const void *t, size_t len) {
+ size_t curlen = sdslen(s);
+
+ s = sdsMakeRoomFor(s,len);
+ if (s == NULL) return NULL;
+ memcpy(s+curlen, t, len);
+ sdssetlen(s, curlen+len);
+ s[curlen+len] = '\0';
+ return s;
+}
+
+/* Append the specified null termianted C string to the sds string 's'.
+ *
+ * After the call, the passed sds string is no longer valid and all the
+ * references must be substituted with the new pointer returned by the call. */
+sds sdscat(sds s, const char *t) {
+ return sdscatlen(s, t, strlen(t));
+}
+
+/* Append the specified sds 't' to the existing sds 's'.
+ *
+ * After the call, the modified sds string is no longer valid and all the
+ * references must be substituted with the new pointer returned by the call. */
+sds sdscatsds(sds s, const sds t) {
+ return sdscatlen(s, t, sdslen(t));
+}
+
+/* Destructively modify the sds string 's' to hold the specified binary
+ * safe string pointed by 't' of length 'len' bytes. */
+sds sdscpylen(sds s, const char *t, size_t len) {
+ if (sdsalloc(s) < len) {
+ s = sdsMakeRoomFor(s,len-sdslen(s));
+ if (s == NULL) return NULL;
+ }
+ memcpy(s, t, len);
+ s[len] = '\0';
+ sdssetlen(s, len);
+ return s;
+}
+
+/* Like sdscpylen() but 't' must be a null-termined string so that the length
+ * of the string is obtained with strlen(). */
+sds sdscpy(sds s, const char *t) {
+ return sdscpylen(s, t, strlen(t));
+}
+
+/* Helper for sdscatlonglong() doing the actual number -> string
+ * conversion. 's' must point to a string with room for at least
+ * SDS_LLSTR_SIZE bytes.
+ *
+ * The function returns the length of the null-terminated string
+ * representation stored at 's'. */
+#define SDS_LLSTR_SIZE 21
+static int sdsll2str(char *s, long long value) {
+ char *p, aux;
+ unsigned long long v;
+ size_t l;
+
+ /* Generate the string representation, this method produces
+ * an reversed string. */
+ v = (value < 0) ? -value : value;
+ p = s;
+ do {
+ *p++ = '0'+(v%10);
+ v /= 10;
+ } while(v);
+ if (value < 0) *p++ = '-';
+
+ /* Compute length and add null term. */
+ l = p-s;
+ *p = '\0';
+
+ /* Reverse the string. */
+ p--;
+ while(s < p) {
+ aux = *s;
+ *s = *p;
+ *p = aux;
+ s++;
+ p--;
+ }
+ return l;
+}
+
+/* Identical sdsll2str(), but for unsigned long long type. */
+static int sdsull2str(char *s, unsigned long long v) {
+ char *p, aux;
+ size_t l;
+
+ /* Generate the string representation, this method produces
+ * an reversed string. */
+ p = s;
+ do {
+ *p++ = '0'+(v%10);
+ v /= 10;
+ } while(v);
+
+ /* Compute length and add null term. */
+ l = p-s;
+ *p = '\0';
+
+ /* Reverse the string. */
+ p--;
+ while(s < p) {
+ aux = *s;
+ *s = *p;
+ *p = aux;
+ s++;
+ p--;
+ }
+ return l;
+}
+
+/* Create an sds string from a long long value. It is much faster than:
+ *
+ * sdscatprintf(sdsempty(),"%lld\n", value);
+ */
+sds sdsfromlonglong(long long value) {
+ char buf[SDS_LLSTR_SIZE];
+ int len = sdsll2str(buf,value);
+
+ return sdsnewlen(buf,len);
+}
+
+/* Like sdscatprintf() but gets va_list instead of being variadic. */
+sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
+ va_list cpy;
+ char staticbuf[1024], *buf = staticbuf, *t;
+ size_t buflen = strlen(fmt)*2;
+
+ /* We try to start using a static buffer for speed.
+ * If not possible we revert to heap allocation. */
+ if (buflen > sizeof(staticbuf)) {
+ buf = s_malloc(buflen);
+ if (buf == NULL) return NULL;
+ } else {
+ buflen = sizeof(staticbuf);
+ }
+
+ /* Try with buffers two times bigger every time we fail to
+ * fit the string in the current buffer size. */
+ while(1) {
+ buf[buflen-2] = '\0';
+ va_copy(cpy,ap);
+ vsnprintf(buf, buflen, fmt, cpy);
+ va_end(cpy);
+ if (buf[buflen-2] != '\0') {
+ if (buf != staticbuf) s_free(buf);
+ buflen *= 2;
+ buf = s_malloc(buflen);
+ if (buf == NULL) return NULL;
+ continue;
+ }
+ break;
+ }
+
+ /* Finally concat the obtained string to the SDS string and return it. */
+ t = sdscat(s, buf);
+ if (buf != staticbuf) s_free(buf);
+ return t;
+}
+
+/* Append to the sds string 's' a string obtained using printf-alike format
+ * specifier.
+ *
+ * After the call, the modified sds string is no longer valid and all the
+ * references must be substituted with the new pointer returned by the call.
+ *
+ * Example:
+ *
+ * s = sdsnew("Sum is: ");
+ * s = sdscatprintf(s,"%d+%d = %d",a,b,a+b).
+ *
+ * Often you need to create a string from scratch with the printf-alike
+ * format. When this is the need, just use sdsempty() as the target string:
+ *
+ * s = sdscatprintf(sdsempty(), "... your format ...", args);
+ */
+sds sdscatprintf(sds s, const char *fmt, ...) {
+ va_list ap;
+ char *t;
+ va_start(ap, fmt);
+ t = sdscatvprintf(s,fmt,ap);
+ va_end(ap);
+ return t;
+}
+
+/* This function is similar to sdscatprintf, but much faster as it does
+ * not rely on sprintf() family functions implemented by the libc that
+ * are often very slow. Moreover directly handling the sds string as
+ * new data is concatenated provides a performance improvement.
+ *
+ * However this function only handles an incompatible subset of printf-alike
+ * format specifiers:
+ *
+ * %s - C String
+ * %S - SDS string
+ * %i - signed int
+ * %I - 64 bit signed integer (long long, int64_t)
+ * %u - unsigned int
+ * %U - 64 bit unsigned integer (unsigned long long, uint64_t)
+ * %% - Verbatim "%" character.
+ */
+sds sdscatfmt(sds s, char const *fmt, ...) {
+ size_t initlen = sdslen(s);
+ const char *f = fmt;
+ int i;
+ va_list ap;
+
+ va_start(ap,fmt);
+ f = fmt; /* Next format specifier byte to process. */
+ i = initlen; /* Position of the next byte to write to dest str. */
+ while(*f) {
+ char next, *str;
+ size_t l;
+ long long num;
+ unsigned long long unum;
+
+ /* Make sure there is always space for at least 1 char. */
+ if (sdsavail(s)==0) {
+ s = sdsMakeRoomFor(s,1);
+ }
+
+ switch(*f) {
+ case '%':
+ next = *(f+1);
+ f++;
+ switch(next) {
+ case 's':
+ case 'S':
+ str = va_arg(ap,char*);
+ l = (next == 's') ? strlen(str) : sdslen(str);
+ if (sdsavail(s) < l) {
+ s = sdsMakeRoomFor(s,l);
+ }
+ memcpy(s+i,str,l);
+ sdsinclen(s,l);
+ i += l;
+ break;
+ case 'i':
+ case 'I':
+ if (next == 'i')
+ num = va_arg(ap,int);
+ else
+ num = va_arg(ap,long long);
+ {
+ char buf[SDS_LLSTR_SIZE];
+ l = sdsll2str(buf,num);
+ if (sdsavail(s) < l) {
+ s = sdsMakeRoomFor(s,l);
+ }
+ memcpy(s+i,buf,l);
+ sdsinclen(s,l);
+ i += l;
+ }
+ break;
+ case 'u':
+ case 'U':
+ if (next == 'u')
+ unum = va_arg(ap,unsigned int);
+ else
+ unum = va_arg(ap,unsigned long long);
+ {
+ char buf[SDS_LLSTR_SIZE];
+ l = sdsull2str(buf,unum);
+ if (sdsavail(s) < l) {
+ s = sdsMakeRoomFor(s,l);
+ }
+ memcpy(s+i,buf,l);
+ sdsinclen(s,l);
+ i += l;
+ }
+ break;
+ default: /* Handle %% and generally %<unknown>. */
+ s[i++] = next;
+ sdsinclen(s,1);
+ break;
+ }
+ break;
+ default:
+ s[i++] = *f;
+ sdsinclen(s,1);
+ break;
+ }
+ f++;
+ }
+ va_end(ap);
+
+ /* Add null-term */
+ s[i] = '\0';
+ return s;
+}
+
+/* Remove the part of the string from left and from right composed just of
+ * contiguous characters found in 'cset', that is a null terminted C string.
+ *
+ * After the call, the modified sds string is no longer valid and all the
+ * references must be substituted with the new pointer returned by the call.
+ *
+ * Example:
+ *
+ * s = sdsnew("AA...AA.a.aa.aHelloWorld :::");
+ * s = sdstrim(s,"Aa. :");
+ * printf("%s\n", s);
+ *
+ * Output will be just "Hello World".
+ */
+sds sdstrim(sds s, const char *cset) {
+ char *start, *end, *sp, *ep;
+ size_t len;
+
+ sp = start = s;
+ ep = end = s+sdslen(s)-1;
+ while(sp <= end && strchr(cset, *sp)) sp++;
+ while(ep > sp && strchr(cset, *ep)) ep--;
+ len = (sp > ep) ? 0 : ((ep-sp)+1);
+ if (s != sp) memmove(s, sp, len);
+ s[len] = '\0';
+ sdssetlen(s,len);
+ return s;
+}
+
+/* Turn the string into a smaller (or equal) string containing only the
+ * substring specified by the 'start' and 'end' indexes.
+ *
+ * start and end can be negative, where -1 means the last character of the
+ * string, -2 the penultimate character, and so forth.
+ *
+ * The interval is inclusive, so the start and end characters will be part
+ * of the resulting string.
+ *
+ * The string is modified in-place.
+ *
+ * Example:
+ *
+ * s = sdsnew("Hello World");
+ * sdsrange(s,1,-1); => "ello World"
+ */
+void sdsrange(sds s, int start, int end) {
+ size_t newlen, len = sdslen(s);
+
+ if (len == 0) return;
+ if (start < 0) {
+ start = len+start;
+ if (start < 0) start = 0;
+ }
+ if (end < 0) {
+ end = len+end;
+ if (end < 0) end = 0;
+ }
+ newlen = (start > end) ? 0 : (end-start)+1;
+ if (newlen != 0) {
+ if (start >= (signed)len) {
+ newlen = 0;
+ } else if (end >= (signed)len) {
+ end = len-1;
+ newlen = (start > end) ? 0 : (end-start)+1;
+ }
+ } else {
+ start = 0;
+ }
+ if (start && newlen) memmove(s, s+start, newlen);
+ s[newlen] = 0;
+ sdssetlen(s,newlen);
+}
+
+/* Apply tolower() to every character of the sds string 's'. */
+void sdstolower(sds s) {
+ int len = sdslen(s), j;
+
+ for (j = 0; j < len; j++) s[j] = tolower(s[j]);
+}
+
+/* Apply toupper() to every character of the sds string 's'. */
+void sdstoupper(sds s) {
+ int len = sdslen(s), j;
+
+ for (j = 0; j < len; j++) s[j] = toupper(s[j]);
+}
+
+/* Compare two sds strings s1 and s2 with memcmp().
+ *
+ * Return value:
+ *
+ * positive if s1 > s2.
+ * negative if s1 < s2.
+ * 0 if s1 and s2 are exactly the same binary string.
+ *
+ * If two strings share exactly the same prefix, but one of the two has
+ * additional characters, the longer string is considered to be greater than
+ * the smaller one. */
+int sdscmp(const sds s1, const sds s2) {
+ size_t l1, l2, minlen;
+ int cmp;
+
+ l1 = sdslen(s1);
+ l2 = sdslen(s2);
+ minlen = (l1 < l2) ? l1 : l2;
+ cmp = memcmp(s1,s2,minlen);
+ if (cmp == 0) return l1-l2;
+ return cmp;
+}
+
+/* Split 's' with separator in 'sep'. An array
+ * of sds strings is returned. *count will be set
+ * by reference to the number of tokens returned.
+ *
+ * On out of memory, zero length string, zero length
+ * separator, NULL is returned.
+ *
+ * Note that 'sep' is able to split a string using
+ * a multi-character separator. For example
+ * sdssplit("foo_-_bar","_-_"); will return two
+ * elements "foo" and "bar".
+ *
+ * This version of the function is binary-safe but
+ * requires length arguments. sdssplit() is just the
+ * same function but for zero-terminated strings.
+ */
+sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count) {
+ int elements = 0, slots = 5, start = 0, j;
+ sds *tokens;
+
+ if (seplen < 1 || len < 0) return NULL;
+
+ tokens = s_malloc(sizeof(sds)*slots);
+ if (tokens == NULL) return NULL;
+
+ if (len == 0) {
+ *count = 0;
+ return tokens;
+ }
+ for (j = 0; j < (len-(seplen-1)); j++) {
+ /* make sure there is room for the next element and the final one */
+ if (slots < elements+2) {
+ sds *newtokens;
+
+ slots *= 2;
+ newtokens = s_realloc(tokens,sizeof(sds)*slots);
+ if (newtokens == NULL) goto cleanup;
+ tokens = newtokens;
+ }
+ /* search the separator */
+ if ((seplen == 1 && *(s+j) == sep[0]) || (memcmp(s+j,sep,seplen) == 0)) {
+ tokens[elements] = sdsnewlen(s+start,j-start);
+ if (tokens[elements] == NULL) goto cleanup;
+ elements++;
+ start = j+seplen;
+ j = j+seplen-1; /* skip the separator */
+ }
+ }
+ /* Add the final element. We are sure there is room in the tokens array. */
+ tokens[elements] = sdsnewlen(s+start,len-start);
+ if (tokens[elements] == NULL) goto cleanup;
+ elements++;
+ *count = elements;
+ return tokens;
+
+cleanup:
+ {
+ int i;
+ for (i = 0; i < elements; i++) sdsfree(tokens[i]);
+ s_free(tokens);
+ *count = 0;
+ return NULL;
+ }
+}
+
+/* Free the result returned by sdssplitlen(), or do nothing if 'tokens' is NULL. */
+void sdsfreesplitres(sds *tokens, int count) {
+ if (!tokens) return;
+ while(count--)
+ sdsfree(tokens[count]);
+ s_free(tokens);
+}
+
+/* Append to the sds string "s" an escaped string representation where
+ * all the non-printable characters (tested with isprint()) are turned into
+ * escapes in the form "\n\r\a...." or "\x<hex-number>".
+ *
+ * After the call, the modified sds string is no longer valid and all the
+ * references must be substituted with the new pointer returned by the call. */
+sds sdscatrepr(sds s, const char *p, size_t len) {
+ s = sdscatlen(s,"\"",1);
+ while(len--) {
+ switch(*p) {
+ case '\\':
+ case '"':
+ s = sdscatprintf(s,"\\%c",*p);
+ break;
+ case '\n': s = sdscatlen(s,"\\n",2); break;
+ case '\r': s = sdscatlen(s,"\\r",2); break;
+ case '\t': s = sdscatlen(s,"\\t",2); break;
+ case '\a': s = sdscatlen(s,"\\a",2); break;
+ case '\b': s = sdscatlen(s,"\\b",2); break;
+ default:
+ if (isprint(*p))
+ s = sdscatprintf(s,"%c",*p);
+ else
+ s = sdscatprintf(s,"\\x%02x",(unsigned char)*p);
+ break;
+ }
+ p++;
+ }
+ return sdscatlen(s,"\"",1);
+}
+
+/* Helper function for sdssplitargs() that returns non zero if 'c'
+ * is a valid hex digit. */
+static int is_hex_digit(char c) {
+ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
+ (c >= 'A' && c <= 'F');
+}
+
+/* Helper function for sdssplitargs() that converts a hex digit into an
+ * integer from 0 to 15 */
+static int hex_digit_to_int(char c) {
+ switch(c) {
+ case '0': return 0;
+ case '1': return 1;
+ case '2': return 2;
+ case '3': return 3;
+ case '4': return 4;
+ case '5': return 5;
+ case '6': return 6;
+ case '7': return 7;
+ case '8': return 8;
+ case '9': return 9;
+ case 'a': case 'A': return 10;
+ case 'b': case 'B': return 11;
+ case 'c': case 'C': return 12;
+ case 'd': case 'D': return 13;
+ case 'e': case 'E': return 14;
+ case 'f': case 'F': return 15;
+ default: return 0;
+ }
+}
+
+/* Split a line into arguments, where every argument can be in the
+ * following programming-language REPL-alike form:
+ *
+ * foo bar "newline are supported\n" and "\xff\x00otherstuff"
+ *
+ * The number of arguments is stored into *argc, and an array
+ * of sds is returned.
+ *
+ * The caller should free the resulting array of sds strings with
+ * sdsfreesplitres().
+ *
+ * Note that sdscatrepr() is able to convert back a string into
+ * a quoted string in the same format sdssplitargs() is able to parse.
+ *
+ * The function returns the allocated tokens on success, even when the
+ * input string is empty, or NULL if the input contains unbalanced
+ * quotes or closed quotes followed by non space characters
+ * as in: "foo"bar or "foo'
+ */
+sds *sdssplitargs(const char *line, int *argc) {
+ const char *p = line;
+ char *current = NULL;
+ char **vector = NULL;
+
+ *argc = 0;
+ while(1) {
+ /* skip blanks */
+ while(*p && isspace(*p)) p++;
+ if (*p) {
+ /* get a token */
+ int inq=0; /* set to 1 if we are in "quotes" */
+ int insq=0; /* set to 1 if we are in 'single quotes' */
+ int done=0;
+
+ if (current == NULL) current = sdsempty();
+ while(!done) {
+ if (inq) {
+ if (*p == '\\' && *(p+1) == 'x' &&
+ is_hex_digit(*(p+2)) &&
+ is_hex_digit(*(p+3)))
+ {
+ unsigned char byte;
+
+ byte = (hex_digit_to_int(*(p+2))*16)+
+ hex_digit_to_int(*(p+3));
+ current = sdscatlen(current,(char*)&byte,1);
+ p += 3;
+ } else if (*p == '\\' && *(p+1)) {
+ char c;
+
+ p++;
+ switch(*p) {
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ case 't': c = '\t'; break;
+ case 'b': c = '\b'; break;
+ case 'a': c = '\a'; break;
+ default: c = *p; break;
+ }
+ current = sdscatlen(current,&c,1);
+ } else if (*p == '"') {
+ /* closing quote must be followed by a space or
+ * nothing at all. */
+ if (*(p+1) && !isspace(*(p+1))) goto err;
+ done=1;
+ } else if (!*p) {
+ /* unterminated quotes */
+ goto err;
+ } else {
+ current = sdscatlen(current,p,1);
+ }
+ } else if (insq) {
+ if (*p == '\\' && *(p+1) == '\'') {
+ p++;
+ current = sdscatlen(current,"'",1);
+ } else if (*p == '\'') {
+ /* closing quote must be followed by a space or
+ * nothing at all. */
+ if (*(p+1) && !isspace(*(p+1))) goto err;
+ done=1;
+ } else if (!*p) {
+ /* unterminated quotes */
+ goto err;
+ } else {
+ current = sdscatlen(current,p,1);
+ }
+ } else {
+ switch(*p) {
+ case ' ':
+ case '\n':
+ case '\r':
+ case '\t':
+ case '\0':
+ done=1;
+ break;
+ case '"':
+ inq=1;
+ break;
+ case '\'':
+ insq=1;
+ break;
+ default:
+ current = sdscatlen(current,p,1);
+ break;
+ }
+ }
+ if (*p) p++;
+ }
+ /* add the token to the vector */
+ vector = s_realloc(vector,((*argc)+1)*sizeof(char*));
+ vector[*argc] = current;
+ (*argc)++;
+ current = NULL;
+ } else {
+ /* Even on empty input string return something not NULL. */
+ if (vector == NULL) vector = s_malloc(sizeof(void*));
+ return vector;
+ }
+ }
+
+err:
+ while((*argc)--)
+ sdsfree(vector[*argc]);
+ s_free(vector);
+ if (current) sdsfree(current);
+ *argc = 0;
+ return NULL;
+}
+
+/* Modify the string substituting all the occurrences of the set of
+ * characters specified in the 'from' string to the corresponding character
+ * in the 'to' array.
+ *
+ * For instance: sdsmapchars(mystring, "ho", "01", 2)
+ * will have the effect of turning the string "hello" into "0ell1".
+ *
+ * The function returns the sds string pointer, that is always the same
+ * as the input pointer since no resize is needed. */
+sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) {
+ size_t j, i, l = sdslen(s);
+
+ for (j = 0; j < l; j++) {
+ for (i = 0; i < setlen; i++) {
+ if (s[j] == from[i]) {
+ s[j] = to[i];
+ break;
+ }
+ }
+ }
+ return s;
+}
+
+/* Join an array of C strings using the specified separator (also a C string).
+ * Returns the result as an sds string. */
+sds sdsjoin(char **argv, int argc, char *sep) {
+ sds join = sdsempty();
+ int j;
+
+ for (j = 0; j < argc; j++) {
+ join = sdscat(join, argv[j]);
+ if (j != argc-1) join = sdscat(join,sep);
+ }
+ return join;
+}
+
+/* Like sdsjoin, but joins an array of SDS strings. */
+sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen) {
+ sds join = sdsempty();
+ int j;
+
+ for (j = 0; j < argc; j++) {
+ join = sdscatsds(join, argv[j]);
+ if (j != argc-1) join = sdscatlen(join,sep,seplen);
+ }
+ return join;
+}
+
+#if defined(SDS_TEST_MAIN)
+#include <stdio.h>
+#include "testhelp.h"
+#include "limits.h"
+
+#define UNUSED(x) (void)(x)
+int sdsTest(void) {
+ {
+ sds x = sdsnew("foo"), y;
+
+ test_cond("Create a string and obtain the length",
+ sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0)
+
+ sdsfree(x);
+ x = sdsnewlen("foo",2);
+ test_cond("Create a string with specified length",
+ sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0)
+
+ x = sdscat(x,"bar");
+ test_cond("Strings concatenation",
+ sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0);
+
+ x = sdscpy(x,"a");
+ test_cond("sdscpy() against an originally longer string",
+ sdslen(x) == 1 && memcmp(x,"a\0",2) == 0)
+
+ x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk");
+ test_cond("sdscpy() against an originally shorter string",
+ sdslen(x) == 33 &&
+ memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0)
+
+ sdsfree(x);
+ x = sdscatprintf(sdsempty(),"%d",123);
+ test_cond("sdscatprintf() seems working in the base case",
+ sdslen(x) == 3 && memcmp(x,"123\0",4) == 0)
+
+ sdsfree(x);
+ x = sdsnew("--");
+ x = sdscatfmt(x, "Hello %s World %I,%I--", "Hi!", LLONG_MIN,LLONG_MAX);
+ test_cond("sdscatfmt() seems working in the base case",
+ sdslen(x) == 60 &&
+ memcmp(x,"--Hello Hi! World -9223372036854775808,"
+ "9223372036854775807--",60) == 0)
+ printf("[%s]\n",x);
+
+ sdsfree(x);
+ x = sdsnew("--");
+ x = sdscatfmt(x, "%u,%U--", UINT_MAX, ULLONG_MAX);
+ test_cond("sdscatfmt() seems working with unsigned numbers",
+ sdslen(x) == 35 &&
+ memcmp(x,"--4294967295,18446744073709551615--",35) == 0)
+
+ sdsfree(x);
+ x = sdsnew(" x ");
+ sdstrim(x," x");
+ test_cond("sdstrim() works when all chars match",
+ sdslen(x) == 0)
+
+ sdsfree(x);
+ x = sdsnew(" x ");
+ sdstrim(x," ");
+ test_cond("sdstrim() works when a single char remains",
+ sdslen(x) == 1 && x[0] == 'x')
+
+ sdsfree(x);
+ x = sdsnew("xxciaoyyy");
+ sdstrim(x,"xy");
+ test_cond("sdstrim() correctly trims characters",
+ sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0)
+
+ y = sdsdup(x);
+ sdsrange(y,1,1);
+ test_cond("sdsrange(...,1,1)",
+ sdslen(y) == 1 && memcmp(y,"i\0",2) == 0)
+
+ sdsfree(y);
+ y = sdsdup(x);
+ sdsrange(y,1,-1);
+ test_cond("sdsrange(...,1,-1)",
+ sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
+
+ sdsfree(y);
+ y = sdsdup(x);
+ sdsrange(y,-2,-1);
+ test_cond("sdsrange(...,-2,-1)",
+ sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0)
+
+ sdsfree(y);
+ y = sdsdup(x);
+ sdsrange(y,2,1);
+ test_cond("sdsrange(...,2,1)",
+ sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
+
+ sdsfree(y);
+ y = sdsdup(x);
+ sdsrange(y,1,100);
+ test_cond("sdsrange(...,1,100)",
+ sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
+
+ sdsfree(y);
+ y = sdsdup(x);
+ sdsrange(y,100,100);
+ test_cond("sdsrange(...,100,100)",
+ sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
+
+ sdsfree(y);
+ sdsfree(x);
+ x = sdsnew("foo");
+ y = sdsnew("foa");
+ test_cond("sdscmp(foo,foa)", sdscmp(x,y) > 0)
+
+ sdsfree(y);
+ sdsfree(x);
+ x = sdsnew("bar");
+ y = sdsnew("bar");
+ test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0)
+
+ sdsfree(y);
+ sdsfree(x);
+ x = sdsnew("aar");
+ y = sdsnew("bar");
+ test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0)
+
+ sdsfree(y);
+ sdsfree(x);
+ x = sdsnewlen("\a\n\0foo\r",7);
+ y = sdscatrepr(sdsempty(),x,sdslen(x));
+ test_cond("sdscatrepr(...data...)",
+ memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0)
+
+ {
+ unsigned int oldfree;
+ char *p;
+ int step = 10, j, i;
+
+ sdsfree(x);
+ sdsfree(y);
+ x = sdsnew("0");
+ test_cond("sdsnew() free/len buffers", sdslen(x) == 1 && sdsavail(x) == 0);
+
+ /* Run the test a few times in order to hit the first two
+ * SDS header types. */
+ for (i = 0; i < 10; i++) {
+ int oldlen = sdslen(x);
+ x = sdsMakeRoomFor(x,step);
+ int type = x[-1]&SDS_TYPE_MASK;
+
+ test_cond("sdsMakeRoomFor() len", sdslen(x) == oldlen);
+ if (type != SDS_TYPE_5) {
+ test_cond("sdsMakeRoomFor() free", sdsavail(x) >= step);
+ oldfree = sdsavail(x);
+ }
+ p = x+oldlen;
+ for (j = 0; j < step; j++) {
+ p[j] = 'A'+j;
+ }
+ sdsIncrLen(x,step);
+ }
+ test_cond("sdsMakeRoomFor() content",
+ memcmp("0ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ",x,101) == 0);
+ test_cond("sdsMakeRoomFor() final length",sdslen(x)==101);
+
+ sdsfree(x);
+ }
+ }
+ test_report()
+ return 0;
+}
+#endif
+
+#ifdef SDS_TEST_MAIN
+int main(void) {
+ return sdsTest();
+}
+#endif
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/sdsalloc.h b/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/sdsalloc.h
new file mode 100644
index 00000000000..152976c808b
--- /dev/null
+++ b/Build/source/texk/web2c/mfluadir/otfcc/dep/extern/sdsalloc.h
@@ -0,0 +1,41 @@
+/* SDSLib 2.0 -- A C dynamic strings library
+ *
+ * Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2015, Redis Labs, Inc
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Redis nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* SDS allocator selection.
+ *
+ * This file is used in order to change the SDS allocator at compile time.
+ * Just define the following defines to what you want to use. Also add
+ * the include of your alternate allocator if needed (not needed in order
+ * to use the default libc allocator). */
+
+#define s_malloc malloc
+#define s_realloc realloc
+#define s_free free