#ifndef MOE_MB_H

#define MOE_MB_H

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>

#include <mbversion.h>
#include <mbcesconf.h>
#include <mblangconf.h>
#include <btri.h>
#include <wcrx.h>

#define MB_ESC_LEN_MAX (5)

typedef uirx_wc_t mb_wchar_t;

enum {
  mb_G0,
  mb_G1,
  mb_G2,
  mb_G3,
  mb_Gn,
  mb_UTF8,
  mb_UTF16,
  mb_UTF16BE,
  mb_UTF16LE,
  mb_MOEINTERNAL,
#undef defces
#define defces(cesname, mapname) mb_ ## cesname,
#include <mbcesdefs.h>
  mb_GN,
};

enum {
  mb_SL,
  mb_SR,
  mb_SSL,
  mb_SSR,
  mb_Sn,
};

enum {
  mb_94x94,
  mb_96,
  mb_94,
  mb_NON_ISO2022_set,
  mb_SBC = mb_NON_ISO2022_set,
  mb_DBC,
  mb_nSETs,
};

/* BEGIN h2ph */

#define MB_MBC_LEN_MAX (4)
#define MB_UCS_BITLEN_MAX (21)
#define MB_NON_UCS_LOWER (1U << MB_UCS_BITLEN_MAX)
#define MB_NON_UCS_MARK ((~0U << MB_UCS_BITLEN_MAX) & ~(~0U << (MB_MBC_LEN_MAX * 6)))

#define MB_U2I_POOL_LAST_MARK (1U << 31)

#define MB_Gn_LEN (2)
#define MB_Gn_MASK ((1U << MB_Gn_LEN) - 1U)
#define MB_Sn_LEN (2)
#define MB_Sn_MASK ((1U << MB_Gn_LEN) - 1U)
#define MB_GnSn_ENC(gn, sn) (((sn) << MB_Gn_LEN) | (gn))
#define MB_GnSn_ENC_Gn(gnsn) ((gn) & MB_Gn_MASK)
#define MB_GnSn_ENC_Sn(gnsn) (((sn) >> MB_Gn_LEN) & MB_Sn_MASK)

#define MB_ESC_FC_LEN (6)
#define MB_ESC_FC_MASK ((1U << MB_ESC_FC_LEN) - 1U)
#define MB_ESC_FC_BASE (1U << MB_ESC_FC_LEN)
#define MB_ESC_IC_LEN (2)
#define MB_ESC_IC_MASK ((1U << MB_ESC_IC_LEN) - 1U)

#define MB_ASCII_FC (0x42)
#define MB_UTF8_BEG "\x47"
#define MB_NOTCHAR_FC (0x40)
#define MB_CTL_FC (0x41)
#define MB_UCS_FC (0x40)
#define MB_FAKEUCS_FC (0x41)

#define MB_94_UNIT (94)
#define MB_94_LOWER (MB_NON_UCS_LOWER)
#define MB_94_UPPER (MB_94_LOWER + (1U << (MB_ESC_IC_LEN + MB_ESC_FC_LEN)) * MB_94_UNIT)

#define MB_96_UNIT (96)
#define MB_96_LOWER (MB_94_UPPER)
#define MB_96_UPPER (MB_96_LOWER + (1U << (MB_ESC_IC_LEN + MB_ESC_FC_LEN)) * MB_96_UNIT)

#define MB_SBC_UNIT_LEN (7)
#define MB_SBC_UNIT (1U << MB_SBC_UNIT_LEN)
#define MB_SBC_UNIT_MASK (MB_SBC_UNIT - 1U)
#define MB_SBC_LOWER (MB_96_UPPER)
#define MB_SBC_UPPER (MB_SBC_LOWER + (1U << (MB_ESC_IC_LEN + MB_ESC_FC_LEN + MB_SBC_UNIT_LEN)))

#define MB_SBC_ESC_LEN (MB_ESC_IC_LEN + MB_ESC_FC_LEN)
#define MB_SBC_ESC_MASK ((1U << MB_SBC_ESC_LEN) - 1U)
#define MB_SBC_ESC_ENC(fc) (((fc) & ~MB_ESC_FC_BASE) & MB_SBC_ESC_MASK)

#define MB_WORD_94_ENC(fc, c) ((fc) == MB_ASCII_FC ? (c) + 0x21 : MB_94_LOWER + MB_SBC_ESC_ENC((fc)) * MB_94_UNIT + (c))
#define MB_WORD_96_ENC(fc, c) (MB_96_LOWER + MB_SBC_ESC_ENC((fc)) * MB_96_UNIT + (c))
#define MB_WORD_SBC_ENC(fc, c) (MB_SBC_LOWER + MB_SBC_ESC_ENC((fc)) * MB_SBC_UNIT + (c))

#define MB_CTL_ENC(c) \
((unsigned char)(c) & ~MB_SBC_UNIT_MASK ? \
 MB_WORD_SBC_ENC(MB_CTL_FC, (unsigned char)(c) & MB_SBC_UNIT_MASK) : \
 (unsigned char)(c))

