/* Generated from "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod" by precompile.pike running Pike v8.1 release 13
 *
 * Do NOT edit this file.
 */

#undef PRECOMPILE_API_VERSION
#define PRECOMPILE_API_VERSION 6



#undef cmod___CMOD__
#define cmod___CMOD__ 1
#line 1 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
#line 1 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
#line 1 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
#line 3488 "/Users/hww3/devel/pike/lib/modules/Tools.pmod/Standalone.pmod/precompile.pike"







#line 3495 "/Users/hww3/devel/pike/lib/modules/Tools.pmod/Standalone.pmod/precompile.pike"
#line 1 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
#line 1 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
/* -*- c -*-
|| This file is part of Pike. For copyright information see COPYRIGHT.
|| Pike is distributed under GPL, LGPL and MPL. See the file COPYING
|| for more information.
*/

/* JSON5 tools.
 *
 * Ref: RFC 4627
 *
 * Decoder comes from Public.Parser.JSON52 by Arne Gödeke.
 * Encoder created May 2010 by Martin Stjernholm.
 */

#include "module.h"
#include "cyclic.h"
#include "interpret.h"
#include "pike_error.h"
#include "pike_float.h"
#include "pike_types.h"
#include "sscanf.h"
#include "module_support.h"

#define DEFAULT_CMOD_STORAGE static



#ifndef PIKE_UNUSED_ATTRIBUTE
#define PIKE_UNUSED_ATTRIBUTE
#endif
#define CMOD_MAP_PROGRAM_IDS_DEFINED 1
static int ___cmod_map_program_ids(int id) PIKE_UNUSED_ATTRIBUTE;
#ifndef TYPEOF
/* Compat with older Pikes. */
#define TYPEOF(SVAL)	((SVAL).type)
#define SUBTYPEOF(SVAL)	((SVAL).subtype)
#define SET_SVAL_TYPE(SVAL, TYPE)	(TYPEOF(SVAL) = TYPE)
#define SET_SVAL_SUBTYPE(SVAL, TYPE)	(SUBTYPEOF(SVAL) = TYPE)
#define SET_SVAL(SVAL, TYPE, SUBTYPE, FIELD, EXPR) do {	\
    /* Set the type afterwards to avoid a clobbered	\
     * svalue in case EXPR throws. */			\
    (SVAL).u.FIELD = (EXPR);				\
    SET_SVAL_TYPE((SVAL), (TYPE));			\
    SET_SVAL_SUBTYPE((SVAL), (SUBTYPE));		\
  } while(0)
#endif /* !TYPEOF */
#ifndef PIKE_UNUSED
/* Compat with Pike 7.8 and earlier. */
/* NB: Not strictly correct; PIKE_UNUSED was added the
 *     day after set_program_id_to_id(), but good enough.
 */
#ifndef UNUSED
#define UNUSED(X)	X
#endif
#ifndef set_program_id_to_id
/* NB: Recent Pike 7.8 has a #define that conflicts with
 *     the following declaration.
 */
static void set_program_id_to_id(void*UNUSED(id)){}
#endif
#else /* */
PMOD_EXPORT void set_program_id_to_id( int (*to)(int) );
#endif /* !PIKE_UNUSED */
#if !defined(string_has_null) && !defined(STRING_CONTENT_CHECKED)
/* This symbol was added as a macro in Pike 7.7.20, and is an
 * inline function in Pike 7.9.4 and later, at which time the
 * flag STRING_CONTENT_CHECKED was added.
 */
#define string_has_null(X) (strlen((X)->str)!=(size_t)(X)->len)
#endif


#ifndef DEFAULT_CMOD_STORAGE
#define CMOD_COND_USED
#define DEFAULT_CMOD_STORAGE static
#endif
#ifndef CMOD_COND_USED
# define f_JSON5_decode_fun_num_used 1
# define f_JSON5_decode_utf8_fun_num_used 1
# define f_JSON5_encode_fun_num_used 1
# define f_JSON5_escape_string_fun_num_used 1
# define f_JSON5_validate_fun_num_used 1
# define f_JSON5_validate_utf8_fun_num_used 1
#else /* !CMOD_COND_USED */
# undef f_JSON5_decode_fun_num_used
# undef f_JSON5_decode_utf8_fun_num_used
# undef f_JSON5_encode_fun_num_used
# undef f_JSON5_escape_string_fun_num_used
# undef f_JSON5_validate_fun_num_used
# undef f_JSON5_validate_utf8_fun_num_used
#endif /* !CMOD_COND_USED */

#ifdef f_JSON5_encode_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_JSON5_encode_fun_num = -1;

#endif /* f_JSON5_encode_fun_num_used */

#ifdef f_JSON5_escape_string_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_JSON5_escape_string_fun_num = -1;

#endif /* f_JSON5_escape_string_fun_num_used */

#ifdef f_JSON5_validate_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_JSON5_validate_fun_num = -1;

#endif /* f_JSON5_validate_fun_num_used */

#ifdef f_JSON5_decode_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_JSON5_decode_fun_num = -1;

