/*
Copyright (c) 2000-2004, 2007 Tony Garnock-Jones <tonyg@kcbbs.gen.nz>

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.
*/

#ifndef libubf_a__ubf_a_h
#define libubf_a__ubf_a_h

#ifdef __cplusplus
extern "C" {
#endif

typedef enum UBF_A_ObjectKind_ {
  UBF_A_UNKNOWN = 0,

  UBF_A_NUMBER,
  UBF_A_STRING,
  UBF_A_SYMBOL,
  UBF_A_BINARY,
  UBF_A_TAG,
  UBF_A_PAIR,
  UBF_A_VECTOR,

  UBF_A_MaxType
} UBF_A_ObjectKind;

typedef struct UBF_A_Object_ {
  UBF_A_ObjectKind kind;
  union {
    signed long long num;
    struct {
      size_t length;
      char vec[1];
    } data;
    struct {
      struct UBF_A_Object_ *value;
      char key[1];
    } tag;
    struct {
      struct UBF_A_Object_ *head;
      struct UBF_A_Object_ *tail;
    } pair;
    struct {
      size_t length;
      struct UBF_A_Object_ *vec[1];
    } vector;
  } body;
} UBF_A_Object;

typedef struct UBF_A_Pool_ {
  UBF_A_Object *root;

  int num_blocks;
  void **blocklist;

  size_t pagesize;
  char *alloc_block;
  size_t alloc_used;
} UBF_A_Pool;

/* If a char is available, returns it. The void* is arbitrary
   user-supplied state for the function. Should return -1 for
   end-of-file, -2 for temporarily blocked (essentially EAGAIN), or
   any other value for successful read of a char. */
typedef int (*UBF_A_CharSource)(void *);

/* Accepts the supplied int as a char. The void* is arbitrary
   user-supplied state for the function. Should return EOF if an error
   occurs; any other value will be interpreted as success. */
typedef int (*UBF_A_CharSink)(int, void *);

typedef enum UBF_A_Error_ {
  UBF_A_NoError = 0,
  UBF_A_EarlyEOF,
  UBF_A_UnhandledCharacter,
  UBF_A_UnsupportedQuotedCharacter,
  UBF_A_OrphanSemanticTag,
  UBF_A_MissingBinaryLength,
  UBF_A_MissingBinaryTilde,
  UBF_A_StackUnderflow,
  UBF_A_StackOverflow,
  UBF_A_ReservedCharacter,
  UBF_A_CharacterOutOfRange,
  UBF_A_MissingOpenStruct,
  UBF_A_UnknownObjectKind
} UBF_A_Error;

/* Opaque struct. */
typedef struct UBF_A_DecoderState_ *UBF_A_DecoderState;

extern char const *ubf_a_version(void);

extern void init_ubf_a_pool(UBF_A_Pool *pool, size_t pagesize);
extern void empty_ubf_a_pool(UBF_A_Pool *pool);

extern void *ubf_a_pool_alloc(UBF_A_Pool *pool, size_t amount);

extern char const *ubf_a_error_message(UBF_A_Error error);

extern UBF_A_Error ubf_a_start_decode(UBF_A_DecoderState *stateptr,
				      UBF_A_Pool *pool,
				      UBF_A_CharSource source, void *source_arg);
extern UBF_A_Error ubf_a_update_decode(UBF_A_DecoderState state, int *finished);
extern void ubf_a_finish_decode(UBF_A_DecoderState state);

extern UBF_A_Error ubf_a_decode(UBF_A_Pool *pool, UBF_A_CharSource source, void *source_arg);
extern UBF_A_Error ubf_a_encode(UBF_A_Object const *o, UBF_A_CharSink sink, void *sink_arg);

extern UBF_A_Object *ubf_a_number(UBF_A_Pool *pool, signed long long num);
extern UBF_A_Object *ubf_a_string(UBF_A_Pool *pool, char const *str);
extern UBF_A_Object *ubf_a_string_nocopy(UBF_A_Pool *pool, size_t len);
extern UBF_A_Object *ubf_a_symbol(UBF_A_Pool *pool, char const *sym);
extern UBF_A_Object *ubf_a_binary(UBF_A_Pool *pool, char const *bin, size_t len);
extern UBF_A_Object *ubf_a_binary_nocopy(UBF_A_Pool *pool, size_t len);
extern UBF_A_Object *ubf_a_tag(UBF_A_Pool *pool, char const *key, UBF_A_Object *value);
extern UBF_A_Object *ubf_a_pair(UBF_A_Pool *pool, UBF_A_Object *head, UBF_A_Object *tail);
extern UBF_A_Object *ubf_a_list(UBF_A_Pool *pool, ...);
extern UBF_A_Object *ubf_a_vector_init(UBF_A_Pool *pool, size_t len, ...);
extern UBF_A_Object *ubf_a_vector(UBF_A_Pool *pool, size_t len);

extern void ubf_a_list_reverse(UBF_A_Object **list);
extern int ubf_a_compare(UBF_A_Object const *left, UBF_A_Object const *right);

#ifdef __cplusplus
}
#endif

#endif