#define MB_MBC_LOWER (MB_SBC_UPPER)

#define MB_DBC_FC_LEN (MB_ESC_FC_LEN - 1)
#define MB_DBC_FC_MASK ((1U << MB_DBC_FC_LEN) - 1U)

#define MB_94x94_UNIT (94 * 94)
#define MB_94x94_LOWER (MB_MBC_LOWER)
#define MB_94x94_UPPER (MB_94x94_LOWER + (1U << (MB_ESC_IC_LEN + MB_DBC_FC_LEN)) * MB_94x94_UNIT)

#define MB_DBC_UNIT_LEN (15)
#define MB_DBC_UNIT (1U << MB_DBC_UNIT_LEN)
#define MB_DBC_UNIT_MASK (MB_DBC_UNIT - 1U)
#define MB_DBC_LOWER (MB_94x94_UPPER)
#define MB_DBC_UPPER (MB_DBC_LOWER + (1U << (MB_ESC_IC_LEN + MB_DBC_FC_LEN + MB_DBC_UNIT_LEN)))

#define MB_DBC_ESC_LEN (MB_ESC_IC_LEN + MB_DBC_FC_LEN)
#define MB_DBC_ESC_MASK ((1U << MB_DBC_ESC_LEN) - 1U)
#define MB_DBC_ESC_ENC(fc) (((fc) & ~MB_ESC_FC_BASE) & MB_DBC_ESC_MASK)

#define MB_WORD_94x94_ENC(fc, c) (MB_94x94_LOWER + MB_DBC_ESC_ENC((fc)) * MB_94x94_UNIT  + (c))
#define MB_WORD_DBC_ENC(fc, c) (MB_DBC_LOWER + MB_DBC_ESC_ENC((fc)) * MB_DBC_UNIT  + (c))

#define MB_WORD_ENC(set, fc, c) \
((set) < mb_SBC ? ((set) < mb_96 ? MB_WORD_94x94_ENC((fc), (c)) : \
		   (set) < mb_94 ? MB_WORD_96_ENC((fc), (c)) : \
		   (fc) == MB_ASCII_FC ? (c) + 0x21 : MB_WORD_94_ENC((fc), (c))) : \
 (set) < mb_DBC ? MB_WORD_SBC_ENC((fc), (c)) : \
 (fc) == MB_UCS_FC ? (c) : MB_WORD_DBC_ENC((fc), (c)))

#define MB_IN_JISC6226 (1 << 0)
#define MB_IN_JISX0208 (1 << 1)
#define MB_IN_JISX0213_1 (1 << 2)
#define MB_IN_JIS1COMMON (MB_IN_JISC6226 | MB_IN_JISX0208 | MB_IN_JISX0213_1)

#define MB_CPROP_IS_SPACE (1 << 0)
#define MB_CPROP_NEVER_BOL (1 << 1)
#define MB_CPROP_NEVER_EOL (1 << 2)
#define MB_CPROP_MAY_BREAK (1 << 3)
#define MB_CPROP_EOL_TO_NULL (1 << 4)
#define MB_NCPROPS (5)

/* END h2ph */

enum {
  mb_notchar_continue = MB_WORD_SBC_ENC(MB_NOTCHAR_FC, 0x00),
  mb_notchar_enc_invalid,
  mb_notchar_enc_short,
  mb_notchar_eof,
  mb_notchar_bof,
};

#define MB_WORD_SBC_FC_DEC(fc) (((fc) & MB_SBC_ESC_MASK) | MB_ESC_FC_BASE)
#define MB_WORD_DO_SBC_DEC(enc, fc, lo, u) ((fc) = MB_WORD_SBC_FC_DEC(((enc) - (lo)) / (u)), ((enc) - (lo)) % (u))

#define MB_WORD_94_DEC(enc, set, fc) ((set) = mb_94, MB_WORD_DO_SBC_DEC((enc), (fc), MB_94_LOWER, MB_94_UNIT))
#define MB_WORD_96_DEC(enc, set, fc) ((set) = mb_96, MB_WORD_DO_SBC_DEC((enc), (fc), MB_96_LOWER, MB_96_UNIT))
#define MB_WORD_SBC_DEC(enc, set, fc) ((set) = mb_SBC, MB_WORD_DO_SBC_DEC((enc), (fc), MB_SBC_LOWER, MB_SBC_UNIT))

#define MB_WORD_DBC_FC_DEC(fc) (((fc) & MB_DBC_ESC_MASK) | MB_ESC_FC_BASE)
#define MB_WORD_DO_DBC_DEC(enc, fc, lo, u) ((fc) = MB_WORD_DBC_FC_DEC(((enc) - (lo)) / (u)), ((enc) - (lo)) % (u))

#define MB_WORD_94x94_DEC(enc, set, fc) ((set) = mb_94x94, MB_WORD_DO_DBC_DEC((enc), (fc), MB_94x94_LOWER, MB_94x94_UNIT))
#define MB_WORD_DBC_DEC(enc, set, fc) ((set) = mb_DBC, MB_WORD_DO_DBC_DEC((enc), (fc), MB_DBC_LOWER, MB_DBC_UNIT))