#endif /* f_JSON5_decode_fun_num_used */

#ifdef f_JSON5_validate_utf8_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_JSON5_validate_utf8_fun_num = -1;

#endif /* f_JSON5_validate_utf8_fun_num_used */

#ifdef f_JSON5_decode_utf8_fun_num_used
DEFAULT_CMOD_STORAGE ptrdiff_t f_JSON5_decode_utf8_fun_num = -1;

#endif /* f_JSON5_decode_utf8_fun_num_used */
/*! @module Standards */

/*! @module JSON5 */

#line 32 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
#define ASCII_ONLY 1
#define HUMAN_READABLE 2
#define PIKE_CANONICAL 4
#define UNQUOTED_IDENTIFIERS 8
#define SINGLE_QUOTED_STRINGS 16

#define JSON5_UTF8	1
#define JSON5_ERROR	2
#define JSON5_VALIDATE	4
#define JSON5_FIRST_VALUE 8

static char *err_msg;

#define PUSH_SPECIAL(X) do {if (!(state->flags&JSON5_VALIDATE)) {	\
    push_object (get_val_##X());					\
} c++; if (state->level > 0) return p+1; } while(0)

#define PARSE(X, FPC) do {						\
    state->level++;							\
    i = _parse_JSON5_##X(str, FPC, pe, state);				\
    state->level--;							\
    if (state->flags&JSON5_ERROR) {					\
	    return i;							\
    } else if (state->level > 0) return i;				\
    c++;								\
} while(0)

#define PARSE_STRING(FPC) do {						\
    state->level++;							\
    if (state->flags&JSON5_UTF8) 					\
	i = _parse_JSON5_string_utf8(str, FPC, pe, state);		\
    else								\
	i = _parse_JSON5_string(str, FPC, pe, state);			\
    state->level--;							\
    if (state->flags&JSON5_ERROR) {					\
	    return i;							\
    } else if (state->level > 0) return i;				\
    c++;								\
} while(0)

#define IS_SURROGATE(x) ((x) >= 0xd800 && (x) < 0xe000)
#define IS_HIGH_SURROGATE(x) ((x) >= 0xd800 && (x) < 0xdc00)
#define IS_LOW_SURROGATE(x) ((x) >= 0xdc00 && (x) < 0xe000)
#define IS_NUNICODE(x)	((x) < 0 || IS_SURROGATE (x) || (x) > 0x10ffff)
#define IS_NUNICODE1(x)	((x) < 0 || IS_SURROGATE (x))
#define IS_ESCAPABLE_QUOTE(x, f) ((x == '"' && !(flags & SINGLE_QUOTED_STRINGS)) || (x == '\'' && (flags & SINGLE_QUOTED_STRINGS)))
#define IS_NUMBER(x) (x >= '0' && x <= '9')
#define IS_ALPHA(x) ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z'))

static int json5_is_identifier(struct pike_string * str) {
  ptrdiff_t i;
  for(i = 0; i < str->len; i++)
  {
    char c = str->str[i];
    if(i && !(c == '_' || IS_ALPHA(c) || IS_NUMBER(c))) { 
      return 0;
    }
    else if(!i && !(c == '_' || IS_ALPHA(c))) {
      return 0;
    }
  }
  return 1;
}

static void json5_escape_string (struct string_builder *buf, int flags,
				struct pike_string *val)
{
  PCHARP str = MKPCHARP_STR (val);
  ptrdiff_t l = val->len, i, s;
  for (s = 0, i = 0; i < l; i++) {
    p_wchar2 c = INDEX_PCHARP (str, i);
    if (c < 0 || c > 0x10ffff)
      Pike_error ("Cannot json5 encode non-unicode char "
		  "0x%"PRINTPIKEINT"x.\n", (INT_TYPE) c);
    if (IS_ESCAPABLE_QUOTE(c, flags) || c == '\\' || c <= 0x1f ||
	(c >= 0x7f && flags & ASCII_ONLY) ||
	/* Let's escape U+2028 and U+2029 as well for compat with
	 * parsers built in javascript - see
	 * http://timelessrepo.com/json5-isnt-a-javascript-subset. */
	c == 0x2028 || c == 0x2029) {
      if (s < i) {
	PCHARP piece = ADD_PCHARP (str, s);
	string_builder_append (buf, piece, i - s);
      }
      string_builder_putchar (buf, '\\');
      switch (c) {
	case '"': string_builder_putchar (buf, '"'); break;
	case '\'': string_builder_putchar (buf, '\''); break;
	case '\\': string_builder_putchar (buf, '\\'); break;
	case '\b': string_builder_putchar (buf, 'b'); break;
	case '\f': string_builder_putchar (buf, 'f'); break;
	case '\n': string_builder_putchar (buf, 'n'); break;
	case '\r': string_builder_putchar (buf, 'r'); break;
	case '\t': string_builder_putchar (buf, 't'); break;
	default:
	  if (c <= 0xffff) {
	    string_builder_putchar (buf, 'u');
	    string_builder_append_integer (buf, c, 16, APPEND_ZERO_PAD, 4, 4);
	  }
	  else {
	    string_builder_putchar (buf, 'u');
	    c -= 0x10000;
	    string_builder_append_integer (buf, (c >> 10) + 0xd800, 16,
					   APPEND_ZERO_PAD, 4, 4);
	    string_builder_strcat (buf, "\\u");
	    string_builder_append_integer (buf, (c & 0x3ff) + 0xdc00, 16,
					   APPEND_ZERO_PAD, 4, 4);
	  }
	  break;
      }
      s = i + 1;
    }
  }
  if (s < i) {
    PCHARP piece = ADD_PCHARP (str, s);
    string_builder_append (buf, piece, i - s);
  }
}

