<commit_before>/*
 * Copyright (c) 2014 <NAME>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <alloca.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>

#include "json.h"
#include "internal.h"

#include <buffer.h>

enum json_ansi_color {
    JSON_ANSI_COLOR_BLACK   = 0,
    JSON_ANSI_COLOR_RED     = 1,
    JSON_ANSI_COLOR_GREEN   = 2,
    JSON_ANSI_COLOR_YELLOW  = 3,
    JSON_ANSI_COLOR_BLUE    = 4,
    JSON_ANSI_COLOR_MAGENTA = 5,
    JSON_ANSI_COLOR_CYAN    = 6,
    JSON_ANSI_COLOR_WHITE   = 7,
    JSON_ANSI_COLOR_GRAY    = 8,
    JSON_ANSI_COLOR_DEFAULT = 9,
};

struct json_format_ctx {
    uint32_t opts;
    size_t indent;
};

static int json_format_value(const struct json_value *, struct bf_buffer *,
                             struct json_format_ctx *);

static int json_format_object(const struct json_object *, struct bf_buffer *,
                              struct json_format_ctx *);
static int json_format_array(const struct json_array *, struct bf_buffer *,
                             struct json_format_ctx *);
static int json_format_integer(int64_t, struct bf_buffer *,
                               struct json_format_ctx *);
static int json_format_real(double, struct bf_buffer *,
                            struct json_format_ctx *);
static int json_format_string(const char *, size_t, struct bf_buffer *,
                              struct json_format_ctx *);
static int json_format_boolean(bool, struct bf_buffer *,
                               struct json_format_ctx *);
static int json_format_null(struct bf_buffer *,
                            struct json_format_ctx *);

static int json_format_indent(struct bf_buffer *, struct json_format_ctx *);

static bool json_utf8_is_leading_byte(unsigned char);
static bool json_utf8_is_continuation_byte(unsigned char);
static size_t json_utf8_sequence_length(unsigned char);
static int json_utf8_decode_codepoint(const char *, uint32_t *, size_t *);

#define JSON_SET_ANSI_COLOR(ctx_, buf_, color_)                        \
    if (ctx_->opts & JSON_FORMAT_COLOR_ANSI) {                         \
        if (bf_buffer_add_printf(buf_, "\e[%dm", 30 + color_) == -1) { \
            json_set_error("%s", bf_get_error());                      \
            return 1;                                                  \
        }                                                              \
    }

#define JSON_CLEAR_ANSI_COLOR(ctx_, buf_)                \
    if (ctx_->opts & JSON_FORMAT_COLOR_ANSI) {           \
        if (bf_buffer_add_string(buf_, "\e[0m") == -1) { \
            json_set_error("%s", bf_get_error());        \
            return 1;                                    \
        }                                                \
    }

char *
json_value_format(const struct json_value *value, uint32_t opts, size_t *plen) {
    struct json_format_ctx ctx;
    struct bf_buffer *buf;
    char *text;

    buf = bf_buffer_new(0);
    if (!buf) {
        json_set_error("%s", bf_get_error());
        return NULL;
    }

    memset(&ctx, 0, sizeof(struct json_format_ctx));
    ctx.opts = opts;
    ctx.indent = 0;

    if (json_format_value(value, buf, &ctx) == -1)
        goto error;

    text = bf_buffer_dup_string(buf);
    if (!text) {
        json_set_error("%s", bf_get_error());
        goto error;
    }

    if (plen)
        *plen = bf_buffer_length(buf);

    bf_buffer_delete(buf);
    return text;

error:
    bf_buffer_delete(buf);
    return NULL;
}

static int
json_format_value(const struct json_value *value, struct bf_buffer *buf,
                  struct json_format_ctx *ctx) {
    switch (value->type) {
    case JSON_OBJECT:
        return json_format_object(&value->u.object, buf, ctx);

    case JSON_ARRAY:
        return json_format_array(&value->u.array, buf, ctx);
<commit_msg>make json_value_format() returned memory allocated with json_malloc()<commit_after>/*
 * Copyright (c) 2014 <NAME>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <alloca.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>

#include "json.h"
#include "internal.h"

#include <buffer.h>

enum json_ansi_color {
    JSON_ANSI_COLOR_BLACK   = 0,
    JSON_ANSI_COLOR_RED     = 1,
    JSON_ANSI_COLOR_GREEN   = 2,
    JSON_ANSI_COLOR_YELLOW  = 3,
    JSON_ANSI_COLOR_BLUE    = 4,
    JSON_ANSI_COLOR_MAGENTA = 5,
    JSON_ANSI_COLOR_CYAN    = 6,
    JSON_ANSI_COLOR_WHITE   = 7,
    JSON_ANSI_COLOR_GRAY    = 8,
    JSON_ANSI_COLOR_DEFAULT = 9,
};

struct json_format_ctx {
    uint32_t opts;
    size_t indent;
};

static int json_format_value(const struct json_value *, struct bf_buffer *,
                             struct json_format_ctx *);

static int json_format_object(const struct json_object *, struct bf_buffer *,
                              struct json_format_ctx *);
static int json_format_array(const struct json_array *, struct bf_buffer *,
                             struct json_format_ctx *);
static int json_format_integer(int64_t, struct bf_buffer *,
                               struct json_format_ctx *);
static int json_format_real(double, struct bf_buffer *,
                            struct json_format_ctx *);
static int json_format_string(const char *, size_t, struct bf_buffer *,
                              struct json_format_ctx *);
static int json_format_boolean(bool, struct bf_buffer *,
                               struct json_format_ctx *);
static int json_format_null(struct bf_buffer *,
                            struct json_format_ctx *);

static int json_format_indent(struct bf_buffer *, struct json_format_ctx *);

static bool json_utf8_is_leading_byte(unsigned char);
static bool json_utf8_is_continuation_byte(unsigned char);
static size_t json_utf8_sequence_length(unsigned char);
static int json_utf8_decode_codepoint(const char *, uint32_t *, size_t *);

#define JSON_SET_ANSI_COLOR(ctx_, buf_, color_)                        \
    if (ctx_->opts & JSON_FORMAT_COLOR_ANSI) {                         \
        if (bf_buffer_add_printf(buf_, "\e[%dm", 30 + color_) == -1) { \
            json_set_error("%s", bf_get_error());                      \
            return 1;                                                  \
        }                                                              \
    }

#define JSON_CLEAR_ANSI_COLOR(ctx_, buf_)                \
    if (ctx_->opts & JSON_FORMAT_COLOR_ANSI) {           \
        if (bf_buffer_add_string(buf_, "\e[0m") == -1) { \
            json_set_error("%s", bf_get_error());        \
            return 1;                                    \
        }                                                \
    }

char *
json_value_format(const struct json_value *value, uint32_t opts, size_t *plen) {
    struct json_format_ctx ctx;
    struct bf_buffer *buf;
    char *data, *text;
    size_t length;

    buf = bf_buffer_new(0);
    if (!buf) {
        json_set_error("%s", bf_get_error());
        return NULL;
    }

    memset(&ctx, 0, sizeof(struct json_format_ctx));
    ctx.opts = opts;
    ctx.indent = 0;

    if (json_format_value(value, buf, &ctx) == -1)
        goto error;

    data = bf_buffer_extract(buf, &length);
    if (!data) {
        json_set_error("%s", bf_get_error());
        goto error;
    }

    text = json_malloc(length + 1);
    if (!text)
        goto error;

    memcpy(text, data, length);
    text[length] = '\0';

    if (plen)
        *plen = length;

    bf_buffer_delete(buf);
    return text;

error:
    bf_buffer_delete(buf);
    return NULL;
}

static int
json_format_value(const struct json_value *value, struct bf_buffer *buf,
                  struct json_format_ctx *ctx) {
    switch (value->type) {
    case JSON_OBJECT:
        return json_format_object(&value->u.object, buf, ctx);

    case JSON_ARRAY:
        return json_format_array(&value->u.array, buf, ctx);

{'fraction_non_alphanumeric': 0.08759597707364551, 'fraction_numerical': 0.008218881799502541, 'mean_word_length': 2.2713123452423063, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1620138', 'n_tokens_mistral': 2889, 'n_tokens_neox': 2741, 'n_words': 744}