#define MB_WORD_NON_UCS_DEC(enc, set, fc) \
((enc) < MB_MBC_LOWER ? \
 (enc) < MB_96_LOWER ? MB_WORD_94_DEC((enc), (set), (fc)) : \
 (enc) < MB_SBC_LOWER ? MB_WORD_96_DEC((enc), (set), (fc)) : MB_WORD_SBC_DEC((enc), (set), (fc)) : \
 (enc) < MB_DBC_LOWER ? MB_WORD_94x94_DEC((enc), (set), (fc)) : MB_WORD_DBC_DEC((enc), (set), (fc)))

#define MB_WORD_UCS_DEC(enc, set, fc) \
(((enc) < 0x21 || (enc) > 0x7E) ? \
 ((set) = mb_DBC, (fc) = MB_UCS_FC, (enc)) : \
 ((set) = mb_94, (fc) = MB_ASCII_FC, (enc) - 0x21))

#define MB_WORD_DEC(enc, set, fc) \
((enc) & MB_NON_UCS_MARK ? \
 MB_WORD_NON_UCS_DEC((enc), (set), (fc)) : \
 MB_WORD_UCS_DEC((enc), (set), (fc)))

#define MB_FLAG_DONTFLUSH_BUFFER (1 << 0)
#define MB_FLAG_ASCIIATCTL (1 << 1)
#define MB_FLAG_28FOR94X94G0 (1 << 2)
#define MB_FLAG_UNKNOWNCS (1 << 3)
#define MB_FLAG_NOSSL (1 << 4)
#define MB_FLAG_DISCARD_NOTPREFERED_CHAR (1 << 5)
#define MB_FLAG_CS_DETECTING (1 << 6)

#define MB_WCHAR_WIDTH(wc) ((wc) & MB_NON_UCS_MARK ? (wc) < MB_MBC_LOWER ? 1 : 2 : mb_ucs_width((wc)))

#define MB_ENCODE_TO_WS (1U << 0)
#define MB_ENCODE_SKIP_INVALID (1U << 1)
#define MB_ENCODE_SKIP_SHORT (1U << 2)

typedef enum {
  mb_flag_plus,
  mb_flag_minus,
  mb_flag_set,
  mb_flag_noop,
} mb_flag_op_t;

struct mb_ces_st;
typedef mb_wchar_t (*mb_conv_t)(mb_wchar_t wc, struct mb_ces_st *ces);

typedef struct mb_setup_st {
  mb_flag_op_t flag_op;
  int flag;
  const char *cs;
} mb_setup_t;

typedef struct mb_G_st {
  unsigned char l;
  unsigned char r;
  unsigned char set[mb_Gn];
  unsigned char fc[mb_Gn];
} mb_G_t;

typedef struct mb_GnSn_st {
  unsigned char gn, sn;
} mb_GnSn_t;

typedef struct mb_chartype_st {
  unsigned char set;
  unsigned char fc;
} mb_chartype_t;

typedef struct mb_wchar_range_st {
  mb_wchar_t wchar_min;
  mb_wchar_t wchar_max;
  size_t n;
} mb_wchar_range_t;

struct mb_char_node_st;

typedef struct mb_char_map_st {
  struct mb_char_node_st *v;
  size_t e;
  mb_wchar_range_t *dectab;
  size_t *bv;
} mb_char_map_t;

struct mb_info_st;
typedef mb_wchar_t (*mb_encoder_func_t)(mb_wchar_t wc, void *arg, struct mb_info_st *info);
typedef size_t (*mb_decoder_func_t)(mb_wchar_t wc, void *arg, struct mb_info_st *info);
typedef size_t (*mb_default_decoder_func_t)(mb_wchar_t wc, struct mb_info_st *info);

typedef struct mb_char_node_st {
  int char_min;
  int char_max;
  mb_wchar_range_t *wcv;
  mb_encoder_func_t func;
  void *arg;
  mb_char_map_t next;
} mb_char_node_t;

typedef struct mb_encoder_st {
  mb_wchar_range_t *wcv;
  mb_char_node_t *node;
} mb_encoder_t;

typedef struct mb_encoder_map_st {
  mb_encoder_t *nv;
  short *iv;
} mb_encoder_map_t;

typedef struct mb_decoder_st {
  mb_decoder_func_t func;
  void *arg;
  mb_wchar_t wchar_base;
  mb_char_map_t *map;
  size_t wcv_pos;
} mb_decoder_t;

typedef struct mb_decoder_map_st {
  mb_wchar_range_t *tab;
  size_t n;
  mb_decoder_t *dest;
} mb_decoder_map_t;

typedef struct mb_ces_st {
  const char **namev;
  mb_flag_op_t flag_op;
  int flag;
  mb_G_t G;
  mb_conv_t *convv;
  mb_decoder_map_t *decoder;
  size_t (*default_decoder)(mb_wchar_t, struct mb_info_st *);
  int auto_detect_factor;
} mb_ces_t;