struct parser_state {
    unsigned int level;
    int flags;
};

struct encode_context {
  struct string_builder buf;
  int flags;
  int indent;
  struct svalue *callback;
};

static void json5_encode_key (struct encode_context *ctx, struct svalue *val);
static void json5_encode_recur (struct encode_context *ctx, struct svalue *val);
static void json5_encode_low_recur (struct encode_context *ctx, struct svalue *val, int is_object_key);

static void encode_mapcont (struct encode_context *ctx, struct mapping *m)
/* Assumes there's at least one element. */
{
  struct string_builder *buf = &ctx->buf;
  int e, notfirst = 0;
  struct keypair *k;
  struct mapping_data *md = m->data;

  NEW_MAPPING_LOOP (md) {
    if (notfirst) {
      fast_check_threads_etc(8);
      string_builder_putchar (buf, ',');
      if (ctx->indent >= 0) {
	int indent = ctx->indent;
	string_builder_putchar (buf, '\n');
	string_builder_putchars (buf, ' ', indent);
      }
    }
    else {
      if (ctx->indent >= 0) {
	int indent = ctx->indent = ctx->indent + 2;
	string_builder_putchar (buf, '\n');
	string_builder_putchars (buf, ' ', indent);
      }
      notfirst = 1;
    }

    if (TYPEOF(k->ind) != T_STRING)
      Pike_error ("Cannot json5 encode mapping with non-string index %O.\n",
		  &k->ind);
    json5_encode_key (ctx, &k->ind);

    string_builder_putchar (buf, ':');
    if (ctx->indent >= 0) string_builder_putchar (buf, ' ');
    json5_encode_recur (ctx, &k->val);
  }
}

static void encode_mapcont_canon (struct encode_context *ctx, struct mapping *m)
/* Assumes there's at least one element. */
{
  struct string_builder *buf = &ctx->buf;
  int i, notfirst = 0;
  struct array *inds = mapping_indices (m);
  int size = inds->size;
  ONERROR uwp;
  SET_ONERROR (uwp, do_free_array, inds);

  /* encode_value_canonic uses get_switch_order, but this sort is good
   * enough considering we only have to deal (correctly) with strings. */
  sort_array_destructively (inds);

  for (i = 0; i < size; i++) {
    struct svalue *ind = ITEM (inds) + i;

    {
      /* Push the value on the stack so we know it's still there when
       * we get to formatting it. Probably not really necessary, but
       * better safe than sorry. */
      struct svalue *val = low_mapping_lookup (m, ind);
      if (val)
	push_svalue (val);
      else
	/* The entry has disappeared since the array was created.
	 * Ignore it and continue is the right thing to do. */
	continue;
    }

    if (notfirst) {
      int indent = ctx->indent;
      string_builder_putchar (buf, ',');
      if (indent >= 0) {
	string_builder_putchar (buf, '\n');
	string_builder_putchars (buf, ' ', indent);
      }
    }
    else {
      int indent = ctx->indent;
      if (indent >= 0) {
	ctx->indent = indent = indent + 2;
	string_builder_putchar (buf, '\n');
	string_builder_putchars (buf, ' ', indent);
      }
      notfirst = 1;
    }

    if (TYPEOF(*ind) != T_STRING)
      Pike_error ("Cannot json5 encode mapping with non-string index %O.\n",
		  ind);
    json5_encode_key (ctx, ind);

    string_builder_putchar (buf, ':');
    if (ctx->indent >= 0) string_builder_putchar (buf, ' ');

    json5_encode_recur (ctx, Pike_sp - 1);
    pop_stack();
  }

  UNSET_ONERROR (uwp);
  free_array (inds);
}

static void json5_encode_key(struct encode_context *ctx, struct svalue *val) {
  json5_encode_low_recur(ctx, val, 1);
}

static void json5_encode_recur (struct encode_context *ctx, struct svalue *val) {
  json5_encode_low_recur(ctx, val, 0);
}

