}
#endif
-#if MJSON_ENABLE_PRINT
-int mjson_print_fixed_buf(const char *ptr, int len, void *fndata) {
- struct mjson_fixedbuf *fb = (struct mjson_fixedbuf *) fndata;
- int i, left = fb->size - 1 - fb->len;
- if (left < len) len = left;
- for (i = 0; i < len; i++) fb->ptr[fb->len + i] = ptr[i];
- fb->len += len;
- fb->ptr[fb->len] = '\0';
- return len;
-}
-
-// This function allocates memory in chunks of size MJSON_DYNBUF_CHUNK
-// to decrease memory fragmentation, when many calls are executed to
-// print e.g. a base64 string or a hex string.
-int mjson_print_dynamic_buf(const char *ptr, int len, void *fndata) {
- char *s, *buf = *(char **) fndata;
- size_t curlen = buf == NULL ? 0 : strlen(buf);
- size_t new_size = curlen + len + 1 + MJSON_DYNBUF_CHUNK;
- new_size -= new_size % MJSON_DYNBUF_CHUNK;
-
- if ((s = (char *) realloc(buf, new_size)) == NULL) {
- return 0;
- } else {
- memcpy(s + curlen, ptr, len);
- s[curlen + len] = '\0';
- *(char **) fndata = s;
- return len;
- }
-}
-
-int mjson_print_null(const char *ptr, int len, void *userdata) {
- (void) ptr;
- (void) userdata;
- return len;
-}
-
-int mjson_print_buf(mjson_print_fn_t fn, void *fnd, const char *buf, int len) {
- return fn(buf, len, fnd);
-}
-
-int mjson_print_long(mjson_print_fn_t fn, void *fnd, long val, int is_signed) {
- unsigned long v = val, s = 0, n, i;
- char buf[20], t;
- if (is_signed && val < 0) {
- buf[s++] = '-', v = -val;
- }
- // This loop prints a number in reverse order. I guess this is because we
- // write numbers from right to left: least significant digit comes last.
- // Maybe because we use Arabic numbers, and Arabs write RTL?
- for (n = 0; v > 0; v /= 10) buf[s + n++] = "0123456789"[v % 10];
- // Reverse a string
- for (i = 0; i < n / 2; i++)
- t = buf[s + i], buf[s + i] = buf[s + n - i - 1], buf[s + n - i - 1] = t;
- if (val == 0) buf[n++] = '0'; // Handle special case
- return fn(buf, s + n, fnd);
-}
-
-int mjson_print_int(mjson_print_fn_t fn, void *fnd, int v, int s) {
- return mjson_print_long(fn, fnd, s ? (long) v : (unsigned) v, s);
-}
-
-static int addexp(char *buf, int e, int sign) {
- int n = 0;
- buf[n++] = 'e';
- buf[n++] = sign;
- if (e > 400) return 0;
- if (e < 10) buf[n++] = '0';
- if (e >= 100) buf[n++] = (e / 100) + '0', e -= 100 * (e / 100);
- if (e >= 10) buf[n++] = (e / 10) + '0', e -= 10 * (e / 10);
- buf[n++] = e + '0';
- return n;
-}
-
-int mjson_print_dbl(mjson_print_fn_t fn, void *fnd, double d, int width) {
- char buf[40];
- int i, s = 0, n = 0, e = 0;
- double t, mul, saved;
- if (d == 0.0) return fn("0", 1, fnd);
- if (isinf(d)) return fn(d > 0 ? "inf" : "-inf", d > 0 ? 3 : 4, fnd);
- if (isnan(d)) return fn("nan", 3, fnd);
- if (d < 0.0) d = -d, buf[s++] = '-';
-
- // Round
- saved = d;
- mul = 1.0;
- while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0;
- while (d <= 1.0 && d / mul <= 1.0) mul /= 10.0;
- for (i = 0, t = mul * 5; i < width; i++) t /= 10.0;
- d += t;
- // Calculate exponent, and 'mul' for scientific representation
- mul = 1.0;
- while (d >= 10.0 && d / mul >= 10.0) mul *= 10.0, e++;
- while (d < 1.0 && d / mul < 1.0) mul /= 10.0, e--;
- // printf(" --> %g %d %g %g\n", saved, e, t, mul);
-
- if (e >= width) {
- struct mjson_fixedbuf fb = {buf + s, (int) sizeof(buf) - s, 0};
- n = mjson_print_dbl(mjson_print_fixed_buf, &fb, saved / mul, width);
- // printf(" --> %.*g %d [%.*s]\n", 10, d / t, e, fb.len, fb.ptr);
- n += addexp(buf + s + n, e, '+');
- return fn(buf, s + n, fnd);
- } else if (e <= -width) {
- struct mjson_fixedbuf fb = {buf + s, (int) sizeof(buf) - s, 0};
- n = mjson_print_dbl(mjson_print_fixed_buf, &fb, saved / mul, width);
- // printf(" --> %.*g %d [%.*s]\n", 10, d / mul, e, fb.len, fb.ptr);
- n += addexp(buf + s + n, -e, '-');
- return fn(buf, s + n, fnd);
- } else {
- for (i = 0, t = mul; d >= 1.0 && s + n < (int) sizeof(buf); i++) {
- int ch = (int) (d / t);
- if (n > 0 || ch > 0) buf[s + n++] = ch + '0';
- d -= ch * t;
- t /= 10.0;
- }
- // printf(" --> [%g] -> %g %g (%d) [%.*s]\n", saved, d, t, n, s + n, buf);
- if (n == 0) buf[s++] = '0';
- while (t >= 1.0 && n + s < (int) sizeof(buf)) buf[n++] = '0', t /= 10.0;
- if (s + n < (int) sizeof(buf)) buf[n + s++] = '.';
- // printf(" 1--> [%g] -> [%.*s]\n", saved, s + n, buf);
- for (i = 0, t = 0.1; s + n < (int) sizeof(buf) && n < width; i++) {
- int ch = (int) (d / t);
- buf[s + n++] = ch + '0';
- d -= ch * t;
- t /= 10.0;
- }
- }
- while (n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeros
- if (n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot
- return fn(buf, s + n, fnd);
-}
-
-int mjson_print_str(mjson_print_fn_t fn, void *fnd, const char *s, int len) {
- int i, n = fn("\"", 1, fnd);
- for (i = 0; i < len; i++) {
- char c = mjson_escape(s[i]);
- if (c) {
- n += fn("\\", 1, fnd);
- n += fn(&c, 1, fnd);
- } else {
- n += fn(&s[i], 1, fnd);
- }
- }
- return n + fn("\"", 1, fnd);
-}
-
-#if MJSON_ENABLE_BASE64
-int mjson_print_b64(mjson_print_fn_t fn, void *fnd, const unsigned char *s,
- int n) {
- const char *t =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- int i, len = fn("\"", 1, fnd);
- for (i = 0; i < n; i += 3) {
- int a = s[i], b = i + 1 < n ? s[i + 1] : 0, c = i + 2 < n ? s[i + 2] : 0;
- char buf[4] = {t[a >> 2], t[(a & 3) << 4 | (b >> 4)], '=', '='};
- if (i + 1 < n) buf[2] = t[(b & 15) << 2 | (c >> 6)];
- if (i + 2 < n) buf[3] = t[c & 63];
- len += fn(buf, sizeof(buf), fnd);
- }
- return len + fn("\"", 1, fnd);
-}
-#endif /* MJSON_ENABLE_BASE64 */
-
-int mjson_vprintf(mjson_print_fn_t fn, void *fnd, const char *fmt,
- va_list xap) {
- int i = 0, n = 0;
- va_list ap;
- va_copy(ap, xap);
- while (fmt[i] != '\0') {
- if (fmt[i] == '%') {
- char fc = fmt[++i];
- int is_long = 0;
- if (fc == 'l') {
- is_long = 1;
- fc = fmt[i + 1];
- }
- if (fc == 'Q') {
- char *buf = va_arg(ap, char *);
- n += mjson_print_str(fn, fnd, buf ? buf : "",
- buf ? (int) strlen(buf) : 0);
- } else if (strncmp(&fmt[i], ".*Q", 3) == 0) {
- int len = va_arg(ap, int);
- char *buf = va_arg(ap, char *);
- n += mjson_print_str(fn, fnd, buf, len);
- i += 2;
- } else if (fc == 'd' || fc == 'u') {
- int is_signed = (fc == 'd');
- if (is_long) {
- long val = va_arg(ap, long);
- n += mjson_print_long(fn, fnd, val, is_signed);
- i++;
- } else {
- int val = va_arg(ap, int);
- n += mjson_print_int(fn, fnd, val, is_signed);
- }
- } else if (fc == 'B') {
- const char *s = va_arg(ap, int) ? "true" : "false";
- n += mjson_print_buf(fn, fnd, s, (int) strlen(s));
- } else if (fc == 's') {
- char *buf = va_arg(ap, char *);
- n += mjson_print_buf(fn, fnd, buf, (int) strlen(buf));
- } else if (strncmp(&fmt[i], ".*s", 3) == 0) {
- int len = va_arg(ap, int);
- char *buf = va_arg(ap, char *);
- n += mjson_print_buf(fn, fnd, buf, len);
- i += 2;
- } else if (fc == 'g') {
- n += mjson_print_dbl(fn, fnd, va_arg(ap, double), 6);
- } else if (strncmp(&fmt[i], ".*g", 3) == 0) {
- int width = va_arg(ap, int);
- n += mjson_print_dbl(fn, fnd, va_arg(ap, double), width);
- i += 2;
-#if MJSON_ENABLE_BASE64
- } else if (fc == 'V') {
- int len = va_arg(ap, int);
- const char *buf = va_arg(ap, const char *);
- n += mjson_print_b64(fn, fnd, (unsigned char *) buf, len);
-#endif
- } else if (fc == 'H') {
- const char *hex = "0123456789abcdef";
- int i, len = va_arg(ap, int);
- const unsigned char *p = va_arg(ap, const unsigned char *);
- n += fn("\"", 1, fnd);
- for (i = 0; i < len; i++) {
- n += fn(&hex[(p[i] >> 4) & 15], 1, fnd);
- n += fn(&hex[p[i] & 15], 1, fnd);
- }
- n += fn("\"", 1, fnd);
- } else if (fc == 'M') {
- mjson_vprint_fn_t vfn = va_arg(ap, mjson_vprint_fn_t);
- n += vfn(fn, fnd, &ap);
- }
- i++;
- } else {
- n += mjson_print_buf(fn, fnd, &fmt[i++], 1);
- }
- }
- va_end(xap);
- va_end(ap);
- return n;
-}
-
-int mjson_printf(mjson_print_fn_t fn, void *fnd, const char *fmt, ...) {
- va_list ap;
- int len;
- va_start(ap, fmt);
- len = mjson_vprintf(fn, fnd, fmt, ap);
- va_end(ap);
- return len;
-}
-#endif /* MJSON_ENABLE_PRINT */
-
static int is_digit(int c) {
return c >= '0' && c <= '9';
}