typedef struct mb_info_st {
  int flag;
  mb_G_t G;
  mb_G_t Gsave;
  unsigned char GRB4;
  mb_encoder_map_t *encoder;
  char *buf;
  size_t size, b, e, i;
  char auxbuf[MB_MBC_LEN_MAX];
  size_t aux_i, aux_n;
  struct mb_ces_st *ces;
  union {
    size_t (*in)(char *s, size_t n, void *io_arg);
    size_t (*out)(const char *s, size_t n, void *io_arg);
  } io_func;
  void *io_arg;
} mb_info_t;

typedef size_t (*mb_ws_conv_t)(mb_wchar_t *ws, mb_wchar_t *ws_end, mb_info_t *info);

#define MB_MEM_DELTA (32)

typedef struct mb_b64opt_st {
  size_t llen;
  const char *pre;
  size_t pree;
  const char *post;
  size_t poste;
  const char *eol;
  size_t eole;
} mb_b64opt_t;

typedef struct mb_b64_st {
  mb_b64opt_t *opt;
  int enc_p;
  size_t se;
  char d[4];
  size_t dn;
  mb_info_t *orig;
} mb_b64_t;

#define MB_MEM_BIG_DELTA (BUFSIZ)

#define MB_CS_DETECT_FLAG_MKUNBOUND (1 << 0)

#define MB_CS_DETECT_CHOICEMAX (16)

struct mb_cs_detector_stat_st;
struct mb_cs_detector_st;

typedef void (*mb_cs_judge_encoding_t)(struct mb_cs_detector_stat_st *, const char *, size_t);
typedef size_t (*mb_cs_judge_t)(struct mb_cs_detector_st *);
typedef char *(*mb_cs_setup_t)(struct mb_cs_detector_st *, size_t, size_t);

typedef struct mb_cs_detector_stat_st {
  mb_ces_t *ces;
  size_t processed;
  long by_encode, by_char;
} mb_cs_detector_stat_t;

typedef struct mb_cs_detector_st {
  int flag;
  size_t nstats;
  void *(*realloc_bag)(void *, size_t);
  void (*free_bag)(void *);
  void (*free_detector)(void *);
  mb_cs_detector_stat_t stat[MB_CS_DETECT_CHOICEMAX];
  size_t samev[MB_CS_DETECT_CHOICEMAX];
  mb_info_t *orig, copy;
  size_t limit;
  long processed;
} mb_cs_detector_t;

typedef struct mb_flag_tab_st {
  int value, mask;
} mb_flag_tab_t;

#include <mbces.h>

/* iso2mb.c */
extern char mb_version_string[];
extern int mb_version;
extern int mb_call_getc_internal(mb_info_t *info);

#define mb_call_getc(info) \
((info)->i < (info)->e ? \
 (unsigned char)(info)->buf[((info)->i)++] : \
 mb_call_getc_internal((info)))

extern void mb_fill_inbuf(mb_info_t *info, const char *s, size_t n);
extern mb_wchar_t mb_encode_failure(mb_info_t *info);
extern mb_wchar_t mb_94x94_encoder(int c1, int gn, mb_info_t *info);
extern mb_wchar_t mb_96_encoder(int c1, int gn, mb_info_t *info);
extern unsigned int *mb_set_localized_ascii_table(unsigned int *new);
extern mb_wchar_t mb_94_encoder(int c1, int gn, mb_info_t *info);
extern mb_wchar_t (*mb_iso2022_encoderv[])(int c1, int gn, mb_info_t *info);

#define mb_iso2022_encoder(c1, gn, info) \
(((gn) < mb_Gn && (info)->G.set[(gn)] < mb_NON_ISO2022_set) ? \
 mb_iso2022_encoderv[(info)->G.set[(gn)]]((c1), (gn), (info)) : \
 mb_notchar_enc_invalid)