static void json5_encode_low_recur (struct encode_context *ctx, struct svalue *val, int is_object_key)
{
  int flags = ctx->flags;
  char string_quote_char = '"';

  DECLARE_CYCLIC();

  if(flags & SINGLE_QUOTED_STRINGS)
    string_quote_char = '\''; 

  check_c_stack (1024);

  if (TYPEOF(*val) <= MAX_COMPLEX && BEGIN_CYCLIC (val->u.ptr, 0))
    Pike_error ("Cyclic data structure - already visited %O.\n", val);

  switch (TYPEOF(*val)) {
    case PIKE_T_STRING: {
      struct string_builder *buf = &ctx->buf;
      int use_quote = !(is_object_key && (flags & UNQUOTED_IDENTIFIERS) && 
		json5_is_identifier(val->u.string)); 
      if(use_quote)
        string_builder_putchar (buf, string_quote_char);
      json5_escape_string (buf, ctx->flags, val->u.string);
      if(use_quote) 
        string_builder_putchar (buf, string_quote_char);
      break;
    }

    case PIKE_T_INT:
      if(SUBTYPEOF(*val))
          string_builder_strcat(&ctx->buf,"null");
      else
          string_builder_append_integer (&ctx->buf, val->u.integer,
                                         10, APPEND_SIGNED, 0, 0);
      break;

    case PIKE_T_FLOAT: {
      FLOAT_TYPE f = val->u.float_number;
      char b[MAX_FLOAT_SPRINTF_LEN];
      if (PIKE_ISNAN (f) || PIKE_ISINF (f))
      {
        string_builder_strcat(&ctx->buf, "null");
        break;
      }
      format_pike_float (b, f);
      string_builder_strcat (&ctx->buf, b);
      break;
    }

    case PIKE_T_ARRAY: {
      struct string_builder *buf = &ctx->buf;
      string_builder_putchar (buf, '[');
      {
	struct array *a = val->u.array;
	int size = a->size;
	if (size) {
	  int i;
	  if (ctx->indent >= 0 && size > 1) {
	    int indent = ctx->indent = ctx->indent + 2;
	    string_builder_putchar (buf, '\n');
	    string_builder_putchars (buf, ' ', indent);
	  }
	  json5_encode_recur (ctx, ITEM (a));
	  for (i = 1; i < size; i++) {
	    fast_check_threads_etc(8);
	    string_builder_putchar (buf, ',');
	    if (ctx->indent >= 0) {
	      int indent = ctx->indent;
	      string_builder_putchar (buf, '\n');
	      string_builder_putchars (buf, ' ', indent);
	    }
	    json5_encode_recur (ctx, ITEM (a) + i);
	  }
	  if (ctx->indent >= 0 && size > 1) {
	    int indent = ctx->indent = ctx->indent - 2;
	    string_builder_putchar (buf, '\n');
	    string_builder_putchars (buf, ' ', indent);
	  }
	}
      }
      string_builder_putchar (buf, ']');
      break;
    }

    case PIKE_T_MAPPING: {
      string_builder_putchar (&ctx->buf, '{');
      check_mapping_for_destruct (val->u.mapping);
      if (m_sizeof (val->u.mapping)) {
	if (ctx->flags & PIKE_CANONICAL)
	  encode_mapcont_canon (ctx, val->u.mapping);
	else
	  encode_mapcont (ctx, val->u.mapping);
	if (ctx->indent >= 0) {
	  int indent = ctx->indent = ctx->indent - 2;
	  string_builder_putchar (&ctx->buf, '\n');
	  string_builder_putchars (&ctx->buf, ' ', indent);
	}
      }
      string_builder_putchar (&ctx->buf, '}');
      break;
    }

    case PIKE_T_OBJECT: {
      struct object *o = val->u.object;
      if (o->prog) {
	/* FIXME: Consider always using encode_json(), and signalling
	 *        JSON5 via a flag?
	 */
	int fun = find_identifier ("encode_json5", o->prog);
	const char *enc_name = "encode_json5";
	if (fun < 0) {
	  /* Fall back to the generic JSON encoder.
	   *
	   * All valid JSON should be valid JSON5.
	   */
	  fun = find_identifier ("encode_json", o->prog);
	  enc_name = "encode_json";
	}
	if (fun < 0) {
	  int args = 2;
	  if (!ctx->callback)
	    Pike_error ("Cannot json5 encode object %O without "
			"encode_json5 or encode_json function.\n", val);
	  if (TYPEOF(*ctx->callback) == PIKE_T_STRING) {
	    string_builder_shared_strcat (&ctx->buf, ctx->callback->u.string);
	    break;
	  }
	  push_svalue(val);
	  push_int(ctx->flags);
	  if (ctx->indent >= 0) {
	    args++;
	    push_int(ctx->indent);
	  }
	  apply_svalue(ctx->callback, args);
	} else {
	  int args = 1;
	  push_int (ctx->flags);
	  if (ctx->indent >= 0) {
	    push_int (ctx->indent);
	    args++;
	  }
	  apply_low (o, fun, args);
	}
	if (TYPEOF(Pike_sp[-1]) != PIKE_T_STRING)
	  Pike_error ("Expected string from %O->%s(), got %s.\n",
		      val, enc_name, get_name_of_type (TYPEOF(Pike_sp[-1])));
	string_builder_shared_strcat (&ctx->buf, Pike_sp[-1].u.string);
	free_string ((--Pike_sp)->u.string);
	break;
      }
    }
    /* FALLTHRU */

    default:
      Pike_error ("Cannot json5 encode %s.\n", get_name_of_type (TYPEOF(*val)));
  }

  if (TYPEOF(*val) <= MAX_COMPLEX)
    END_CYCLIC();
}

/*! @decl constant ASCII_ONLY
 *! @decl constant HUMAN_READABLE
 *! @decl constant PIKE_CANONICAL
 *! @decl constant UNQUOTED_IDENTIFIERS
 *! @decl constant SINGLE_QUOTED_STRINGS
 *!
 *! Bit field flags for use with @[encode]:
 *!
 *! @dl
 *! @item Standards.JSON5.ASCII_ONLY
 *!   Use @expr{\uxxxx@} escapes for all non-ascii characters and DEL
 *!   (U+007f). The default is to escape only the characters that must
 *!   be escaped. The flag value is 1.
 *!
 *!   Characters above U+FFFF are encoded using escaped surrogate
 *!   pairs, as per @rfc{4627@}.
 *!
 *! @item Standards.JSON5.HUMAN_READABLE
 *!   Pretty print with indentation to make the result easier on human
 *!   eyes. The default is to use no extra whitespace at all. The flag
 *!   value is 2.
 *!
 *! @item Standards.JSON5.PIKE_CANONICAL
 *!   Make the output canonical, so that the same value always
 *!   generates the same char-by-char equal string. In practice this
 *!   means that mapping elements are sorted on their indices. Note
 *!   that the other flags take precedence, so e.g. the canonical form
 *!   with @[HUMAN_READABLE] is not the same as the canonical form
 *!   without it. The flag value is 4.
 *!
 *!   This canonical form is stable for the @[encode] function,
 *!   providing floats aren't used (their formatting is currently
 *!   affected by float size and libc formatting code). In the future
 *!   there may be a standardized canonical form which quite likely
 *!   will be different from this one. In that case a separate flag
 *!   has to be added so this one doesn't change - hence the name
 *!   @[PIKE_CANONICAL].
 *!
 *! @item Standards.JSON5.UNQUOTED_IDENTIFIERS
 *!   When producing mapping keys, permit keys which are identifiers
 *!   to be expressed without surrounding quotation marks.
 *!
 *! @item Standards.JSON5.SINGLE_QUOTED_STRINGS
 *!   Use single quotation marks rather than double quotation marks
 *!   when encoding string values.
 *! @enddl
 */

/*! @decl string encode (int|float|string|array|mapping|object val, @
 *!                      void|int flags, void|function|object|program|string callback)
 *!
 *! Encodes a value to a JSON5 string.
 *!
 *! @param val
 *!   The value to encode. It can contain integers, floats (except the
 *!   special numbers NaN and infinity), strings, arrays, mappings
 *!   with string indices, and the special object values @[null],
 *!   @[true] and @[false] defined in this module (or really any
 *!   object that implements an @expr{encode_json5@} callback or
 *!   is handled by the supplied callback argument).
 *!
 *! @param flags
 *!   Flag bit field to control formatting. See @[ASCII_ONLY],
 *!   @[HUMAN_READABLE] and @[PIKE_CANONICAL] for further details.
 *!
 *! @param callback
 *!   A function that will be called for types that can not be encoded
 *!   otherwise.  It will be called with the value to be encoded as the first
 *!   argument, and optionally with flags and indent arguments. If a string is
 *!   supplied, it will be used to replace the value verbatim.
 *!   The callback must return a string or throw an error.
 *!
 *! @note
 *! 8-bit and wider characters in input strings are neither escaped
 *! nor utf-8 encoded by default. @[string_to_utf8] can be used safely
 *! on the returned string to get a valid transport encoded JSON5
 *! string. See @[escape_string] for further details on string
 *! escaping.
 *!
 *! @seealso
 *! @[escape_string]
 */