extern mb_wchar_t mb_iso2022_GL_encoder(mb_wchar_t c1, void *dummy_arg, mb_info_t *info);
extern mb_wchar_t mb_iso2022_GR_encoder(mb_wchar_t c1, void *dummy_arg, mb_info_t *info);
extern mb_wchar_t mb_iso2022_SSL_encoder(mb_wchar_t c1, void *dummy_arg, mb_info_t *info);
extern mb_wchar_t mb_iso2022_SSR_encoder(mb_wchar_t c1, void *dummy_arg, mb_info_t *info);
extern mb_encoder_map_t *mb_encoder_map[mb_GN];
extern void mb_update_encoder(unsigned int gl, unsigned int gr, mb_info_t *info);
extern mb_wchar_t mb_ctl_encoder(mb_wchar_t c, void *arg, mb_info_t *info);
extern mb_wchar_t mb_escfun_sl01(mb_wchar_t c, void *arg, mb_info_t *info);
extern mb_wchar_t mb_escfun_cs_94x94(mb_wchar_t c, void *arg, mb_info_t *info);
extern mb_wchar_t mb_escfun_cs_misc(mb_wchar_t c, void *arg, mb_info_t *info);
extern mb_wchar_t mb_escfun_cs_return(mb_wchar_t c, void *arg, mb_info_t *info);
extern mb_wchar_t mb_escfun_cs_utf8(mb_wchar_t c, void *arg, mb_info_t *info);
extern mb_wchar_t mb_escfun_cs_utf16(mb_wchar_t c, void *arg, mb_info_t *info);
extern mb_wchar_t mb_escfun_cs_rev(mb_wchar_t c, void *arg, mb_info_t *info);
extern mb_wchar_t mb_escfun_cs_94(mb_wchar_t c, void *arg, mb_info_t *info);
extern mb_wchar_t mb_escfun_cs_94_i(mb_wchar_t c, void *arg, mb_info_t *info);
extern mb_wchar_t mb_escfun_cs_96(mb_wchar_t c, void *arg, mb_info_t *info);
extern mb_wchar_t mb_escfun_sl23(mb_wchar_t c, void *arg, mb_info_t *info);
extern mb_wchar_t mb_escfun_sr(mb_wchar_t c, void *arg, mb_info_t *info);
extern mb_wchar_t mb_utf16_encoder(mb_wchar_t c1, void *arg, mb_info_t *info);
extern mb_wchar_t mb_utf16le_encoder(mb_wchar_t c1, void *arg, mb_info_t *info);
extern size_t mb_apply_convv(mb_wchar_t *ws, mb_wchar_t *ws_end, mb_ws_conv_t *v, mb_info_t *info);
extern mb_wchar_t mb_encode(mb_info_t *info, int wc_p, void **p_to, void *to_end);

#define MB_ENCODE_TO_WCHAR \
{ \
  void *to_temp; \
  mb_wchar_t wcv[1]; \
\
  to_temp = wcv; \
  return mb_encode(info, MB_ENCODE_TO_WS, &to_temp, wcv + 1); \
}

#ifdef __GNUC__
extern __inline__ mb_wchar_t mb_encode_to_wchar(mb_info_t *info) MB_ENCODE_TO_WCHAR
#else
extern mb_wchar_t mb_encode_to_wchar(mb_info_t *info);
#endif

#define MB_FETCH_WCHAR \
{ \
  void *to_temp; \
  mb_wchar_t wcv[1]; \
\
  to_temp = wcv; \
  return mb_encode(info, MB_ENCODE_TO_WS | MB_ENCODE_SKIP_INVALID | MB_ENCODE_SKIP_SHORT, &to_temp, wcv + 1); \
}

#ifdef __GNUC__
extern __inline__ mb_wchar_t mb_fetch_wchar(mb_info_t *info) MB_FETCH_WCHAR
#else
extern mb_wchar_t mb_fetch_wchar(mb_info_t *info);
#endif

#define mb_wchar_to_mbc(c, buf) \
((c) < 0x80 ? \
 ((buf)[0] = (c), 1) : \
 ((buf)[0] = 0xC0 | (((c) >> 18) & 0x3F), \
  (buf)[1] = 0x80 | (((c) >> 12) & 0x3F), \
  (buf)[2] = 0x80 | (((c) >> 6) & 0x3F), \
  (buf)[3] = 0x80 | ((c) & 0x3F), \
  MB_MBC_LEN_MAX))

extern int mb_unfetch_char(int c, mb_info_t *info);
extern int mb_getc(mb_info_t *info);
extern size_t mb_getmbc(char *d, mb_info_t *info);
extern size_t mb_getmem(char *d, size_t n, mb_info_t *info);
extern char *mb_getline(char *d, int n, mb_info_t *info);
extern char *mb_info2mb(mb_info_t *info, size_t n, size_t *p_end);
extern void mb_vmem2mb_setup(mb_info_t *info, const char *s, size_t n, mb_setup_t *setup, const char *op, va_list ap);
extern void mb_mem2mb_setup(mb_info_t *info, const char *s, size_t n, mb_setup_t *setup, const char *op, ...);
extern char *mb_vmem2mb(const char *s, size_t n, size_t *p_end, mb_setup_t *setup, const char *op, va_list ap);
extern char *mb_mem2mb(const char *s, size_t n, size_t *p_end, mb_setup_t *setup, const char *op, ...);
extern char *mb_vstr2mb(const char *s, size_t *p_end, mb_setup_t *setup, const char *op, va_list ap);
extern char *mb_str2mb(const char *s, size_t *p_end, mb_setup_t *setup, const char *op, ...);
extern void mb_mkunbound_cs_detector(mb_cs_detector_t *p);
extern size_t mb_cs_detector_find_best(mb_cs_detector_t *p, size_t *p_same);
extern unsigned int *mb_set_wchar_weight_tab(unsigned int *new);
extern void mb_cs_try_detect(mb_cs_detector_t *p);
extern void mb_restore_G(mb_info_t *info, mb_G_t *G, mb_G_t *Gsave);
extern void mb_setup_by_detected_ces(mb_ces_t *ces, mb_info_t *info);
extern mb_wchar_t mb_cs_detect_encode(mb_info_t *info, int flag, void **p_to, void *to_end);
extern void mb_bind_cs_detector(mb_cs_detector_t *p, mb_info_t *info);
extern mb_cs_detector_t *mb_alloc_cs_detector(mb_info_t *info, size_t init, size_t limit);