#define f_JSON5_encode_defined
DEFAULT_CMOD_STORAGE void f_JSON5_encode(INT32 args) {
#line 520 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
struct svalue * val;
struct svalue * flags;
#line 521 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
struct svalue * callback;
struct svalue * base_indent;
#line 520 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
if(args < 1) wrong_number_of_args_error("encode",args,1);
#line 520 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
if(args > 4) wrong_number_of_args_error("encode",args,4);
#line 520 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
val=Pike_sp+0-args; dmalloc_touch_svalue(Pike_sp+0-args);
if ((args > 1) &&
    ((TYPEOF(Pike_sp[1-args]) != PIKE_T_INT) ||
     (SUBTYPEOF(Pike_sp[1-args]) != NUMBER_UNDEFINED))) {
#line 521 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
if((TYPEOF(Pike_sp[1-args]) != PIKE_T_INT)) SIMPLE_ARG_TYPE_ERROR("encode",2,"void|int");
#line 521 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
flags=Pike_sp+1-args; dmalloc_touch_svalue(Pike_sp+1-args);
#line 521 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
} else flags = NULL;
#line 521 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
if ((args > 2) &&
    ((TYPEOF(Pike_sp[2-args]) != PIKE_T_INT) ||
     (SUBTYPEOF(Pike_sp[2-args]) != NUMBER_UNDEFINED))) {
#line 521 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
callback=Pike_sp+2-args; dmalloc_touch_svalue(Pike_sp+2-args);
#line 521 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
} else callback = NULL;
if ((args > 3) &&
    ((TYPEOF(Pike_sp[3-args]) != PIKE_T_INT) ||
     (SUBTYPEOF(Pike_sp[3-args]) != NUMBER_UNDEFINED))) {
#line 522 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
if((TYPEOF(Pike_sp[3-args]) != PIKE_T_INT)) SIMPLE_ARG_TYPE_ERROR("encode",4,"void|int");
#line 522 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
base_indent=Pike_sp+3-args; dmalloc_touch_svalue(Pike_sp+3-args);
#line 522 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
} else base_indent = NULL;
#line 524 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
{
  struct encode_context ctx;
  ONERROR uwp;
  ctx.flags = (flags ? flags->u.integer : 0);
  ctx.indent = (ctx.flags & HUMAN_READABLE ? base_indent ? base_indent->u.integer : 0 : -1);
  ctx.callback = callback;
  init_string_builder (&ctx.buf, 0);
  SET_ONERROR (uwp, free_string_builder, &ctx.buf);
  json5_encode_recur (&ctx, val);
  UNSET_ONERROR (uwp);
  do { struct pike_string * ret_=(finish_string_builder (&ctx.buf)); pop_n_elems(args); push_string(ret_); return; }while(0);
#line 535 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
}

}
/*! @decl string escape_string (string str, void|int flags)
 *!
 *! Escapes string data for use in a JSON5 string.
 *!
 *! 8-bit and wider characters in input strings are neither escaped
 *! nor utf-8 encoded by default. @[string_to_utf8] can be used safely
 *! on the returned string to get a valid transport encoded JSON5
 *! string.
 *!
 *! The characters U+2028 (LINE SEPARATOR) and U+2029 (PARAGRAPH
 *! SEPARATOR) are exceptions - they are encoded with \u escapes for
 *! compatibility. The reason is that those characters are not allowed
 *! in Javascript strings, so JSON5 parsers built in Javascript may
 *! have trouble with them otherwise.
 *!
 *! @param val
 *!   The string to escape.
 *!
 *! @param flags
 *!   Flag bit field to control formatting. @[ASCII_ONLY] is the only
 *!   flag that has any effect for this function.
 *!
 *! @note
 *! The difference between using this function and @[encode] on a
 *! string is that @[encode] returns quotations marks around the
 *! result.
 *!
 *! @seealso
 *! @[encode]
 */
#define f_JSON5_escape_string_defined
DEFAULT_CMOD_STORAGE void f_JSON5_escape_string(INT32 args) {
#line 567 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
struct pike_string * str;
#line 567 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
struct svalue * flags;
#line 567 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
if(args < 1) wrong_number_of_args_error("escape_string",args,1);
#line 567 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
if(args > 2) wrong_number_of_args_error("escape_string",args,2);
#line 567 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
if(TYPEOF(Pike_sp[0-args]) != PIKE_T_STRING) SIMPLE_ARG_TYPE_ERROR("escape_string",1,"string");
#line 567 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
debug_malloc_pass(str=Pike_sp[0-args].u.string);
#line 567 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
if ((args > 1) &&
    ((TYPEOF(Pike_sp[1-args]) != PIKE_T_INT) ||
     (SUBTYPEOF(Pike_sp[1-args]) != NUMBER_UNDEFINED))) {
#line 567 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
if((TYPEOF(Pike_sp[1-args]) != PIKE_T_INT)) SIMPLE_ARG_TYPE_ERROR("escape_string",2,"void|int");
#line 567 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
flags=Pike_sp+1-args; dmalloc_touch_svalue(Pike_sp+1-args);
#line 567 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
} else flags = NULL;
{
  struct string_builder buf;
  ONERROR uwp;
  init_string_builder (&buf, 0);
  SET_ONERROR (uwp, free_string_builder, &buf);
  json5_escape_string (&buf, flags ? flags->u.integer : 0, str);
  UNSET_ONERROR (uwp);
  do { struct pike_string * ret_=(finish_string_builder (&buf)); pop_n_elems(args); push_string(ret_); return; }while(0);
#line 576 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
}

}
#line 578 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
#include "json5_parser.c"

static void low_validate(struct pike_string *data, int flags) {
    ptrdiff_t stop;
    struct parser_state state;

    state.flags = flags|JSON5_VALIDATE;
    state.level = 0;

    stop = _parse_JSON5(MKPCHARP_STR(data), 0, data->len, &state);

    if (state.flags & JSON5_ERROR || stop != data->len) {
	push_int((INT_TYPE)stop);
    } else {
	push_int(-1);
    }

    return;
}