/* mb2iso.c */
extern size_t mb_store_mem_once(const char *s, size_t n, mb_info_t *info);
extern size_t mb_store_mem(const char *s, size_t n, mb_info_t *info);
extern size_t mb_flush_buffer(mb_info_t *info);
extern size_t mb_force_flush_buffer(size_t min, mb_info_t *info);

#define mb_store_octet(o, info) \
(!((info)->e < (info)->size) ? mb_force_flush_buffer(1, (info)) : 0U, \
 ((info)->buf[((info)->e)++] = (o)))

extern void mb_store_esc_for_char_internal(mb_GnSn_t *gnsn, mb_chartype_t *ct, mb_info_t *info);

#define mb_store_esc_for_char(gnsn, ct, info) \
(((info)->G.set[(gnsn)->gn] != (ct)->set || \
  (info)->G.fc[(gnsn)->gn] != (ct)->fc || \
  ((gnsn)->sn == mb_SL ? (info)->G.l != (gnsn)->gn : \
   (gnsn)->sn == mb_SR ? (info)->G.r != (gnsn)->gn : 1)) ? \
 (mb_store_esc_for_char_internal((gnsn), (ct), (info)), 1) : 0)

extern mb_GnSn_t mb_G0SL;
extern mb_GnSn_t mb_G1SL;
extern mb_GnSn_t mb_G1SR;
extern mb_GnSn_t mb_G2SL;
extern mb_GnSn_t mb_G2SR;
extern mb_GnSn_t mb_G2SSL;
extern mb_GnSn_t mb_G2SSR;
extern mb_GnSn_t mb_G3SL;
extern mb_GnSn_t mb_G3SR;
extern mb_GnSn_t mb_G3SSL;
extern mb_GnSn_t mb_G3SSR;
extern size_t mb_94x94L_decoder(mb_wchar_t wc, void *arg, mb_info_t *info);
extern size_t mb_94x94R_decoder(mb_wchar_t wc, void *arg, mb_info_t *info);
extern size_t mb_96L_decoder(mb_wchar_t wc, void *arg, mb_info_t *info);
extern size_t mb_96R_decoder(mb_wchar_t wc, void *arg, mb_info_t *info);
extern size_t mb_94L_decoder(mb_wchar_t wc, void *arg, mb_info_t *info);
extern size_t mb_94R_decoder(mb_wchar_t wc, void *arg, mb_info_t *info);
extern size_t mb_CLGL_decoder(mb_wchar_t wc, void *arg, mb_info_t *info);
extern size_t mb_utf16_decoder(mb_wchar_t wc, void *arg, mb_info_t *info);
extern size_t mb_utf16le_decoder(mb_wchar_t wc, void *arg, mb_info_t *info);
extern void mb_store_esc(mb_G_t *new, mb_info_t *info);
extern size_t mb_store_char_noconv(int c, mb_info_t *info);
#define mb_store_sbc(c, info) (((c) >= 0x21 && (c) <= 0x7E) ? mb_store_wchar((c), (info)) : mb_store_char_noconv((c), (info)))
extern size_t mb_default_decoder(mb_wchar_t enc, mb_info_t *info);
extern mb_default_decoder_func_t mb_setup_fallback_decoder(mb_default_decoder_func_t new);
extern unsigned char *mb_set_domestic_ascii_table(unsigned char *new);
extern size_t mb_conv_ascii(mb_wchar_t *ws, mb_wchar_t *ws_end, mb_info_t *info);
extern int mb_get_jis1flag(mb_wchar_t c);
extern size_t mb_conv_to_jisx0213(mb_wchar_t *ws, mb_wchar_t *ws_end, mb_info_t *info);
extern size_t mb_conv_to_jisx0213_aggressive(mb_wchar_t *ws, mb_wchar_t *ws_end, mb_info_t *info);
#ifdef USE_UCS
extern size_t mb_conv_to_ucs(mb_wchar_t *ws, mb_wchar_t *ws_end, mb_info_t *info);
extern mb_wchar_t mb_conv1_to_ucs(mb_wchar_t wc, mb_ces_t *ces);
extern size_t mb_conv_f2h(mb_wchar_t *ws, mb_wchar_t *ws_end, mb_info_t *info);
extern size_t mb_conv_h2f(mb_wchar_t *ws, mb_wchar_t *ws_end, mb_info_t *info);
extern mb_wchar_t mb_conv_for_decoder(mb_wchar_t wc, mb_decoder_map_t *decmap);
#ifdef USE_WIN1252
extern size_t mb_conv_ms_latin1(mb_wchar_t *ws, mb_wchar_t *ws_end, mb_info_t *info);
#endif
#endif
extern size_t mb_decode(mb_wchar_t *from, mb_wchar_t *from_end, mb_info_t *info);

#define MB_STORE_WCHAR \
{ \
  return mb_decode(&enc, &enc + 1, info); \
}