static ptrdiff_t parse_json5_pcharp( PCHARP data, size_t len, int flags, char **err_out )
{
    ptrdiff_t stop;
    struct parser_state state;

    err_msg = NULL;
    state.flags = flags;
    state.level = 0;
    stop = _parse_JSON5(data, 0, len, &state );
    if (state.flags & JSON5_ERROR )
    {
        if( err_out )
            *err_out = err_msg;
        return -stop;
    }
    return stop;
}

static void low_decode(struct pike_string *data, int flags) {
    ptrdiff_t stop;
    struct parser_state state;

    err_msg = NULL;

    state.level = 0;
    state.flags = flags;

    stop = _parse_JSON5(MKPCHARP_STR(data), 0, data->len, &state);

    if (!(state.flags&JSON5_ERROR)) {
	if (stop == data->len) {
		return;
	}
    }

    ref_push_string(data);
    push_int((INT_TYPE)stop);
    if (err_msg) {
      push_text (err_msg);
      apply (Pike_fp->current_object, "decode_error", 3);
    }
    else
      apply (Pike_fp->current_object, "decode_error", 2);

    return;
}


/*! @decl int validate(string s)
 *!
 *! Checks if a string is valid JSON5.
 *!
 *! @returns
 *! 	In case the string contains valid JSON5 @expr{-1@} is returned. It is then guaranteed to be parsed
 *! 	without errors by @[decode()].
 *! 	In case the string is not valid JSON5, the error position is returned.
 */
#define f_JSON5_validate_defined
DEFAULT_CMOD_STORAGE void f_JSON5_validate(INT32 args) {
#line 655 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
struct pike_string * data;
#line 655 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
if(args != 1) wrong_number_of_args_error("validate",args,1);
#line 655 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
if(TYPEOF(Pike_sp[0-1]) != PIKE_T_STRING) SIMPLE_ARG_TYPE_ERROR("validate",1,"string");
#line 655 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
debug_malloc_pass(data=Pike_sp[0-1].u.string);
#line 655 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
{
    low_validate(data, 0);
}

}
/*! @decl array|mapping|string|float|int|object decode(string s)
 *!
 *! Decodes a JSON5 string.
 *!
 *! @throws
 *! 	Throws an exception in case the data contained in @expr{s@} is not valid
 *! 	JSON5.
 */
#define f_JSON5_decode_defined
DEFAULT_CMOD_STORAGE void f_JSON5_decode(INT32 args) {
#line 667 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
struct pike_string * data;
#line 667 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
if(args != 1) wrong_number_of_args_error("decode",args,1);
#line 667 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
if(TYPEOF(Pike_sp[0-1]) != PIKE_T_STRING) SIMPLE_ARG_TYPE_ERROR("decode",1,"string");
#line 667 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
debug_malloc_pass(data=Pike_sp[0-1].u.string);
#line 667 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
{
    low_decode(data, 0);
}

}
/*! @decl int validate_utf8(string s)
 *!
 *! Checks if a string is valid utf8 encoded JSON5.
 *!
 *! @returns
 *! 	In case the string contains valid JSON5 @expr{-1@} is returned. It is then guaranteed to be parsed
 *! 	without errors by @[decode()].
 *! 	In case the string is not valid JSON5, the integer position inside the string
 *! 	where the error occurs is returned.
 */
#define f_JSON5_validate_utf8_defined
DEFAULT_CMOD_STORAGE void f_JSON5_validate_utf8(INT32 args) {
#line 681 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
struct pike_string * data;
#line 681 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
if(args != 1) wrong_number_of_args_error("validate_utf8",args,1);
#line 681 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
if(TYPEOF(Pike_sp[0-1]) != PIKE_T_STRING) SIMPLE_ARG_TYPE_ERROR("validate_utf8",1,"string");
#line 681 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
debug_malloc_pass(data=Pike_sp[0-1].u.string);
#line 681 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
{
    if (data->size_shift)
      Pike_error("Strings wider than 1 byte are NOT valid UTF-8.\n");

    low_validate(data, JSON5_UTF8);
}

}
/*! @decl array|mapping|string|float|int|object decode_utf8(string s)
 *!
 *! Decodes an utf8 encoded JSON5 string.
 *! Should give the same result as @expr{Standards.JSON5.decode(utf8_to_string(s))@}.
 *!
 *! @throws
 *! 	Throws an exception in case the data contained in @expr{s@} is not valid
 *! 	JSON5.
 */
#define f_JSON5_decode_utf8_defined
DEFAULT_CMOD_STORAGE void f_JSON5_decode_utf8(INT32 args) {
#line 697 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
struct pike_string * data;
#line 697 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
if(args != 1) wrong_number_of_args_error("decode_utf8",args,1);
#line 697 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
if(TYPEOF(Pike_sp[0-1]) != PIKE_T_STRING) SIMPLE_ARG_TYPE_ERROR("decode_utf8",1,"string");
#line 697 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
debug_malloc_pass(data=Pike_sp[0-1].u.string);
#line 697 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
{
    if (data->size_shift) {
	ref_push_string(data);
	push_int(0);
	push_static_text("Strings wider than 1 byte are NOT valid UTF-8.");
	apply (Pike_fp->current_object, "decode_error", 3);
    }

    low_decode(data, JSON5_UTF8);
}

}
/*! @endmodule */