#ifdef __GNUC__
extern __inline__ size_t mb_store_wchar(mb_wchar_t enc, mb_info_t *info) MB_STORE_WCHAR
#else
extern size_t mb_store_wchar(mb_wchar_t enc, mb_info_t *info);
#endif

extern size_t mb_conv_for_specific_ces(mb_wchar_t *ws, mb_wchar_t *ws_end, mb_ces_t *ces);
extern size_t mb_conv_for_ces(mb_wchar_t *ws, mb_wchar_t *ws_end, mb_info_t *info);

#define mb_mem_to_wchar_internal(s, e, wc) \
((e) > 0 ? \
 ((unsigned char)(s)[0] < 0x80 ? \
  ((wc) = (unsigned char)(s)[0], 1) : \
  (e) >= MB_MBC_LEN_MAX ? \
  ((wc) = ((((unsigned char)(s)[0] & 0x3F) << 18) | \
	   (((unsigned char)(s)[1] & 0x3F) << 12) | \
	   (((unsigned char)(s)[2] & 0x3F) << 6) | \
	   ((unsigned char)(s)[3] & 0x3F)), \
   MB_MBC_LEN_MAX) : \
  ((wc) = (unsigned char)(s)[0], -1)) : \
 ((wc) = mb_notchar_eof, 0))

#define mb_str_to_wchar_internal(s, wc) \
((unsigned char)(s)[0] < 0x80 ? \
 ((s)[0] ? ((wc) = (unsigned char)(s)[0], 1) : ((wc) = mb_notchar_eof, 0)) : \
 ((s)[1] && (s)[2] && (s)[3]) ? \
 ((wc) = ((((unsigned char)(s)[0] & 0x3F) << 18) | \
	  (((unsigned char)(s)[1] & 0x3F) << 12) | \
	  (((unsigned char)(s)[2] & 0x3F) << 6) | \
	  ((unsigned char)(s)[3] & 0x3F)), \
  MB_MBC_LEN_MAX) : \
 ((wc) = (unsigned char)(s)[0], -1))

extern size_t mb_store_char(const char *s, size_t e, mb_info_t *info);
extern int mb_putc(int c, mb_info_t *info);
extern size_t mb_putmem(const char *s, size_t n, mb_info_t *info);
extern size_t mb_putstr(const char *s, mb_info_t *info);
extern void mb_flush_auxbuf(mb_info_t *info);
extern void mb_flush(mb_info_t *info);
extern char *mb_vmem2iso_setup(mb_info_t *info, size_t n, mb_setup_t *setup, const char *op, va_list ap);
extern char *mb_mem2iso_setup(mb_info_t *info, size_t n, mb_setup_t *setup, const char *op, ...);
extern char *mb_vmem2iso(const char *s, size_t *p_n, mb_setup_t *setup, const char *op, va_list ap);
extern char *mb_mem2iso(const char *s, size_t *p_n, mb_setup_t *setup, const char *op, ...);
extern char *mb_vstr2iso(const char *s, mb_setup_t *setup, const char *op, va_list ap);
extern char *mb_str2iso(const char *s, mb_setup_t *setup, const char *op, ...);
extern int mb_vprintf(mb_info_t *info, const char *format, va_list ap);
extern int mb_printf(mb_info_t *info, const char *format, ...);
extern size_t mb_putmem_b64encode(const char *s, size_t se, mb_b64opt_t *b64opt, mb_info_t *info);
extern char *mb_vmem2b64(const char *s, size_t *p_n, const char *title, mb_setup_t *setup, const char *op, va_list ap);
extern char *mb_mem2b64(const char *s, size_t *p_n, const char *title, mb_setup_t *setup, const char *op, ...);
extern char *mb_vstr2b64(const char *s, const char *title, mb_setup_t *setup, const char *op, va_list ap);
extern char *mb_str2b64(const char *s, const char *title, mb_setup_t *setup, const char *op, ...);

/* mbinit.c */
extern void mb_setup_by_ces(mb_ces_t *p, mb_info_t *info);
extern btri_string_tab_t *mb_set_ces_tab(btri_string_tab_t *new);
extern void mb_ces_by_name(const char *cs, mb_info_t *info);
extern void mb_vsetsetup(mb_setup_t *setup, const char *op, va_list ap);
extern void mb_setsetup(mb_setup_t *setup, const char *op, ...);
extern void mb_vsetup(mb_info_t *info, mb_setup_t *dflt, const char *op, va_list ap);
extern void mb_setup(mb_info_t *info, mb_setup_t *dflt, const char *op, ...);
extern void mb_vinit(mb_info_t *info, void *arg, mb_setup_t *dflt, const char *op, va_list ap);
extern void mb_init(mb_info_t *info, void *arg, mb_setup_t *dflt, const char *op, ...);
extern void mb_vinit_r(mb_info_t *info, void *arg,
		       size_t (*func)(char *s, size_t, void *),
		       mb_setup_t *dflt, const char *op, va_list ap);
extern void mb_init_r(mb_info_t *info, void *arg,
		      size_t (*func)(char *s, size_t, void *),
		      mb_setup_t *dflt, const char *op, ...);
extern void mb_vinit_w(mb_info_t *info, void *arg,
		       size_t (*func)(const char *, size_t, void *),
		       mb_setup_t *dflt, const char *op, va_list ap);
extern void mb_init_w(mb_info_t *info, void *arg,
		      size_t (*func)(const char *, size_t, void *),
		      mb_setup_t *dflt, const char *op, ...);
extern size_t mb_namev_to_converterv(const char *s, mb_ws_conv_t *v, size_t max, void (*ehook)(const char *, size_t));
extern int mb_namev_to_flag(const char *s, int flag, void (*ehook)(const char *, size_t));
extern int mb_lang_to_detector(const char *s, mb_cs_detector_stat_t *statv, size_t *p_nstats);

/* mbfind.c */
extern mb_wchar_t mb_mem_to_wchar(const char *s, size_t *p_b, size_t *p_e);
extern mb_wchar_t mb_str_to_wchar(const char **p_s);
extern const char *mb_mem_to_wstr(const char *from, const char *from_end, mb_wchar_t **p_to, mb_wchar_t *to_end);
extern const char *mb_str_to_wstr(const char *from, mb_wchar_t **p_to, mb_wchar_t *to_end);
extern void mb_set_widthtable(char *term);
extern size_t mb_ucs_width(mb_wchar_t wc);
extern size_t mb_mem_width(const char *s, size_t n);
extern size_t mb_str_width(const char *s);
extern size_t mb_str_width_n(const char *s, size_t n);
extern size_t mb_wmem_width(const mb_wchar_t *s, size_t n);
extern size_t mb_wstr_width(const mb_wchar_t *s);
extern size_t mb_wstr_width_n(const mb_wchar_t *s, size_t n);
extern int mb_wchar_prop(mb_wchar_t wc);
extern int mb_mem_to_prop(const char *s, size_t e);
extern int mb_str_to_prop(const char *s);

/* mbio.c */
extern void mb_vfsetup(FILE *fp, const char *op, va_list ap);
extern void mb_fsetup(FILE *fp, const char *op, ...);
extern void mb_vfsetup_default(const char *op, va_list ap);
extern void mb_fsetup_default(const char *op, ...);
extern FILE *mb_vfbind(FILE *fp, const char *mode, va_list ap);
extern FILE *mb_fbind(FILE *fp, const char *mode, ...);
extern FILE *mb_vfopen(const char *fn, const char *mode, va_list ap);
extern FILE *mb_fopen(const char *fn, const char *mode, ...);
extern FILE *mb_vfreopen(const char *fn, const char *mode, FILE *fp, va_list ap);
extern FILE *mb_freopen(const char *fn, const char *mode, FILE *fp, ...);
extern FILE *mb_vfdopen(int fd, const char *mode, va_list ap);
extern FILE *mb_fdopen(int fd, const char *mode, ...);
extern int mb_fclose(FILE *fp);
extern int mb_fgetpos(FILE *fp, fpos_t *p_pos);
extern int mb_fsetpos(FILE *fp, const fpos_t *p_pos);
extern long mb_ftell(FILE *fp);
extern int mb_fseek(FILE *fp, long off, int mode);
extern size_t mb_fread(char *d, size_t n, FILE *fp);
extern size_t mb_fwrite(const char *s, size_t n, FILE *fp);
#define mb_fputcstr(cstr, strm) (mb_fwrite(cstr, sizeof(cstr) - 1, (strm)))
extern size_t mb_fputs(const char *s, FILE *fp);
extern int mb_fgetc(FILE *fp);
extern mb_wchar_t mb_fgetwc(FILE *fp);
extern int mb_ungetc(int c, FILE *fp);
extern char *mb_fgets(char *d, size_t n, FILE *fp);
extern int mb_fputc(int c, FILE *fp);
extern mb_wchar_t mb_fputwc(mb_wchar_t wc, FILE *fp);
extern int mb_vfprintf(FILE *fp, const char *format, va_list ap);
extern int mb_fprintf(FILE *fp, const char *format, ...);
extern int mb_fflush(FILE *fp);
extern size_t mb_fgetmbc(char *d, FILE *fp);
extern size_t mb_fread_fromto(char *buf, size_t n, FILE *fp, long *p_from, long to);
extern mb_cs_detector_t *mb_fbind_cs_detector(mb_cs_detector_t *p, FILE *fp);
extern mb_cs_detector_t *mb_falloc_cs_detector(FILE *fp, size_t init, size_t limit);
extern int mb_finfo(FILE *fp, mb_info_t **p_info_r, mb_info_t **p_info_w);

/* jis0208-extra.c */
extern size_t mb_jisx0208_to_ucs_extra(mb_wchar_t *ws, mb_wchar_t *ws_end, mb_info_t *info);
extern size_t mb_ucs_to_jisx0208_extra(mb_wchar_t *ws, mb_wchar_t *ws_end, mb_info_t *info);

#endif