/*! @endmodule */

#line 712 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
PIKE_MODULE_INIT
{
  add_integer_constant ("ASCII_ONLY", ASCII_ONLY, 0);
  add_integer_constant ("HUMAN_READABLE", HUMAN_READABLE, 0);
  add_integer_constant ("PIKE_CANONICAL", PIKE_CANONICAL, 0);
  add_integer_constant ("UNQUOTED_IDENTIFIERS", UNQUOTED_IDENTIFIERS, 0);
  add_integer_constant ("SINGLE_QUOTED_STRINGS", SINGLE_QUOTED_STRINGS, 0);

  
#ifdef CMOD_MAP_PROGRAM_IDS_DEFINED
set_program_id_to_id( ___cmod_map_program_ids );

#endif /* CMOD_MAP_PROGRAM_IDS_DEFINED */

#ifdef f_JSON5_encode_defined

#ifdef f_JSON5_encode_fun_num_used
  f_JSON5_encode_fun_num =
#endif /* f_JSON5_encode_fun_num_used */
#line 520 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
    ADD_FUNCTION2("encode", f_JSON5_encode, tFunc(tOr6("\10\200\0\0\0\177\377\377\377",tFloat,tStr,tArray,tMapping,tObj) tOr(tVoid,"\10\200\0\0\0\177\377\377\377") tOr5(tVoid,tFuncV(tNone,tMix,tAny),tObj,tPrg(tObj),tStr) tOr(tVoid,"\10\200\0\0\0\177\377\377\377"),tStr), 0, OPT_TRY_OPTIMIZE);

#endif /* f_JSON5_encode_defined */

#ifdef f_JSON5_escape_string_defined

#ifdef f_JSON5_escape_string_fun_num_used
  f_JSON5_escape_string_fun_num =
#endif /* f_JSON5_escape_string_fun_num_used */
#line 567 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
    ADD_FUNCTION2("escape_string", f_JSON5_escape_string, tFunc(tStr tOr(tVoid,"\10\200\0\0\0\177\377\377\377"),tStr), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_JSON5_escape_string_defined */

#ifdef f_JSON5_validate_defined

#ifdef f_JSON5_validate_fun_num_used
  f_JSON5_validate_fun_num =
#endif /* f_JSON5_validate_fun_num_used */
#line 655 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
    ADD_FUNCTION2("validate", f_JSON5_validate, tFunc(tStr,"\10\200\0\0\0\177\377\377\377"), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_JSON5_validate_defined */

#ifdef f_JSON5_decode_defined

#ifdef f_JSON5_decode_fun_num_used
  f_JSON5_decode_fun_num =
#endif /* f_JSON5_decode_fun_num_used */
#line 667 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
    ADD_FUNCTION2("decode", f_JSON5_decode, tFunc(tStr,tOr6(tArray,tMapping,tStr,tFloat,"\10\200\0\0\0\177\377\377\377",tObj)), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_JSON5_decode_defined */

#ifdef f_JSON5_validate_utf8_defined

#ifdef f_JSON5_validate_utf8_fun_num_used
  f_JSON5_validate_utf8_fun_num =
#endif /* f_JSON5_validate_utf8_fun_num_used */
#line 681 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
    ADD_FUNCTION2("validate_utf8", f_JSON5_validate_utf8, tFunc(tStr,"\10\200\0\0\0\177\377\377\377"), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_JSON5_validate_utf8_defined */

#ifdef f_JSON5_decode_utf8_defined

#ifdef f_JSON5_decode_utf8_fun_num_used
  f_JSON5_decode_utf8_fun_num =
#endif /* f_JSON5_decode_utf8_fun_num_used */
#line 697 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
    ADD_FUNCTION2("decode_utf8", f_JSON5_decode_utf8, tFunc(tStr,tOr6(tArray,tMapping,tStr,tFloat,"\10\200\0\0\0\177\377\377\377",tObj)), 0, OPT_EXTERNAL_DEPEND|OPT_SIDE_EFFECT);

#endif /* f_JSON5_decode_utf8_defined */

#ifdef CMOD_MAP_PROGRAM_IDS_DEFINED
set_program_id_to_id( 0 );
#endif /* CMOD_MAP_PROGRAM_IDS_DEFINED */
#line 720 "/Users/hww3/devel/pike/src/post_modules/JSON5/json5.cmod"
;

  PIKE_MODULE_EXPORT(Standards.JSON5, parse_json5_pcharp );
}

PIKE_MODULE_EXIT
{
  ;
}


#ifdef CMOD_MAP_PROGRAM_IDS_DEFINED
static int ___cmod_map_program_ids(int id)
{
  if( (id&0x7f000000) != 0x7f000000 ) return id;
  id = id&0x00ffffff;
  return 0;
}
#endif /* CMOD_MAP_PROGRAM_IDS_DEFINED */
