pike.git / src / modules / _Charset / charsetmod.cmod

version» Context lines:

pike.git/src/modules/_Charset/charsetmod.cmod:1: + /* charsetmod.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. + */    -  + #include "config.h" + #include "global.h" + #include "program.h" + #include "interpret.h" + #include "stralloc.h" + #include "object.h" + #include "module_support.h" + #include "pike_error.h" + #include "builtin_functions.h" +  + #include "charsetmod.h" +  + #ifdef __CHAR_UNSIGNED__ + #define SIGNED signed + #else + #define SIGNED + #endif +  + #define DEFAULT_CMOD_STORAGE static +  + /*! @module _Charset +  *! +  *! Low-level tables and code for the @[Charset] module. +  *! +  *! This is probably not the module you want; try the @[Charset] module. +  *! +  *! @seealso +  *! @[Charset] +  */ +  + /* Remap old symbols */ + #define std_cs_stor cq__Charset_Std_CS_struct + #define std_cs_program cq__Charset_Std_CS_program +  + static struct program *utf1_program = NULL, *utf1e_program = NULL; + static struct program *utf7_program = NULL, *utf8_program = NULL; + static struct program *utf7e_program = NULL, *utf8e_program = NULL; + static struct program *utf_ebcdic_program = NULL, *utf_ebcdice_program = NULL; + static struct program *utf7_5_program = NULL, *utf7_5e_program = NULL; + static struct program *euc_program = NULL, *sjis_program = NULL; + static struct program *gbke_program = NULL; + static struct program *multichar_program = NULL, *gb18030e_program = NULL; + static struct program *rfc_base_program = NULL; + /* The following inherit rfc_base_program. */ + static struct program *std_rfc_program = NULL; + static struct program *euce_program = NULL, *sjise_program = NULL; + static struct program *std_94_program = NULL, *std_96_program = NULL; + static struct program *std_9494_program = NULL, *std_9696_program = NULL; + static struct program *std_big5_program = NULL; + static struct program *std_8bit_program = NULL, *std_8bite_program = NULL; + static struct program *std_16bite_program = NULL; +  + static size_t rfc_charset_name_offs = 0; +  + static struct array *double_custom_chars = NULL; + static struct array *double_combiner_chars = NULL; +  + DECLARATIONS; +  + struct std_rfc_stor { +  UNICHAR const *table; + }; + static size_t std_rfc_stor_offs = 0; +  + struct std_misc_stor { +  int lo, hi; + }; + static size_t std_misc_stor_offs = 0; +  + struct utf7_stor { +  INT32 dat, surro; +  int shift, datbit; + }; + static size_t utf7_stor_offs = 0; +  + struct euc_stor { +  UNICHAR const *table, *table2, *table3; +  struct pike_string *name; + }; + static size_t euc_stor_offs = 0; +  + struct multichar_stor { +  const struct multichar_table *table; +  int is_gb18030; +  struct pike_string *name; + }; + static size_t multichar_stor_offs = 0; +  + struct std8e_stor { +  p_wchar0 *revtab; +  unsigned lowtrans; +  int lo, hi; +  p_wchar2 zero_char; /* Character at code point 0x00 */ + }; + static size_t std8e_stor_offs = 0; +  + struct std16e_stor { +  p_wchar1 *revtab; +  unsigned lowtrans; +  int lo, hi; +  int sshift; + }; + static size_t std16e_stor_offs = 0; +  + static SIGNED char rev64t['z'-'+'+1]; + static char fwd64t[64]= + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +  + /* Start std_cs */ +  + PIKECLASS Std_CS +  flags ID_PROTECTED; + { +  CVAR struct string_builder strbuild; +  CVAR struct pike_string *retain, *replace; +  PIKEVAR mixed _repcb flags ID_PROTECTED; +  +  DECLARE_STORAGE; +  + PIKEFUN void create(string|void replace, function(string:string)|void repcb) + { +  struct std_cs_stor *s = THIS; +  +  if(replace) { +  if(s->replace != NULL) +  free_string(s->replace); +  add_ref(s->replace = replace); +  } +  +  if(repcb && TYPEOF(*repcb) == T_FUNCTION) +  assign_svalue(&s->_repcb, repcb); +  +  pop_n_elems(args); + } +  + PIKEFUN void set_replacement_callback(function(string:string) repcb) + { +  struct std_cs_stor *s = THIS; +  +  if(repcb) +  assign_svalue(&s->_repcb, repcb); +  +  push_object(this_object()); + } +  + PIKEFUN string drain() + { +  struct std_cs_stor *s = THIS; +  +  pop_n_elems(args); +  push_string(finish_string_builder(&s->strbuild)); +  init_string_builder(&s->strbuild, 0); + } +  + PIKEFUN object clear() + { +  struct std_cs_stor *s = THIS; +  +  pop_n_elems(args); +  +  if(s->retain != NULL) { +  free_string(s->retain); +  s->retain = NULL; +  } +  +  reset_string_builder(&s->strbuild); +  +  push_object(this_object()); + } +  + INIT + { +  struct std_cs_stor *s = THIS; +  +  s->retain = NULL; +  s->replace = NULL; +  +  init_string_builder(&s->strbuild,0); + } +  + EXIT + { +  struct std_cs_stor *s = THIS; +  +  if(s->retain != NULL) +  free_string(s->retain); +  +  if(s->replace != NULL) +  free_string(s->replace); +  +  free_string_builder(&s->strbuild); + } + } + /* End std_cs */ +  + static int call_repcb(struct svalue *repcb, p_wchar2 ch) + { +  push_string(make_shared_binary_string2(&ch, 1)); +  apply_svalue(repcb, 1); +  if(TYPEOF(Pike_sp[-1]) == T_STRING) +  return 1; +  pop_stack(); +  return 0; + } +  + static struct svalue decode_err_prog = SVALUE_INIT_INT (0); + static struct svalue encode_err_prog = SVALUE_INIT_INT (0); + static void DECLSPEC(noreturn) transcode_error_va ( +  struct pike_string *str, ptrdiff_t pos, struct pike_string *charset, +  int encode, const char *reason, va_list args) ATTRIBUTE((noreturn)); +  + static void DECLSPEC(noreturn) transcode_error_va ( +  struct pike_string *str, ptrdiff_t pos, struct pike_string *charset, +  int encode, const char *reason, va_list args) + /* Note: Consumes a ref to charset. */ + { +  struct svalue *err_prog; +  +  if (encode) { +  if (TYPEOF(encode_err_prog) == T_INT) { +  push_static_text ("Charset.EncodeError"); +  SAFE_APPLY_MASTER ("resolv", 1); +  if (TYPEOF(Pike_sp[-1]) != T_PROGRAM && TYPEOF(Pike_sp[-1]) != T_FUNCTION) +  Pike_error ("Failed to resolve Charset.EncodeError " +  "to a program - unable to throw an encode error.\n"); +  move_svalue (&encode_err_prog, --Pike_sp); +  } +  err_prog = &encode_err_prog; +  } +  +  else { +  if (TYPEOF(decode_err_prog) == T_INT) { +  push_static_text ("Charset.DecodeError"); +  SAFE_APPLY_MASTER ("resolv", 1); +  if (TYPEOF(Pike_sp[-1]) != T_PROGRAM && TYPEOF(Pike_sp[-1]) != T_FUNCTION) +  Pike_error ("Failed to resolve Charset.DecodeError " +  "to a program - unable to throw an decode error.\n"); +  move_svalue (&decode_err_prog, --Pike_sp); +  } +  err_prog = &decode_err_prog; +  } +  +  ref_push_string (str); +  push_int (pos); +  ref_push_string (charset); +  if (reason) { +  struct string_builder s; +  init_string_builder (&s, 0); +  string_builder_vsprintf (&s, reason, args); +  push_string (finish_string_builder (&s)); +  } +  else +  push_int (0); +  f_backtrace (0); +  apply_svalue (err_prog, 5); +  f_throw (1); + } +  + void DECLSPEC(noreturn) transcode_error ( +  struct pike_string *str, ptrdiff_t pos, struct pike_string *charset, +  int encode, const char *reason, ...) + { +  va_list args; +  va_start (args, reason); +  transcode_error_va (str, pos, charset, encode, reason, args); +  va_end (args); + } +  + void DECLSPEC(noreturn) transcoder_error ( +  struct pike_string *str, ptrdiff_t pos, int encode, const char *reason, ...) + { +  struct svalue charset_str; +  va_list args; +  va_start (args, reason); +  SET_SVAL_SUBTYPE(charset_str, 0); +  MAKE_CONST_STRING (charset_str.u.string, "charset"); +  SET_SVAL_TYPE(charset_str, T_STRING); +  object_index_no_free (Pike_sp, Pike_fp->current_object, 0, &charset_str); +  Pike_sp++; +  if (TYPEOF(Pike_sp[-1]) == T_STRING) { +  transcode_error_va (str, pos, Pike_sp[-1].u.string, encode, reason, args); +  } else { +  transcode_error_va (str, pos, MK_STRING("UNDEFINED"), encode, reason, args); +  } +  va_end (args); + } +  + #define REPLACE_CHAR(ch, func, ctx, str, pos) do { \ +  if(repcb != NULL && call_repcb(repcb, ch)) { \ +  func(ctx, sb, Pike_sp[-1].u.string, rep, NULL); \ +  pop_stack(); \ +  } else if(rep != NULL) \ +  func(ctx, sb, rep, NULL, NULL); \ +  else \ +  transcoder_error (str, pos, 1, "Unsupported character %d.\n",ch); \ +  } while (0) +  + #define MKREPCB(c) (TYPEOF(c) == T_FUNCTION? &(c):NULL) +  + static void f_drain_rfc1345(INT32 args) + { +  struct std_cs_stor *s = (struct std_cs_stor *)Pike_fp->current_storage; +  UNICHAR trailer = 0; +  int double_combiners = 0; +  +  if (s->strbuild.s->size_shift) { +  ptrdiff_t i, len = s->strbuild.s->len; +  /* We need to check for private-space characters. */ +  switch(s->strbuild.s->size_shift) { +  case 1: +  { +  p_wchar1 *s1 = STR1(s->strbuild.s); +  for (i=0; i < len; i++) { +  if ((s1[i] & 0xf000) == 0xe000) { +  if ((s1[i] & 0xff00) == 0xe300) { +  /* Non-spacing character ==> combiner */ +  trailer = s1[i++]; +  if (i < len) { +  s1[i-1] = s1[i]; +  s1[i] = trailer & 0x0fff; +  trailer = 0; +  } else { +  s->strbuild.s->len--; +  break; +  } +  } else if ((s1[i] & 0xff00) == 0xee00) { +  /* Non-spacing character ==> combiner */ +  trailer = s1[i++]; +  if (i < len) { +  s1[i-1] = s1[i]; +  s1[i] = 0xf000 | (trailer & 0x0fff); +  trailer = 0; +  } else { +  s->strbuild.s->len--; +  break; +  } +  } else if ((s1[i] & 0xff00) == 0xe100) { +  /* Non-spacing character ==> double combiner +  * +  * Reorder here, and expand later. +  */ +  trailer = s1[i++]; +  if (i < len) { +  s1[i-1] = s1[i]; +  s1[i] = trailer; +  trailer = 0; +  double_combiners = 1; +  } else { +  s->strbuild.s->len--; +  break; +  } +  } +  } +  } +  } +  break; +  case 2: +  { +  p_wchar2 *s2 = STR2(s->strbuild.s); +  for (i=0; i < len; i++) { +  if ((s2[i] & 0xf000) == 0xe000) { +  if ((s2[i] & 0xff00) == 0xe300) { +  /* Non-spacing character ==> combiner */ +  trailer = s2[i++]; +  if (i < len) { +  s2[i-1] = s2[i]; +  s2[i] = trailer & 0x0fff; +  trailer = 0; +  } else { +  s->strbuild.s->len--; +  break; +  } +  } else if ((s2[i] & 0xff00) == 0xee00) { +  /* Non-spacing character ==> combiner */ +  trailer = s2[i++]; +  if (i < len) { +  s2[i-1] = s2[i]; +  s2[i] = 0xf000 | (trailer & 0x0fff); +  trailer = 0; +  } else { +  s->strbuild.s->len--; +  break; +  } +  } else if ((s2[i] & 0xff00) == 0xe100) { +  /* Non-spacing character ==> double combiner +  * +  * Reorder here, and expand later. +  */ +  trailer = s2[i++]; +  if (i < len) { +  s2[i-1] = s2[i]; +  s2[i] = trailer; +  trailer = 0; +  double_combiners = 1; +  } else { +  s->strbuild.s->len--; +  break; +  } +  } +  } +  } +  } +  break; +  case 0: /* Dummy case to silence clang warning */ +  break; +  } +  } +  +  f_cq__Charset_Std_CS_drain(args); +  +  if (trailer) { +  /* The last character was a non-spacing character. +  * Restore it for the next pass. +  */ +  string_builder_putchar(&s->strbuild, trailer); +  } +  if (double_combiners) { +  /* There were non-spacing double modifiers used. */ +  ref_push_array(double_custom_chars); +  ref_push_array(double_combiner_chars); +  f_replace(3); +  } + } +  + static void f_std_feed(INT32 args, ptrdiff_t (*func)(struct pike_string *, +  struct std_cs_stor *)) + { +  struct std_cs_stor *s = (struct std_cs_stor *)Pike_fp->current_storage; +  struct pike_string *str; +  ptrdiff_t l; +  +  get_all_args(NULL, args, "%W", &str); +  +  if(str->size_shift>0) +  Pike_error("Can't feed on wide strings!\n"); +  +  if(s->retain != NULL) { +  str = add_shared_strings(s->retain, str); +  push_string (str); +  args++; +  } +  +  l = func(str, s); +  +  if (s->retain) { +  free_string(s->retain); +  s->retain = NULL; +  } +  if(l>0) +  s->retain = make_shared_binary_string((char *)STR0(str)+str->len-l, l); +  +  pop_n_elems(args); +  push_object(this_object()); + } +  +  + static ptrdiff_t feed_utf8(struct pike_string *str, struct std_cs_stor *s) + { +  static const int utf8cont[] = { 0, 0, 0, 0, 0, 0, 0, 0, +  0, 0, 0, 0, 0, 0, 0, 0, +  0, 0, 0, 0, 0, 0, 0, 0, +  0, 0, 0, 0, 0, 0, 0, 0, +  1, 1, 1, 1, 1, 1, 1, 1, +  1, 1, 1, 1, 1, 1, 1, 1, +  2, 2, 2, 2, 2, 2, 2, 2, +  3, 3, 3, 3, 0, 0, 0, 0 }; +  static const unsigned int first_char_mask[] = {0x1f, 0x0f, 0x07, 0x03, 0x01}; +  +  const p_wchar0 *p = STR0(str); +  ptrdiff_t l = str->len; +  for (; l > 0; l--) { +  unsigned int ch = *p++; +  +  if (ch & 0x80) { +  int cl = utf8cont[(ch>>1) - 64], i; +  if (!cl) +  transcoder_error (str, p - STR0(str) - 1, 0, "Invalid byte.\n"); +  +  ch &= first_char_mask[cl - 1]; +  +  for (i = cl >= l ? l - 1 : cl; i--;) { +  unsigned int c = *p++; +  if ((c & 0xc0) != 0x80) +  /* Report the start of the invalid sequence to make things +  * easier for code that tries to recover from invalid UTF-8. */ +  transcoder_error (str, p - STR0(str) - +  ((cl >= l ? l - 1 : cl) - i) - 1, +  0, "Truncated UTF-8 sequence.\n"); +  ch = (ch << 6) | (c & 0x3f); +  } +  +  if(cl >= l) +  return l; +  l -= cl; +  +  switch (cl) { +  case 1: if (ch >= (1 << 7)) break; /* FALLTHRU */ +  case 2: if (ch >= (1 << 11)) break; /* FALLTHRU */ +  case 3: if (ch >= (1 << 16)) break; +  transcoder_error (str, p - STR0(str) - cl - 1, 0, +  "Non-shortest form of character U+%04X.\n", ch); +  } +  +  if ((ch >= 0xd800 && ch <= 0xdfff) || ch > 0x10ffff) +  transcoder_error (str, p - STR0(str) - cl - 1, 0, +  "Character U+%04X is outside the valid range.\n", ch); +  } +  +  string_builder_putchar(&s->strbuild, ch); +  } +  +  return l; + } +  + static void f_feed_utf8(INT32 args) + { +  f_std_feed(args, feed_utf8); + } +  + /* From http://www.unicode.org/reports/tr16/ +  * Table 3: Byte map from UTF-EBCDIC byte-sequence to I8-sequence. +  */ + static const unsigned char utf_ebcdic_to_i8_conv[] = { +  0x00, 0x01, 0x02, 0x03, 0x9c, 0x09, 0x86, 0x7f, +  0x97, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, +  0x10, 0x11, 0x12, 0x13, 0x9d, 0x0a, 0x08, 0x87, +  0x18, 0x19, 0x92, 0x8f, 0x1c, 0x1d, 0x1e, 0x1f, +  0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x17, 0x1b, +  0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07, +  0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, +  0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a, +  0x20, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, +  0xa7, 0xa8, 0xa9, 0x2e, 0x3c, 0x28, 0x2b, 0x7c, +  0x26, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, +  0xb1, 0xb2, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x5e, +  0x2d, 0x2f, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, +  0xb9, 0xba, 0xbb, 0x2c, 0x25, 0x5f, 0x3e, 0x3f, +  0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, +  0xc4, 0x60, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22, +  0xc5, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, +  0x68, 0x69, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, +  0xcc, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, +  0x71, 0x72, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, +  0xd3, 0x7e, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, +  0x79, 0x7a, 0xd4, 0xd5, 0xd6, 0x5b, 0xd7, 0xd8, +  0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, +  0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0x5d, 0xe6, 0xe7, +  0x7b, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, +  0x48, 0x49, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, +  0x7d, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, +  0x51, 0x52, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, +  0x5c, 0xf4, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, +  0x59, 0x5a, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, +  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, +  0x38, 0x39, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0x9f, + }; +  + static ptrdiff_t feed_utf_ebcdic(struct pike_string *str, +  struct std_cs_stor *s) + { +  static const int cont[] = { 0, 0, 0, 0, 0, 0, 0, 0, +  0, 0, 0, 0, 0, 0, 0, 0, +  1, 1, 1, 1, 1, 1, 1, 1, +  1, 1, 1, 1, 1, 1, 1, 1, +  2, 2, 2, 2, 2, 2, 2, 2, +  3, 3, 3, 3, 4, 4, 0, 0, }; +  static const unsigned int first_char_mask[] = {0x1f, 0x0f, 0x07, 0x03, 0x01}; +  +  const p_wchar0 *p = STR0(str); +  ptrdiff_t l = str->len; +  for (; l > 0; l--) { +  unsigned int ch = utf_ebcdic_to_i8_conv[*p++]; +  +  if ((ch & 0x80) && (ch & 0x60)) { +  int cl = cont[(ch>>1) - 80]; +  int i; +  if (!cl) +  transcoder_error (str, p - STR0(str) - 1, 0, "Invalid byte.\n"); +  +  ch &= first_char_mask[cl - 1]; +  +  for (i = cl >= l ? l - 1 : cl; i--;) { +  unsigned int c = utf_ebcdic_to_i8_conv[*p++]; +  if ((c & 0xe0) != 0xa0) +  /* Report the start of the invalid sequence to make things +  * easier for code that tries to recover from invalid UTF-EBCDIC. */ +  transcoder_error (str, p - STR0(str) - +  ((cl >= l ? l - 1 : cl) - i) - 1, +  0, "Truncated UTF-EBCDIC I8-sequence.\n"); +  ch = (ch << 5) | (c & 0x1f); +  } +  +  if(cl >= l) +  return l; +  +  l -= cl; +  + #if 0 +  /* FIXME: Detect non-shortest sequence. */ +  switch (cl) { +  case 1: if (ch >= (1 << 7)) break; +  case 2: if (ch >= (1 << 11)) break; +  case 3: if (ch >= (1 << 16)) break; +  transcoder_error (str, p - STR0(str) - cl - 1, 0, +  "Non-shortest form of character U+%04X.\n", ch); +  } +  +  if ((ch >= 0xd800 && ch <= 0xdfff) || ch > 0x10ffff) +  transcoder_error (str, p - STR0(str) - cl - 1, 0, +  "Character U+%04X is outside the valid range.\n", ch); + #endif /* 0 */ +  } +  +  string_builder_putchar(&s->strbuild, ch); +  } +  +  return l; + } +  + static void f_feed_utf_ebcdic(INT32 args) + { +  f_std_feed(args, feed_utf_ebcdic); + } +  + static ptrdiff_t feed_utf7_5(struct pike_string *str, struct std_cs_stor *s) + { +  static int utf7_5len[] = { 0, 0, 0, 0, 0, 0, 0, 0, +  -1,-1, 1, 2,-1,-1,-1,-1, }; +  static const unsigned INT32 utf7_5of[] = { 0ul, 0x28c0ul, 0xb30c0ul }; +  +  const p_wchar0 *p = STR0(str); +  ptrdiff_t l = str->len; +  while(l>0) { +  unsigned INT32 ch = 0; +  int cl = utf7_5len[(*p)>>4]; +  if(cl>--l) +  return l+1; +  switch(cl) { +  case 2: ch += *p++; ch<<=6; /* FALLTHRU */ +  case 1: ch += *p++; ch<<=6; /* FALLTHRU */ +  case 0: ch += *p++; +  break; +  case -1: +  /* FIXME: Encoding error if cl < 0. */ +  cl = 0; +  break; +  } +  l-=cl; +  string_builder_putchar(&s->strbuild, (ch-utf7_5of[cl])&0x7fffffffl); +  } +  return l; + } +  + static void f_feed_utf7_5(INT32 args) + { +  f_std_feed(args, feed_utf7_5); + } +  + static ptrdiff_t feed_utf7(struct pike_string *str, struct std_cs_stor *s) + { +  struct utf7_stor *u7 = (struct utf7_stor *)(((char*)s)+utf7_stor_offs); +  INT32 dat = u7->dat, surro = u7->surro; +  int shift = u7->shift, datbit = u7->datbit; +  +  const p_wchar0 *p = STR0(str); +  ptrdiff_t l = str->len; +  if(l<=0) +  return l; +  +  if(shift==2) { +  if(*p=='-') { +  string_builder_putchar(&s->strbuild, '+'); +  if(--l==0) { +  u7->shift=0; +  return l; +  } +  p++; +  shift=0; +  } else +  shift=1; +  } +  +  for(;;) +  if(shift) { +  int c = 0, z; +  while(l-->0 && (c=(*p++)-'+')>=0 && c<=('z'-'+') && (z=rev64t[c])>=0) { +  dat = (dat<<6)|z; +  if((datbit+=6)>=16) { +  INT32 uc = dat>>(datbit-16); +  if((uc&0xfc00)==0xd800) { +  if(surro) +  string_builder_putchar(&s->strbuild, surro); +  surro = uc; +  } else if(surro) { +  if((uc&0xfc00)==0xdc00) +  string_builder_putchar(&s->strbuild, 0x00010000+ +  ((surro&0x3ff)<<10)+(uc&0x3ff)); +  else { +  string_builder_putchar(&s->strbuild, surro); +  string_builder_putchar(&s->strbuild, uc); +  } +  surro = 0; +  } else +  string_builder_putchar(&s->strbuild, uc); +  datbit -= 16; +  dat &= (1<<datbit)-1; +  } +  } +  if(l<0) { +  l++; +  break; +  } +  if(surro) { +  string_builder_putchar(&s->strbuild, surro); +  surro = 0; +  } +  /* should check that dat is 0 here. */ +  shift=0; +  dat=0; +  datbit=0; +  if(c!=('-'-'+')) { +  l++; +  --p; +  } else +  if(l==0) +  break; +  } else { +  while(l-->0 && *p!='+') +  string_builder_putchar(&s->strbuild, *p++); +  if(l<0) { +  l++; +  break; +  } +  p++; +  if(l==0) { +  shift=2; +  break; +  } +  if(*p=='-') { +  string_builder_putchar(&s->strbuild, '+'); +  if(--l==0) +  break; +  p++; +  } else +  shift = 1; +  } +  +  u7->dat = dat; +  u7->surro = surro; +  u7->shift = shift; +  u7->datbit = datbit; +  return l; + } +  + static void f_clear_utf7(INT32 args) + { +  struct utf7_stor *u7 = +  (struct utf7_stor *)(Pike_fp->current_storage+utf7_stor_offs); +  +  f_cq__Charset_Std_CS_clear(args); +  +  u7->dat = 0; +  u7->surro = 0; +  u7->shift = 0; +  u7->datbit = 0; + } +  + static void utf7_init_stor(struct object *UNUSED(o)) + { +  struct utf7_stor *u7 = +  (struct utf7_stor *)(Pike_fp->current_storage+utf7_stor_offs); +  +  u7->dat = 0; +  u7->surro = 0; +  u7->shift = 0; +  u7->datbit = 0; + } +  + static void f_feed_utf7(INT32 args) + { +  f_std_feed(args, feed_utf7); + } +  + static ptrdiff_t feed_sjis(struct pike_string *str, struct std_cs_stor *s) + { +  const p_wchar0 *p = STR0(str); +  ptrdiff_t l = str->len; +  while(l>0) { +  unsigned INT32 ch = *p++; +  if(ch < 0x80) { +  if(ch == 0x5c) +  ch = 0xa5; +  else if(ch == 0x7e) +  ch = 0x203e; +  string_builder_putchar(&s->strbuild, ch); +  --l; +  } else if(ch < 0xa1 || ch >= 0xe0) { +  if(ch == 0x80 || ch == 0xa0 || ch >= 0xeb) { +  string_builder_putchar(&s->strbuild, 0xfffd); +  --l; +  } else { +  int lo; +  if(l<2) +  return l; +  lo = *p++; +  l -= 2; +  if(ch > 0xa0) +  ch -= 0x40; +  if(lo >= 0x40 && lo <= 0x9e && lo != 0x7f) { +  if(lo > 0x7f) +  --lo; +  ch = map_JIS_C6226_1983[(ch-0x81)*188+(lo-0x40)]; +  } else if(lo >= 0x9f && lo <= 0xfc) +  ch = map_JIS_C6226_1983[(ch-0x81)*188+94+(lo-0x9f)]; +  else +  ch = 0xfffd; +  string_builder_putchar(&s->strbuild, ch); +  } +  } else { +  string_builder_putchar(&s->strbuild, ch+0xfec0); +  --l; +  } +  } +  return l; + } +  + static void f_feed_sjis(INT32 args) + { +  f_std_feed(args, feed_sjis); + } +  + static ptrdiff_t feed_euc(struct pike_string *str, struct std_cs_stor *s) + { +  struct euc_stor *euc = (struct euc_stor *)(((char*)s)+euc_stor_offs); +  UNICHAR const *map = euc->table; +  UNICHAR const *map2 = euc->table2; +  UNICHAR const *map3 = euc->table3; +  +  const p_wchar0 *p = STR0(str); +  ptrdiff_t l = str->len; +  while(l>0) { +  unsigned INT32 ch = *p++; +  if(ch < 0x80) { +  string_builder_putchar(&s->strbuild, ch); +  --l; +  } else if(ch > 0xa0 && ch < 0xff) { +  int lo; +  if(l<2) +  return l; +  lo = (*p++)|0x80; +  if(lo > 0xa0 && lo < 0xff) +  ch = map[(ch-0xa1)*94+(lo-0xa1)]; +  else +  ch = 0xfffd; +  string_builder_putchar(&s->strbuild, ch); +  l -= 2; +  } else if(ch == 0x8e) { +  if(l<2) +  return l; +  ch = (*p++)|0x80; +  if(map2 && (ch > 0xa0 && ch < 0xff)) +  ch = map2[ch-0xa1]; +  else +  ch = 0xfffd; +  string_builder_putchar(&s->strbuild, ch); +  l -= 2; +  } else if(ch == 0x8f) { +  int lo; +  if(l<3) +  return l; +  ch = (*p++)|0x80; +  lo = (*p++)|0x80; +  if(map3 && (ch > 0xa0 && ch < 0xff && lo > 0xa0 && lo < 0xff)) +  ch = map3[(ch-0xa1)*94+(lo-0xa1)]; +  else +  ch = 0xfffd; +  string_builder_putchar(&s->strbuild, ch); +  l -= 3; +  } else { +  string_builder_putchar(&s->strbuild, 0xfffd); +  --l; +  } +  } +  return l; + } +  + static void f_feed_euc(INT32 args) + { +  f_std_feed(args, feed_euc); + } +  + static void f_create_euc(INT32 args) + { +  struct euc_stor *s = (struct euc_stor *)(Pike_fp->current_storage + euc_stor_offs); +  struct pike_string *str; +  int lo=0, hi=num_charset_def-1; +  +  check_all_args(NULL, args, BIT_STRING, BIT_STRING, 0); +  +  str = Pike_sp[-args].u.string; +  +  if(str->size_shift>0) +  hi = -1; +  +  while(lo<=hi) { +  int c, mid = (lo+hi)>>1; +  if((c = strcmp((char *)STR0(str), charset_map[mid].name))==0) { +  if(charset_map[mid].mode == MODE_9494) +  s->table = charset_map[mid].table; +  break; +  } +  if(c<0) +  hi=mid-1; +  else +  lo=mid+1; +  } +  +  if(s->table == NULL) +  Pike_error("Unknown charset in EUCDec\n"); +  +  if(s->table == iso2022_9494[2]) { /* jis-x0208 */ +  s->table2 = iso2022_94[9]; /* jis-x0201 */ +  s->table3 = iso2022_9494[4]; /* jis-x0212 */ +  } else { +  s->table2 = NULL; +  s->table3 = NULL; +  } +  +  copy_shared_string (s->name, Pike_sp[1-args].u.string); +  pop_n_elems(args); + } +  + static void f_create_multichar(INT32 args) + { +  char *name; +  const struct multichar_def *def = multichar_map; +  struct multichar_stor *s = (struct multichar_stor *)(Pike_fp->current_storage + multichar_stor_offs); +  +  get_all_args(NULL, args, "%s", &name); +  +  while(1) { +  if(def->name == 0) +  Pike_error("Unknown multichar table.\n"); +  if( strcmp(name, def->name)==0 ) +  break; +  def++; +  } +  +  s->table = def->table; +  /* NOTE: gb18030 is the first in the multichar map! */ +  s->is_gb18030 = (def == multichar_map); +  +  copy_shared_string (s->name, Pike_sp[-args].u.string); +  pop_n_elems(args); + } +  + #include "gb18030.h" +  + /* Used for gb18030 to decode code points outside GBK. */ + static ptrdiff_t feed_gb18030(const p_wchar0 *p, ptrdiff_t l, +  struct std_cs_stor *s) + { +  p_wchar2 index = 0; +  if (l < 4) { +  return l; +  } +  +  /* First decode the linear offset. */ +  +  if ((p[0] < 0x81) || (p[0] > 0xfe)) { +  return 0; +  } +  index = p[0] - 0x81; +  +  if ((p[1] < 0x30) || (p[1] > 0x39)) { +  return 0; +  } +  index *= 10; +  index += p[1] - 0x30; +  +  if ((p[2] < 0x81) || (p[2] > 0xfe)) { +  return 0; +  } +  index *= 126; +  index += p[2] - 0x81; +  +  if ((p[3] < 0x30) || (p[3] > 0x39)) { +  return 0; +  } +  index *= 10; +  index += p[3] - 0x30; +  +  /* Convert to Unicode. */ +  string_builder_putchar(&s->strbuild, gb18030_to_unicode(index)); +  +  /* We've used 4 bytes of input. */ +  return -4; + } +  + static ptrdiff_t feed_multichar(struct pike_string *str, +  struct std_cs_stor *s) + { +  struct multichar_stor *m = (struct multichar_stor *)(Pike_fp->current_storage + multichar_stor_offs); +  const struct multichar_table *table = m->table; +  +  const p_wchar0 *p = STR0(str); +  ptrdiff_t l = str->len; +  while(l>0) { +  unsigned INT32 ch = *p++; +  if(ch < 0x81) { +  /* FIXME: Adjust above limit to 0x80? Recent GB18030 encodes +  * U+0080 as 0x81 0x30 0x81 0x30. +  */ +  string_builder_putchar(&s->strbuild, ch); +  --l; +  } +  else { +  const struct multichar_table page = table[ ch-0x81 ]; +  if(l==1) return 1; +  if(ch==0xff) { +  transcoder_error (str, p - STR0(str) - 1, 0, "Illegal character.\n"); +  } +  ch = *p++; +  if( ch<page.lo || ch>page.hi ) { +  if (m->is_gb18030) { +  int delta = feed_gb18030(p-2, l, s); +  if (delta < 0) { +  p -= delta + 2; +  l += delta; +  continue; +  } else if (delta > 0) { +  /* More characters needed. */ +  return delta; +  } +  } +  transcoder_error (str, p - STR0(str) - 2, +  0, "Illegal character pair: 0x%02x 0x%02x " +  "(expected 0x%02x 0x%02x..0x%02x).\n", +  p[-2], ch, p[-2], page.lo, page.hi); +  } +  else +  string_builder_putchar(&s->strbuild, page.table[ch-page.lo]); +  l -= 2; +  } +  } +  return 0; + } +  + static void f_feed_multichar(INT32 args) + { +  f_std_feed(args, feed_multichar); + } +  + static void feed_gb18030e(struct std_cs_stor *cs, struct string_builder *sb, +  struct pike_string *str, struct pike_string *rep, +  struct svalue *repcb) + { +  ptrdiff_t l = str->len; +  const struct gb18030e_info *e_info; +  +  switch(str->size_shift) { +  case 0: +  { +  p_wchar0 c, *p = STR0(str); +  while(l--) +  if((c=*p++)<=0x7f) +  string_builder_putchar(sb, c); +  else if ((e_info = get_gb18030e_info(c))) { +  if (e_info->index < 0) { +  /* Two bytes (ie GBK). */ +  int off = ~e_info->index + (c - e_info->ulow)*2; +  string_builder_putchar(sb, gb18030e_bytes[off]); +  string_builder_putchar(sb, gb18030e_bytes[off+1]); +  } else { +  /* Four bytes */ +  int index = e_info->index + c - e_info->ulow; +  c = index/12600; +  string_builder_putchar(sb, 0x81 + c); +  index -= c*12600; +  c = index/1260; +  string_builder_putchar(sb, 0x30 + c); +  index -= c*1260; +  c = index/10; +  string_builder_putchar(sb, 0x81 + c); +  index -= c*10; +  string_builder_putchar(sb, 0x30 + index); +  } +  } else { +  REPLACE_CHAR(c, feed_gb18030e, cs, str, p - STR0(str) - 1); +  } +  } +  break; +  case 1: +  { +  p_wchar1 c, *p = STR1(str); +  while(l--) +  if((c=*p++)<=0x7f) +  string_builder_putchar(sb, c); +  else if ((e_info = get_gb18030e_info(c))) { +  if (e_info->index < 0) { +  /* Two bytes (ie GBK). */ +  int off = ~e_info->index + (c - e_info->ulow)*2; +  string_builder_putchar(sb, gb18030e_bytes[off]); +  string_builder_putchar(sb, gb18030e_bytes[off+1]); +  } else { +  /* Four bytes */ +  int index = e_info->index + c - e_info->ulow; +  c = index/12600; +  string_builder_putchar(sb, 0x81 + c); +  index -= c*12600; +  c = index/1260; +  string_builder_putchar(sb, 0x30 + c); +  index -= c*1260; +  c = index/10; +  string_builder_putchar(sb, 0x81 + c); +  index -= c*10; +  string_builder_putchar(sb, 0x30 + index); +  } +  } else { +  REPLACE_CHAR(c, feed_gb18030e, cs, str, p - STR1(str) - 1); +  } +  } +  break; +  case 2: +  { +  p_wchar2 c, *p = STR2(str); +  while(l--) { +  if((c=*p++)<=0x7f) { +  string_builder_putchar(sb, c); +  } +  else if ((e_info = get_gb18030e_info(c))) { +  if (e_info->index < 0) { +  /* Two bytes (ie GBK). */ +  int off = ~e_info->index + (c - e_info->ulow)*2; +  string_builder_putchar(sb, gb18030e_bytes[off]); +  string_builder_putchar(sb, gb18030e_bytes[off+1]); +  } else { +  /* Four bytes */ +  int index = e_info->index + c - e_info->ulow; +  c = index/12600; +  string_builder_putchar(sb, 0x81 + c); +  index -= c*12600; +  c = index/1260; +  string_builder_putchar(sb, 0x30 + c); +  index -= c*1260; +  c = index/10; +  string_builder_putchar(sb, 0x81 + c); +  index -= c*10; +  string_builder_putchar(sb, 0x30 + index); +  } +  } else { +  REPLACE_CHAR(c, feed_gb18030e, cs, str, p - STR2(str) - 1); +  } +  } +  } +  break; +  } + } +  + static void f_feed_gb18030e(INT32 args) + { +  struct pike_string *str; +  struct std_cs_stor *cs = (struct std_cs_stor *)Pike_fp->current_storage; +  +  get_all_args(NULL, args, "%W", &str); +  +  feed_gb18030e(cs, &cs->strbuild, str, cs->replace, MKREPCB(cs->_repcb)); +  +  pop_n_elems(args); +  push_object(this_object()); + } +  + static void feed_gbke(struct std_cs_stor *cs, struct string_builder *sb, +  struct pike_string *str, struct pike_string *rep, +  struct svalue *repcb) + { +  ptrdiff_t l = str->len; +  const struct gb18030e_info *e_info; +  +  switch(str->size_shift) { +  case 0: +  { +  p_wchar0 c, *p = STR0(str); +  while(l--) +  if((c=*p++)<=0x7f) +  string_builder_putchar(sb, c); +  else if ((e_info = get_gb18030e_info(c)) && +  (e_info->index < 0)) { +  /* Two bytes (ie GBK). */ +  int off = ~e_info->index + (c - e_info->ulow)*2; +  string_builder_putchar(sb, gb18030e_bytes[off]); +  string_builder_putchar(sb, gb18030e_bytes[off+1]); +  } else { +  REPLACE_CHAR(c, feed_gbke, cs, str, p - STR0(str) - 1); +  } +  } +  break; +  case 1: +  { +  p_wchar1 c, *p = STR1(str); +  while(l--) +  if((c=*p++)<=0x7f) +  string_builder_putchar(sb, c); +  else if ((e_info = get_gb18030e_info(c)) && +  (e_info->index < 0)) { +  /* Two bytes (ie GBK). */ +  int off = ~e_info->index + (c - e_info->ulow)*2; +  string_builder_putchar(sb, gb18030e_bytes[off]); +  string_builder_putchar(sb, gb18030e_bytes[off+1]); +  } else { +  REPLACE_CHAR(c, feed_gbke, cs, str, p - STR1(str) - 1); +  } +  } +  break; +  case 2: +  { +  p_wchar2 c, *p = STR2(str); +  while(l--) { +  if((c=*p++)<=0x7f) { +  string_builder_putchar(sb, c); +  } +  else if ((e_info = get_gb18030e_info(c)) && +  (e_info->index < 0)) { +  /* Two bytes (ie GBK). */ +  int off = ~e_info->index + (c - e_info->ulow)*2; +  string_builder_putchar(sb, gb18030e_bytes[off]); +  string_builder_putchar(sb, gb18030e_bytes[off+1]); +  } else { +  REPLACE_CHAR(c, feed_gbke, cs, str, p - STR2(str) - 1); +  } +  } +  } +  break; +  } + } +  + static void f_feed_gbke(INT32 args) + { +  struct pike_string *str; +  struct std_cs_stor *cs = (struct std_cs_stor *)Pike_fp->current_storage; +  +  get_all_args(NULL, args, "%W", &str); +  +  feed_gbke(cs, &cs->strbuild, str, cs->replace, MKREPCB(cs->_repcb)); +  +  pop_n_elems(args); +  push_object(this_object()); + } +  + static void f_create_sjise(INT32 args) + { +  struct std16e_stor *s = (struct std16e_stor *)(Pike_fp->current_storage + std16e_stor_offs); +  int i, j, z; +  +  s->lowtrans = 0x5c; +  s->lo = 0x5c; +  s->hi = 0xfffd; +  +  s->revtab = xcalloc(s->hi-s->lo, sizeof(p_wchar1)); +  +  for(z=0, i=33; i<=126; i++, z+=94) +  for(j=33; j<=126; j++) { +  UNICHAR c; +  if((c=map_JIS_C6226_1983[z+j-33])!=0xfffd && c>=s->lo) { +  if(i&1) +  s->revtab[c-s->lo]=(((i>>1)+(i<95? 113:177))<<8)|(j+(j<96? 31:32)); +  else +  s->revtab[c-s->lo]=(((i>>1)+(i<95? 112:176))<<8)|(j+126); +  } +  } +  +  for(i=0x5d; i<0x7e; i++) +  s->revtab[i-s->lo] = i; +  +  for(i=1; i<64; i++) +  s->revtab[i+0xff60-s->lo] = 0xa0+i; +  +  s->revtab[0xa5 - s->lo] = 0x5c; +  s->revtab[0x203e - s->lo] = 0x7e; +  +  /* Could use a program constant in this case, but that'd require a +  * quirky inherit structure. /mast */ +  REF_MAKE_CONST_STRING (*(struct pike_string **) (Pike_fp->current_storage + +  rfc_charset_name_offs), +  "shiftjis"); +  f_cq__Charset_Std_CS_create(args); + } +  + static void f_create_euce(INT32 args) + { +  struct std16e_stor *s = (struct std16e_stor *)(Pike_fp->current_storage + std16e_stor_offs); +  struct pike_string *str; +  int i, j, z, lo=0, hi=num_charset_def-1; +  UNICHAR const *table=NULL; +  +  check_all_args(NULL, args, BIT_STRING, BIT_STRING, +  BIT_STRING|BIT_VOID|BIT_INT, +  BIT_FUNCTION|BIT_VOID|BIT_INT, 0); +  +  str = Pike_sp[-args].u.string; +  +  if(str->size_shift>0) +  hi = -1; +  +  while(lo<=hi) { +  int c, mid = (lo+hi)>>1; +  if((c = strcmp((char *)STR0(str), charset_map[mid].name))==0) { +  if(charset_map[mid].mode == MODE_9494) +  table = charset_map[mid].table; +  break; +  } +  if(c<0) +  hi=mid-1; +  else +  lo=mid+1; +  } +  +  if(table == NULL) +  Pike_error("Unknown charset in EUCEnc\n"); +  +  s->lowtrans = 128; +  s->lo = 128; +  s->hi = 128; +  +  s->revtab = xcalloc(65536-s->lo, sizeof(p_wchar1)); +  +  for(z=0, i=33; i<=126; i++, z+=94) +  for(j=33; j<=126; j++) { +  UNICHAR c; +  if((c=table[z+j-33])!=0xfffd && c>=s->lo) { +  s->revtab[c-s->lo]=(i<<8)|j|0x8080; +  if(c>=s->hi) +  s->hi = c+1; +  } +  } +  +  if(table == iso2022_9494[2]) { +  s->sshift = 1; +  table = iso2022_94[9]; +  for(j=33; j<=126; j++) { +  UNICHAR c; +  if((c=table[j-33])!=0xfffd && c>=s->lo && +  !s->revtab[c-s->lo]) { +  s->revtab[c-s->lo]=j; +  if(c>=s->hi) +  s->hi = c+1; +  } +  } +  table = iso2022_9494[4]; +  for(z=0, i=33; i<=126; i++, z+=94) +  for(j=33; j<=126; j++) { +  UNICHAR c; +  if((c=table[z+j-33])!=0xfffd && c>=s->lo && +  !s->revtab[c-s->lo]) { +  s->revtab[c-s->lo]=(i<<8)|j|0x8000; +  if(c>=s->hi) +  s->hi = c+1; +  } +  } +  } +  +  copy_shared_string (*(struct pike_string **) (Pike_fp->current_storage + +  rfc_charset_name_offs), +  Pike_sp[1-args].u.string); +  +  f_cq__Charset_Std_CS_create(args-2); +  pop_n_elems(2); + } +  + static struct std8e_stor *push_std_8bite(int args, int allargs, int lo, int hi) + { +  struct std8e_stor *s8; +  struct object *o = clone_object(std_8bite_program, args); +  allargs -= args; +  copy_shared_string (*(struct pike_string **) (o->storage + +  rfc_charset_name_offs), +  Pike_sp[-allargs].u.string); +  pop_n_elems(allargs); +  push_object(o); +  s8 = (struct std8e_stor *)(Pike_sp[-1].u.object->storage+std8e_stor_offs); +  s8->revtab = xcalloc(hi-lo, sizeof(p_wchar0)); +  s8->lo = lo; +  s8->hi = hi; +  s8->lowtrans = 0; +  return s8; + } +  + static struct std16e_stor *push_std_16bite(int args, int allargs, int lo, int hi) + { +  struct std16e_stor *s16; +  struct object *o = clone_object(std_16bite_program, args); +  allargs -= args; +  copy_shared_string (*(struct pike_string **) (o->storage + +  rfc_charset_name_offs), +  Pike_sp[-allargs].u.string); +  pop_n_elems(allargs); +  push_object(o); +  s16 = (struct std16e_stor *)(Pike_sp[-1].u.object->storage+std16e_stor_offs); +  s16->revtab = xcalloc(hi-lo, sizeof(p_wchar1)); +  s16->lo = lo; +  s16->hi = hi; +  s16->lowtrans = 0; +  return s16; + } +  + /*! @decl object rfc1345(string charset, int(0..1)|void encoder, string|void rep, @ +  *! function(string:string)|void repcb) +  *! +  *! Low-level charset codec factory. +  *! +  *! @param charset +  *! Canonical name of character set to look up. +  *! +  *! @param encoder +  *! Flag indicating that an encoder and not a decoder is wanted. +  *! +  *! @param rep +  *! String to use for characters not representable in the @[charset]. +  *! Only used for encoders. +  *! +  *! @param repcb +  *! Function to call for characters not representable in the @[charset]. +  *! Only used for encoders. +  *! +  *! This is the main entrypoint into the low-level @[_Charset] module. +  *! +  *| @returns +  *! Returns a suitable encoder or decoder on success and @expr{0@} +  *! (zero) on failure. +  *! +  *! @seealso +  *! @[Charset.encoder()], @[Charset.decoder()] +  */ + PIKEFUN object rfc1345(string charset, int|void encoder, string|void rep, +  function(string:string)|void repcb) + { +  struct pike_string *str; +  int lo=0, hi=num_charset_def-1; +  p_wchar1 const *tabl; +  +  if(charset->size_shift) { +  push_int(0); +  return; +  } +  +  while(lo<=hi) { +  int c, mid = (lo+hi)>>1; +  if(!(c = strcmp((char *)STR0(charset), charset_map[mid].name))) { +  struct program *p = NULL; +  +  if(encoder && encoder->u.integer) { +  unsigned lowtrans = 0; +  int i, j, lo2=0, hi2=0, z, c; +  +  switch(charset_map[mid].mode) { +  case MODE_94: lowtrans=lo=33; hi=126; break; +  case MODE_96: lowtrans=128; lo=160; hi=255; break; +  case MODE_9494: lowtrans=lo=lo2=33; hi=hi2=126; break; +  case MODE_9696: lowtrans=32; lo=lo2=160; hi=hi2=255; break; +  case MODE_BIG5: lowtrans=32; lo=0xa1; lo2=0x40; hi=0xf9; hi2=0xfe; break; +  default: +  Pike_fatal("Internal error in rfc1345\n"); +  } +  +  if(hi2) { +  struct std16e_stor *s16; +  s16 = push_std_16bite((args>2? args-2:0), args, lowtrans, 65536); +  +  s16->lowtrans = lowtrans; +  s16->lo = lowtrans; +  s16->hi = lowtrans; +  +  for(z=0, i=lo; i<=hi; i++, z+=(hi2-lo2+1)) +  for(j=lo2; j<=hi2; j++) +  if((c=charset_map[mid].table[z+j-lo2])!=0xfffd && c>=s16->lo) { +  s16->revtab[c-s16->lo]=(i<<8)|j; +  if(c>=s16->hi) +  s16->hi = c+1; +  } +  } else { +  struct std8e_stor *s8; +  s8 = push_std_8bite((args>2? args-2:0), args, lowtrans, 65536); +  +  s8->lowtrans = lowtrans; +  s8->lo = lowtrans; +  s8->hi = lowtrans; +  +  for(i=lo; i<=hi; i++) +  if((c=charset_map[mid].table[i-lo])!=0xfffd && c>=s8->lo) { +  s8->revtab[c-s8->lo]=i; +  if(c>=s8->hi) +  s8->hi = c+1; +  } +  } +  return; +  } +  +  switch(charset_map[mid].mode) { +  case MODE_94: p = std_94_program; break; +  case MODE_96: p = std_96_program; break; +  case MODE_9494: p = std_9494_program; break; +  case MODE_9696: p = std_9696_program; break; +  case MODE_BIG5: p = std_big5_program; break; +  default: +  Pike_fatal("Internal error in rfc1345\n"); +  } +  +  { +  struct object *o = clone_object(p, 0); +  ((struct std_rfc_stor *)(o->storage+std_rfc_stor_offs)) +  ->table = charset_map[mid].table; +  copy_shared_string (*(struct pike_string **) (o->storage + +  rfc_charset_name_offs), +  charset); +  push_object (o); +  } +  return; +  } +  if(c<0) +  hi=mid-1; +  else +  lo=mid+1; +  } +  +  if((tabl = misc_charset_lookup((char *)STR0(charset), &lo, &hi))) { +  +  if(encoder && encoder->u.integer) { +  struct std8e_stor *s8; +  int i, c; +  +  s8 = push_std_8bite((args>2? args-2:0), args, lo, 65536); +  s8->lowtrans = lo; +  s8->lo = lo; +  s8->hi = lo; +  s8->zero_char = 0xfffd; +  for(i=lo; i<=hi; i++) { +  if((c=tabl[i-lo])!=0xfffd && c>=s8->lo) { +  s8->revtab[c-lo]=i; +  if(c>=s8->hi) +  s8->hi = c+1; +  } +  } +  if (!lo && (c=tabl[0])!=0xfffd && c>=s8->lo) { +  /* Character 0x00 is a valid character in the encoding +  * for this character set (eg GSM 03.38). +  * +  * Note: We need to encode this character separately +  * due to 0x00 being used in revtab for the replacement +  * character. +  */ +  s8->zero_char = c; +  } +  return; +  } +  +  { +  struct object *o = clone_object(std_8bit_program, 0); +  ((struct std_rfc_stor *)(o->storage+std_rfc_stor_offs)) +  ->table = (UNICHAR *)tabl; +  ((struct std_misc_stor *)(o->storage+std_misc_stor_offs)) +  ->lo = lo; +  ((struct std_misc_stor *)(o->storage+std_misc_stor_offs)) +  ->hi = hi; +  copy_shared_string (*(struct pike_string **) (o->storage + +  rfc_charset_name_offs), +  charset); +  push_object(o); +  } +  return; +  } +  +  push_int(0); + } +  + static ptrdiff_t feed_94(struct pike_string *str, struct std_cs_stor *s) + { +  UNICHAR const *table = +  ((struct std_rfc_stor *)(((char*)s)+std_rfc_stor_offs))->table; +  const p_wchar0 *p = STR0(str); +  ptrdiff_t l = str->len; +  while(l--) { +  p_wchar0 x = *p++; +  if(x<=0x20 || x>=0x7f) +  string_builder_putchar(&s->strbuild, x); +  else { +  UNICHAR uc = table[x-0x21]; +  if ((uc & 0xf800) == 0xd800) { +  /* We use the surrogate block as an offset after the 94 table +  * to a NUL-terminated string of UNICHARs, for the case where +  * the mapping doesn't fit in a single UNICHAR. */ +  string_builder_utf16_strcat(&s->strbuild, +  table + 94 + (uc & 0x07ff)); +  } else if (uc != 0xe000) +  string_builder_putchar(&s->strbuild, uc); +  } +  } +  return 0; + } +  + static void f_feed_94(INT32 args) + { +  f_std_feed(args, feed_94); + } +  + static ptrdiff_t feed_96(struct pike_string *str, struct std_cs_stor *s) + { +  UNICHAR const *table = +  ((struct std_rfc_stor *)(((char*)s)+std_rfc_stor_offs))->table; +  const p_wchar0 *p = STR0(str); +  ptrdiff_t l = str->len; +  while(l--) { +  p_wchar0 x = *p++; +  if(x<0xa0) +  string_builder_putchar(&s->strbuild, x); +  else { +  UNICHAR uc = table[x-0xa0]; +  if ((uc & 0xf800) == 0xd800) { +  /* We use the surrogate block as an offset after the 96 table +  * to a NUL-terminated string of UNICHARs, for the case where +  * the mapping doesn't fit in a single UNICHAR. */ +  string_builder_utf16_strcat(&s->strbuild, +  table + 96 + (uc & 0x07ff)); +  } else if (uc != 0xe000) +  string_builder_putchar(&s->strbuild, table[x-0xa0]); +  } +  } +  return 0; + } +  + static void f_feed_96(INT32 args) + { +  f_std_feed(args, feed_96); + } +  + static ptrdiff_t feed_9494(struct pike_string *str, struct std_cs_stor *s) + { +  UNICHAR const *table = +  ((struct std_rfc_stor *)(((char*)s)+std_rfc_stor_offs))->table; +  const p_wchar0 *p = STR0(str); +  ptrdiff_t l = str->len; +  while(l--) { +  p_wchar0 y, x = (*p++)&0x7f; +  if(x<=0x20 || x>=0x7f) +  string_builder_putchar(&s->strbuild, x); +  else if(l==0) +  return 1; +  else if((y=(*p)&0x7f)>0x20 && y<0x7f) { +  UNICHAR uc; +  --l; +  p++; +  uc = table[(x-0x21)*94+(y-0x21)]; +  if ((uc & 0xf800) == 0xd800) { +  /* We use the surrogate block as an offset after the 9494 table +  * to a NUL-terminated string of UNICHARs, for the case where +  * the mapping doesn't fit in a single UNICHAR. */ +  string_builder_utf16_strcat(&s->strbuild, +  table + 94*94 + (uc & 0x07ff)); +  } else if (uc != 0xe000) { +  string_builder_putchar(&s->strbuild, uc); +  } +  } else { +  string_builder_putchar(&s->strbuild, x); +  } +  } +  return 0; + } +  + static void f_feed_9494(INT32 args) + { +  f_std_feed(args, feed_9494); + } +  + static ptrdiff_t feed_9696(struct pike_string *str, struct std_cs_stor *s) + { +  UNICHAR const *table = +  ((struct std_rfc_stor *)(((char*)s)+std_rfc_stor_offs))->table; +  const p_wchar0 *p = STR0(str); +  ptrdiff_t l = str->len; +  while(l--) { +  p_wchar0 y, x = (*p++)&0x7f; +  if(x<0x20) +  string_builder_putchar(&s->strbuild, x); +  else if(l==0) +  return 1; +  else if((y=(*p)&0x7f)>=0x20) { +  UNICHAR uc; +  --l; +  p++; +  uc = table[(x-0x20)*96+(y-0x20)]; +  if ((uc & 0xf800) == 0xd800) { +  /* We use the surrogate block as an offset after the 9696 table +  * to a NUL-terminated string of UNICHARs, for the case where +  * the mapping doesn't fit in a single UNICHAR. */ +  string_builder_utf16_strcat(&s->strbuild, +  table + 96*96 + (uc & 0x07ff)); +  } else if (uc != 0xe000) { +  string_builder_putchar(&s->strbuild, table[(x-0x20)*96+(y-0x20)]); +  } +  } else { +  string_builder_putchar(&s->strbuild, x); +  } +  } +  return 0; + } +  + static void f_feed_9696(INT32 args) + { +  f_std_feed(args, feed_9696); + } +  + static ptrdiff_t feed_big5(struct pike_string *str, struct std_cs_stor *s) + { +  UNICHAR const *table = +  ((struct std_rfc_stor *)(((char*)s)+std_rfc_stor_offs))->table; +  const p_wchar0 *p = STR0(str); +  ptrdiff_t l = str->len; +  while(l--) { +  p_wchar0 y, x = (*p++); +  if(x<0xa1 || x>0xf9 ) +  string_builder_putchar(&s->strbuild, x); +  else if(l==0) +  return 1; +  else if((y=(*p))>=0x40 && y<=0xfe ) { +  --l; +  p++; +  string_builder_putchar(&s->strbuild, table[(x-0xa1 )*(0xfe -0x40 +1)+(y-0x40 )]); +  } else { +  string_builder_putchar(&s->strbuild, x); +  } +  } +  return 0; + } +  + static void f_feed_big5(INT32 args) + { +  f_std_feed(args, feed_big5); + } +  + static ptrdiff_t feed_8bit(struct pike_string *str, struct std_cs_stor *s) + { +  UNICHAR const *table = +  ((struct std_rfc_stor *)(((char*)s)+std_rfc_stor_offs))->table; +  struct std_misc_stor *misc = +  ((struct std_misc_stor *)(((char*)s)+std_misc_stor_offs)); +  int lo = misc->lo, hi = misc->hi; +  +  const p_wchar0 *p = STR0(str); +  ptrdiff_t l = str->len; +  while(l--) { +  p_wchar0 x = *p++; +  if(x<lo || (x>0x7f && hi<=0x7f)) +  string_builder_putchar(&s->strbuild, x); +  else if(x>hi) +  string_builder_putchar(&s->strbuild, DEFCHAR); +  else +  string_builder_putchar(&s->strbuild, table[x-lo]); +  } +  return 0; + } +  + static void f_feed_8bit(INT32 args) + { +  f_std_feed(args, feed_8bit); + } +  +  + static void feed_utf8e(struct std_cs_stor *cs, struct string_builder *sb, +  struct pike_string *str, struct pike_string *rep, +  struct svalue *repcb) + { +  ptrdiff_t l = str->len; +  ptrdiff_t new_len = str->len; +  +  if (!new_len) return; +  +  switch(str->size_shift) { +  case 0: +  { +  p_wchar0 c, *p = STR0(str); +  while(l--) +  if((*p++)>0x7f) +  new_len++; +  if (new_len == str->len) { +  string_builder_shared_strcat(sb, str); +  return; +  } +  l = str->len; +  p = STR0(str); +  string_build_mkspace(sb, new_len, 0); +  while(l--) +  if((c=*p++)<=0x7f) +  string_builder_putchar(sb, c); +  else { +  string_builder_putchar(sb, 0xc0|(c>>6)); +  string_builder_putchar(sb, 0x80|(c&0x3f)); +  } +  } +  break; +  case 1: +  { +  p_wchar1 c, *p = STR1(str); +  while(l--) +  if((c=*p++)<=0x7f) +  string_builder_putchar(sb, c); +  else if(c<=0x7ff) { +  string_builder_putchar(sb, 0xc0|(c>>6)); +  string_builder_putchar(sb, 0x80|(c&0x3f)); +  } else if (c <= 0xd7ff || c >= 0xe000) { +  string_builder_putchar(sb, 0xe0|(c>>12)); +  string_builder_putchar(sb, 0x80|((c>>6)&0x3f)); +  string_builder_putchar(sb, 0x80|(c&0x3f)); +  } else +  REPLACE_CHAR(c, feed_utf8e, cs, str, p - STR1(str) - 1); +  } +  break; +  case 2: +  { +  p_wchar2 c, *p = STR2(str); +  while(l--) { +  if((c=*p++)<=0x7f) { +  string_builder_putchar(sb, c); +  continue; +  } +  else if(c<=0x7ff) { +  string_builder_putchar(sb, 0xc0|(c>>6)); +  string_builder_putchar(sb, 0x80|(c&0x3f)); +  continue; +  } else if(c<=0xffff) { +  if (c <= 0xd7ff || c >= 0xe000) { +  string_builder_putchar(sb, 0xe0|(c>>12)); +  string_builder_putchar(sb, 0x80|((c>>6)&0x3f)); +  string_builder_putchar(sb, 0x80|(c&0x3f)); +  continue; +  } +  } else if(c<=0x10ffff) { +  string_builder_putchar(sb, 0xf0|(c>>18)); +  string_builder_putchar(sb, 0x80|((c>>12)&0x3f)); +  string_builder_putchar(sb, 0x80|((c>>6)&0x3f)); +  string_builder_putchar(sb, 0x80|(c&0x3f)); +  continue; +  } +  REPLACE_CHAR(c, feed_utf8e, cs, str, p - STR2(str) - 1); +  } +  } +  break; +  } + } +  + static void f_feed_utf8e(INT32 args) + { +  struct pike_string *str; +  struct std_cs_stor *cs = (struct std_cs_stor *)Pike_fp->current_storage; +  +  get_all_args(NULL, args, "%W", &str); +  +  feed_utf8e(cs, &cs->strbuild, str, cs->replace, MKREPCB(cs->_repcb)); +  +  pop_n_elems(args); +  push_object(this_object()); + } +  + /* From http://www.unicode.org/reports/tr16/ +  * Table 2: Byte map from I8-sequence to UTF-EBCDIC byte sequence +  */ + static const unsigned char i8_to_utf_ebcdic_conv[] = { +  0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f, +  0x16, 0x05, 0x15, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, +  0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, +  0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f, +  0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, +  0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61, +  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, +  0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f, +  0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, +  0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, +  0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, +  0xe7, 0xe8, 0xe9, 0xad, 0xe0, 0xbd, 0x5f, 0x6d, +  0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, +  0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, +  0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, +  0xa7, 0xa8, 0xa9, 0xc0, 0x4f, 0xd0, 0xa1, 0x07, +  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x06, 0x17, +  0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x09, 0x0a, 0x1b, +  0x30, 0x31, 0x1a, 0x33, 0x34, 0x35, 0x36, 0x08, +  0x38, 0x39, 0x3a, 0x3b, 0x04, 0x14, 0x3e, 0xff, +  0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, +  0x49, 0x4a, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, +  0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, +  0x67, 0x68, 0x69, 0x6a, 0x70, 0x71, 0x72, 0x73, +  0x74, 0x75, 0x76, 0x77, 0x78, 0x80, 0x8a, 0x8b, +  0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x9a, 0x9b, 0x9c, +  0x9d, 0x9e, 0x9f, 0xa0, 0xaa, 0xab, 0xac, 0xae, +  0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, +  0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbe, 0xbf, +  0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xda, 0xdb, +  0xdc, 0xdd, 0xde, 0xdf, 0xe1, 0xea, 0xeb, 0xec, +  0xed, 0xee, 0xef, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, + }; +  + static void feed_utf_ebcdice(struct std_cs_stor *cs, struct string_builder *sb, +  struct pike_string *str, struct pike_string *rep, +  struct svalue *repcb) + { +  ptrdiff_t l = str->len; +  +  switch(str->size_shift) { +  case 0: +  { +  p_wchar0 c, *p = STR0(str); +  while(l--) +  if((c=*p++)<=0x9f) +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[c]); +  else { +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xc0|(c>>5)]); +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|(c&0x1f)]); +  } +  } +  break; +  case 1: +  { +  p_wchar1 c, *p = STR1(str); +  while(l--) +  if((c=*p++)<=0x9f) +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[c]); +  else if(c<=0x3ff) { +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xc0|(c>>5)]); +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|(c&0x1f)]); +  } else if (c <= 0x3fff) { +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xe0|(c>>10)]); +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|((c>>5)&0x1f)]); +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|(c&0x1f)]); +  } else if (c <= 0xd7ff || c >= 0xe000) { +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xf0|(c>>15)]); +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|((c>>10)&0x1f)]); +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|((c>>5)&0x1f)]); +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|(c&0x1f)]); +  } else +  REPLACE_CHAR(c, feed_utf_ebcdice, cs, str, p - STR1(str) - 1); +  } +  break; +  case 2: +  { +  p_wchar2 c, *p = STR2(str); +  while(l--) { +  if((c=*p++)<=0x9f) { +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[c]); +  continue; +  } +  else if(c<=0x3ff) { +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xc0|(c>>5)]); +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|(c&0x1f)]); +  continue; +  } else if(c<=0x3fff) { +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xe0|(c>>10)]); +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|((c>>5)&0x1f)]); +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|(c&0x1f)]); +  continue; +  } else if(c<=0x3ffff) { +  if (c <= 0xd7ff || c >= 0xe000) { +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xe0|(c>>15)]); +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|((c>>10)&0x1f)]); +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|((c>>5)&0x1f)]); +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|(c&0x1f)]); +  continue; +  } +  } else if(c<=0x10ffff) { +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xf0|(c>>20)]); +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|((c>>15)&0x1f)]); +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|((c>>10)&0x1f)]); +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|((c>>5)&0x1f)]); +  string_builder_putchar(sb, i8_to_utf_ebcdic_conv[0xa0|(c&0x1f)]); +  continue; +  } +  REPLACE_CHAR(c, feed_utf_ebcdice, cs, str, p - STR2(str) - 1); +  } +  } +  break; +  } + } +  + static void f_feed_utf_ebcdice(INT32 args) + { +  struct pike_string *str; +  struct std_cs_stor *cs = (struct std_cs_stor *)Pike_fp->current_storage; +  +  get_all_args(NULL, args, "%W", &str); +  +  feed_utf_ebcdice(cs, &cs->strbuild, str, cs->replace, MKREPCB(cs->_repcb)); +  +  pop_n_elems(args); +  push_object(this_object()); + } +  + static void feed_utf7_5e(struct std_cs_stor *cs, struct string_builder *sb, +  struct pike_string *str, struct pike_string *rep, +  struct svalue *repcb) + { +  ptrdiff_t l = str->len; +  +  switch(str->size_shift) { +  case 0: +  { +  p_wchar0 c, *p = STR0(str); +  while(l--) +  if((c=*p++)<=0x7f) +  string_builder_putchar(sb, c); +  else { +  string_builder_putchar(sb, 0xa0|(c>>6)); +  string_builder_putchar(sb, 0xc0|(c&0x3f)); +  } +  } +  break; +  case 1: +  { +  p_wchar1 c, *p = STR1(str); +  while(l--) +  if((c=*p++)<=0x7f) +  string_builder_putchar(sb, c); +  else if(c<=0x3ff) { +  string_builder_putchar(sb, 0xa0|(c>>6)); +  string_builder_putchar(sb, 0xc0|(c&0x3f)); +  } else { +  string_builder_putchar(sb, 0xb0|(c>>12)); +  string_builder_putchar(sb, 0xc0|((c>>6)&0x3f)); +  string_builder_putchar(sb, 0xc0|(c&0x3f)); +  } +  } +  break; +  case 2: +  { +  p_wchar2 c, *p = STR2(str); +  while(l--) +  if((c=*p++)<=0x7f) +  string_builder_putchar(sb, c); +  else if(c<=0x3ff) { +  string_builder_putchar(sb, 0xa0|(c>>6)); +  string_builder_putchar(sb, 0xc0|(c&0x3f)); +  } else if(c<=0xffff) { +  string_builder_putchar(sb, 0xb0|(c>>12)); +  string_builder_putchar(sb, 0xc0|((c>>6)&0x3f)); +  string_builder_putchar(sb, 0xc0|(c&0x3f)); +  } else +  REPLACE_CHAR(c, feed_utf7_5e, cs, str, p - STR2(str) - 1); +  /* FIXME: Encode using surrogates? */ +  } +  break; +  } + } +  + static void f_feed_utf7_5e(INT32 args) + { +  struct pike_string *str; +  struct std_cs_stor *cs = (struct std_cs_stor *)Pike_fp->current_storage; +  +  get_all_args(NULL, args, "%W", &str); +  +  feed_utf7_5e(cs, &cs->strbuild, str, cs->replace, MKREPCB(cs->_repcb)); +  +  pop_n_elems(args); +  push_object(this_object()); + } +  + static void feed_utf7e(struct utf7_stor *u7, struct string_builder *sb, +  struct pike_string *str, struct pike_string *rep, +  struct svalue *repcb) + { +  ptrdiff_t l = str->len; +  INT32 dat = u7->dat; +  int shift = u7->shift, datbit = u7->datbit; +  +  switch(str->size_shift) { +  case 0: +  { +  p_wchar0 c, *p = STR0(str); +  while(l--) +  if(((c=*p++)>=32 && c<=125 && c!=43 && c!=92) +  || c==9 || c==10 || c==13) { +  if(shift) { +  if(datbit) { +  string_builder_putchar(sb, fwd64t[dat<<(6-datbit)]); +  dat=0; +  datbit=0; +  } +  if(c>='+' && c<='z' && rev64t[c-'+']>=0) +  string_builder_putchar(sb, '-'); +  shift = 0; +  } +  string_builder_putchar(sb, c); +  } else if(c==43 && !shift) { +  string_builder_putchar(sb, '+'); +  string_builder_putchar(sb, '-'); +  } else { +  if(!shift) { +  string_builder_putchar(sb, '+'); +  shift = 1; +  } +  dat=(dat<<16)|c; +  string_builder_putchar(sb, fwd64t[dat>>(datbit+10)]); +  string_builder_putchar(sb, fwd64t[(dat>>(datbit+4))&0x3f]); +  if((datbit+=4)>=6) { +  string_builder_putchar(sb, fwd64t[(dat>>(datbit-6))&0x3f]); +  datbit-=6; +  } +  dat&=(1<<datbit)-1; +  } +  } +  break; +  case 1: +  { +  p_wchar1 c, *p = STR1(str); +  while(l--) +  if(((c=*p++)>=32 && c<=125 && c!=43 && c!=92) +  || c==9 || c==10 || c==13) { +  if(shift) { +  if(datbit) { +  string_builder_putchar(sb, fwd64t[dat<<(6-datbit)]); +  dat=0; +  datbit=0; +  } +  if(c>='+' && c<='z' && rev64t[c-'+']>=0) +  string_builder_putchar(sb, '-'); +  shift = 0; +  } +  string_builder_putchar(sb, c); +  } else if(c==43 && !shift) { +  string_builder_putchar(sb, '+'); +  string_builder_putchar(sb, '-'); +  } else { +  if(!shift) { +  string_builder_putchar(sb, '+'); +  shift = 1; +  } +  dat=(dat<<16)|c; +  string_builder_putchar(sb, fwd64t[dat>>(datbit+10)]); +  string_builder_putchar(sb, fwd64t[(dat>>(datbit+4))&0x3f]); +  if((datbit+=4)>=6) { +  string_builder_putchar(sb, fwd64t[(dat>>(datbit-6))&0x3f]); +  datbit-=6; +  } +  dat&=(1<<datbit)-1; +  } +  } +  break; +  case 2: +  { +  p_wchar2 c, *p = STR2(str); +  while(l--) +  if(((c=*p++)>=32 && c<=125 && c!=43 && c!=92) +  || c==9 || c==10 || c==13) { +  if(shift) { +  if(datbit) { +  string_builder_putchar(sb, fwd64t[dat<<(6-datbit)]); +  dat=0; +  datbit=0; +  } +  if(c>='+' && c<='z' && rev64t[c-'+']>=0) +  string_builder_putchar(sb, '-'); +  shift = 0; +  } +  string_builder_putchar(sb, c); +  } else if(c==43 && !shift) { +  string_builder_putchar(sb, '+'); +  string_builder_putchar(sb, '-'); +  } else if(c>0x10ffff) { +  u7->dat = dat; +  u7->shift = shift; +  u7->datbit = datbit; +  REPLACE_CHAR(c, feed_utf7e, u7, str, p - STR2(str) - 1); +  dat = u7->dat; +  shift = u7->shift; +  datbit = u7->datbit; +  } else { +  if(!shift) { +  string_builder_putchar(sb, '+'); +  shift = 1; +  } +  if(c>0xffff) { +  dat=(dat<<16)|(0xd800+(c>>10)-64); +  string_builder_putchar(sb, fwd64t[dat>>(datbit+10)]); +  string_builder_putchar(sb, fwd64t[(dat>>(datbit+4))&0x3f]); +  if((datbit+=4)>=6) { +  string_builder_putchar(sb, fwd64t[(dat>>(datbit-6))&0x3f]); +  datbit-=6; +  } +  dat&=(1<<datbit)-1; +  c=0xdc00+(c&1023); +  } +  dat=(dat<<16)|c; +  string_builder_putchar(sb, fwd64t[dat>>(datbit+10)]); +  string_builder_putchar(sb, fwd64t[(dat>>(datbit+4))&0x3f]); +  if((datbit+=4)>=6) { +  string_builder_putchar(sb, fwd64t[(dat>>(datbit-6))&0x3f]); +  datbit-=6; +  } +  dat&=(1<<datbit)-1; +  } +  } +  break; +  } +  +  u7->dat = dat; +  u7->shift = shift; +  u7->datbit = datbit; + } +  + static void f_feed_utf7e(INT32 args) + { +  struct pike_string *str; +  struct std_cs_stor *cs = (struct std_cs_stor *)Pike_fp->current_storage; +  +  get_all_args(NULL, args, "%W", &str); +  +  feed_utf7e((struct utf7_stor *)(((char*)Pike_fp->current_storage)+utf7_stor_offs), +  &cs->strbuild, str, cs->replace, MKREPCB(cs->_repcb)); +  +  pop_n_elems(args); +  push_object(this_object()); + } +  + static void f_drain_utf7e(INT32 args) + { +  struct std_cs_stor *cs = (struct std_cs_stor *)Pike_fp->current_storage; +  struct utf7_stor *u7 = +  (struct utf7_stor *)(Pike_fp->current_storage+utf7_stor_offs); +  +  if(u7->shift) { +  if(u7->datbit) { +  string_builder_putchar(&cs->strbuild, fwd64t[u7->dat<<(6-u7->datbit)]); +  u7->dat=0; +  u7->datbit=0; +  } +  string_builder_putchar(&cs->strbuild, '-'); +  u7->shift = 0; +  } +  f_cq__Charset_Std_CS_drain(args); + } +  + static void std_8bite_init_stor(struct object *UNUSED(o)) + { +  struct std8e_stor *s8 = +  (struct std8e_stor *)(Pike_fp->current_storage+std8e_stor_offs); +  +  s8->revtab = NULL; +  s8->lowtrans = 32; +  s8->lo = 0; +  s8->hi = 0; +  s8->zero_char = 0xfffd; + } +  + static void std_8bite_exit_stor(struct object *UNUSED(o)) + { +  struct std8e_stor *s8 = +  (struct std8e_stor *)(Pike_fp->current_storage+std8e_stor_offs); +  +  if(s8->revtab) +  free(s8->revtab); + } +  + static void feed_std8e(struct std8e_stor *s8, struct string_builder *sb, +  struct pike_string *str, struct pike_string *rep, +  struct svalue *repcb) + { +  ptrdiff_t l = str->len; +  p_wchar0 *tab = s8->revtab; +  unsigned lowtrans = s8->lowtrans; +  int lo = s8->lo, hi = s8->hi; +  p_wchar0 ch; +  +  switch(str->size_shift) { +  case 0: +  { +  p_wchar0 c, *p = STR0(str); +  while(l--) +  if((c=*p++)<lowtrans) +  string_builder_putchar(sb, c); +  else if(c>=lo && c<hi && (ch=tab[c-lo])!=0) +  string_builder_putchar(sb, ch); +  else if (!lo && (c == s8->zero_char)) +  string_builder_putchar(sb, 0); +  else +  REPLACE_CHAR(c, feed_std8e, s8, str, p - STR0(str) - 1); +  } +  break; +  case 1: +  { +  p_wchar1 c, *p = STR1(str); +  while(l--) +  if((c=*p++)<lowtrans) +  string_builder_putchar(sb, c); +  else if(c>=lo && c<hi && (ch=tab[c-lo])!=0) +  string_builder_putchar(sb, ch); +  else if (!lo && (c == s8->zero_char) && (c != 0xfffd)) +  string_builder_putchar(sb, 0); +  else +  REPLACE_CHAR(c, feed_std8e, s8, str, p - STR1(str) - 1); +  } +  break; +  case 2: +  { +  p_wchar2 c, *p = STR2(str); +  while(l--) +  if((unsigned INT32) (c=*p++)<lowtrans) +  string_builder_putchar(sb, c); +  else if(c>=lo && c<hi && (ch=tab[c-lo])!=0) +  string_builder_putchar(sb, ch); +  else if (!lo && (c == s8->zero_char) && (c != 0xfffd)) +  string_builder_putchar(sb, 0); +  else +  REPLACE_CHAR(c, feed_std8e, s8, str, p - STR2(str) - 1); +  } +  break; +  } + } +  + static void f_feed_std8e(INT32 args) + { +  struct pike_string *str; +  struct std_cs_stor *cs = (struct std_cs_stor *)Pike_fp->current_storage; +  +  get_all_args(NULL, args, "%W", &str); +  +  feed_std8e((struct std8e_stor *)(((char*)Pike_fp->current_storage)+ +  std8e_stor_offs), +  &cs->strbuild, str, cs->replace, MKREPCB(cs->_repcb)); +  +  pop_n_elems(args); +  push_object(this_object()); + } +  + static void std_16bite_init_stor(struct object *UNUSED(o)) + { +  struct std16e_stor *s16 = +  (struct std16e_stor *)(Pike_fp->current_storage+std16e_stor_offs); +  +  s16->revtab = NULL; +  s16->lowtrans = 32; +  s16->lo = 0; +  s16->hi = 0; +  s16->sshift = 0; + } +  + static void std_16bite_exit_stor(struct object *UNUSED(o)) + { +  struct std16e_stor *s16 = +  (struct std16e_stor *)(Pike_fp->current_storage+std16e_stor_offs); +  +  if(s16->revtab) +  free(s16->revtab); + } +  + static void feed_std16e(struct std16e_stor *s16, struct string_builder *sb, +  struct pike_string *str, struct pike_string *rep, +  struct svalue *repcb) + { +  ptrdiff_t l = str->len; +  p_wchar1 *tab = s16->revtab; +  unsigned lowtrans = s16->lowtrans; +  int lo = s16->lo, hi = s16->hi; +  int sshift = s16->sshift; +  p_wchar1 ch; +  +  switch(str->size_shift) { +  case 0: +  { +  p_wchar0 c, *p = STR0(str); +  while(l--) +  if((c=*p++)<lowtrans) +  string_builder_putchar(sb, c); +  else if(c>=lo && c<hi && (ch=tab[c-lo])!=0) { +  if(sshift && !(ch & 0x80)) { +  ch |= 0x80; +  string_builder_putchar(sb, (ch > 0xff? 0x8f : 0x8e)); +  } +  if(ch > 0xff) +  string_builder_putchar(sb, (ch>>8)&0xff); +  string_builder_putchar(sb, ch&0xff); +  } else +  REPLACE_CHAR(c, feed_std16e, s16, str, p - STR0(str) - 1); +  } +  break; +  case 1: +  { +  p_wchar1 c, *p = STR1(str); +  while(l--) +  if((c=*p++)<lowtrans) +  string_builder_putchar(sb, c); +  else if(c>=lo && c<hi && (ch=tab[c-lo])!=0) { +  if(sshift && !(ch & 0x80)) { +  ch |= 0x80; +  string_builder_putchar(sb, (ch > 0xff? 0x8f : 0x8e)); +  } +  if(ch > 0xff) +  string_builder_putchar(sb, (ch>>8)&0xff); +  string_builder_putchar(sb, ch&0xff); +  } else +  REPLACE_CHAR(c, feed_std16e, s16, str, p - STR1(str) - 1); +  } +  break; +  case 2: +  { +  p_wchar2 c, *p = STR2(str); +  while(l--) +  if((unsigned INT32) (c=*p++)<lowtrans) +  string_builder_putchar(sb, c); +  else if(c>=lo && c<hi && (ch=tab[c-lo])!=0) { +  if(sshift && !(ch & 0x80)) { +  ch |= 0x80; +  string_builder_putchar(sb, (ch > 0xff? 0x8f : 0x8e)); +  } +  if(ch > 0xff) +  string_builder_putchar(sb, (ch>>8)&0xff); +  string_builder_putchar(sb, ch&0xff); +  } else +  REPLACE_CHAR(c, feed_std16e, s16, str, p - STR2(str) - 1); +  } +  break; +  } + } +  + static void f_feed_std16e(INT32 args) + { +  struct pike_string *str; +  struct std_cs_stor *cs = (struct std_cs_stor *)Pike_fp->current_storage; +  +  get_all_args(NULL, args, "%W", &str); +  +  feed_std16e((struct std16e_stor *)(((char*)Pike_fp->current_storage)+ +  std16e_stor_offs), +  &cs->strbuild, str, cs->replace, MKREPCB(cs->_repcb)); +  +  pop_n_elems(args); +  push_object(this_object()); + } +  +  + PIKE_MODULE_INIT + { +  int i,n; +  struct svalue prog; +  static p_wchar1 doubles_first_char[] = { 0x0308, 0x0313, 0x0314 }; +  static p_wchar1 doubles_second_char[] = { 0x0300, 0x0301, 0x0342 }; +  p_wchar1 double_char[2]; +  +  /* Handling of double non-spacing characters used by eg ISO-IR-31. */ +  n = 0; +  for(i = 0xe100; i < 0xe130; i += 0x0010) { +  int j; +  for(j = 0; j < 3; j++,n++) { +  p_wchar1 c = i+j; +  push_string(make_shared_binary_string1(&c, 1)); +  } +  } +  double_custom_chars = aggregate_array(n); +  n = 0; +  for (i = 0; i < 3; i++) { +  int j; +  double_char[0] = doubles_first_char[i]; +  for (j = 0; j < 3; j++,n++) { +  double_char[1] = doubles_second_char[j]; +  push_string(make_shared_binary_string1(double_char, 2)); +  } +  } +  double_combiner_chars = aggregate_array(n); +  +  iso2022_init(); +  +  INIT; +  +  SET_SVAL(prog, T_PROGRAM, 0, program, std_cs_program); +  +  memset(rev64t, -1, sizeof(rev64t)); +  for(i=0; i<64; i++) +  rev64t[fwd64t[i]-'+']=i; +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  utf7_stor_offs = ADD_STORAGE(struct utf7_stor); +  add_string_constant ("charset", "utf7", 0); +  /* function(string:object) */ +  ADD_FUNCTION("feed", f_feed_utf7,tFunc(tStr,tObj), 0); +  /* function(:object) */ +  ADD_FUNCTION("clear", f_clear_utf7,tFunc(tNone,tObj), 0); +  set_init_callback(utf7_init_stor); +  add_program_constant("UTF7dec", utf7_program = end_program(), ID_PROTECTED|ID_FINAL); +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  add_string_constant ("charset", "utf8", 0); +  /* function(string:object) */ +  ADD_FUNCTION("feed", f_feed_utf8,tFunc(tStr,tObj), 0); +  add_program_constant("UTF8dec", utf8_program = end_program(), ID_PROTECTED|ID_FINAL); +  +  prog.u.program = utf7_program; +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  add_string_constant ("charset", "utf7", 0); +  /* function(string:object) */ +  ADD_FUNCTION("feed", f_feed_utf7e,tFunc(tStr,tObj), 0); +  /* function(:string) */ +  ADD_FUNCTION("drain", f_drain_utf7e,tFunc(tNone,tStr), 0); +  add_program_constant("UTF7enc", utf7e_program = end_program(), ID_PROTECTED|ID_FINAL); +  prog.u.program = std_cs_program; +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  add_string_constant ("charset", "utf8", 0); +  /* function(string:object) */ +  ADD_FUNCTION("feed", f_feed_utf8e,tFunc(tStr,tObj), 0); +  add_program_constant("UTF8enc", utf8e_program = end_program(), ID_PROTECTED|ID_FINAL); +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  add_string_constant ("charset", "utfebcdic", 0); +  /* function(string:object) */ +  ADD_FUNCTION("feed", f_feed_utf_ebcdic,tFunc(tStr,tObj), 0); +  add_program_constant("UTF_EBCDICdec", utf_ebcdic_program = end_program(), ID_PROTECTED|ID_FINAL); +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  add_string_constant ("charset", "utfebcdic", 0); +  /* function(string:object) */ +  ADD_FUNCTION("feed", f_feed_utf_ebcdice,tFunc(tStr,tObj), 0); +  add_program_constant("UTF_EBCDICenc", utf_ebcdice_program = end_program(), ID_PROTECTED|ID_FINAL); +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  /* function(string:object) */ +  add_string_constant ("charset", "utf75", 0); +  ADD_FUNCTION("feed", f_feed_utf7_5,tFunc(tStr,tObj), 0); +  add_program_constant("UTF7_5dec", utf7_5_program = end_program(), ID_PROTECTED|ID_FINAL); +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  add_string_constant ("charset", "utf75", 0); +  /* function(string:object) */ +  ADD_FUNCTION("feed", f_feed_utf7_5e,tFunc(tStr,tObj), 0); +  add_program_constant("UTF7_5enc", utf7_5e_program = end_program(), ID_PROTECTED|ID_FINAL); +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  euc_stor_offs = ADD_STORAGE(struct euc_stor); +  PIKE_MAP_VARIABLE ("charset", euc_stor_offs + OFFSETOF (euc_stor, name), +  tStr, T_STRING, 0); +  /* function(string:object) */ +  ADD_FUNCTION("feed", f_feed_euc,tFunc(tStr,tObj), 0); +  /* function(string,string:) */ +  ADD_FUNCTION("create", f_create_euc,tFunc(tStr tStr,tVoid), ID_PROTECTED); +  add_program_constant("EUCDec", euc_program = end_program(), ID_PROTECTED|ID_FINAL); +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  multichar_stor_offs = ADD_STORAGE(struct multichar_stor); +  PIKE_MAP_VARIABLE ("charset", +  multichar_stor_offs + OFFSETOF (multichar_stor, name), +  tStr, T_STRING, 0); +  ADD_FUNCTION("create", f_create_multichar,tFunc(tStr,tVoid), ID_PROTECTED); +  ADD_FUNCTION("feed", f_feed_multichar,tFunc(tStr,tObj), 0); +  add_program_constant("MulticharDec", multichar_program = end_program(), ID_PROTECTED|ID_FINAL); +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  add_string_constant ("charset", "gb18030", 0); +  /* function(string:object) */ +  ADD_FUNCTION("feed", f_feed_gb18030e,tFunc(tStr,tObj), 0); +  add_program_constant("GB18030Enc", gb18030e_program = end_program(), ID_PROTECTED|ID_FINAL); +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  add_string_constant ("charset", "gbk", 0); +  /* function(string:object) */ +  ADD_FUNCTION("feed", f_feed_gbke,tFunc(tStr,tObj), 0); +  add_program_constant("GBKenc", gbke_program = end_program(), ID_PROTECTED|ID_FINAL); +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  add_string_constant ("charset", "shiftjis", 0); +  /* function(string:object) */ +  ADD_FUNCTION("feed", f_feed_sjis,tFunc(tStr,tObj), 0); +  add_program_constant("ShiftJisDec", sjis_program = end_program(), ID_PROTECTED|ID_FINAL); +  +  start_new_program(); +  do_inherit (&prog, 0, NULL); +  rfc_charset_name_offs = ADD_STORAGE (struct pike_string *); +  PIKE_MAP_VARIABLE ("charset", rfc_charset_name_offs, tStr, T_STRING, 0); +  rfc_base_program = end_program(); +  +  prog.u.program = rfc_base_program; +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  std8e_stor_offs = ADD_STORAGE(struct std8e_stor); +  /* function(string:object) */ +  ADD_FUNCTION("feed", f_feed_std8e,tFunc(tStr,tObj), 0); +  set_init_callback(std_8bite_init_stor); +  set_exit_callback(std_8bite_exit_stor); +  std_8bite_program = end_program(); +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  std16e_stor_offs = ADD_STORAGE(struct std16e_stor); +  /* function(string:object) */ +  ADD_FUNCTION("feed", f_feed_std16e,tFunc(tStr,tObj), 0); +  set_init_callback(std_16bite_init_stor); +  set_exit_callback(std_16bite_exit_stor); +  std_16bite_program = end_program(); +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  std_rfc_stor_offs = ADD_STORAGE(struct std_rfc_stor); +  ADD_FUNCTION("drain", f_drain_rfc1345, tFunc(tNone,tStr), 0); +  std_rfc_program = end_program(); +  +  prog.u.program = std_16bite_program; +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  /* function(string,string,string|void,function(string:string)|void:void) */ +  ADD_FUNCTION("create", f_create_euce,tFunc(tStr tStr tOr(tStr,tVoid) tOr(tFunc(tStr,tStr),tVoid),tVoid), 0); +  add_program_constant("EUCEnc", euce_program = end_program(), ID_PROTECTED|ID_FINAL); +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  /* function(string|void,function(string:string)|void:void) */ +  ADD_FUNCTION("create", f_create_sjise,tFunc(tOr(tStr,tVoid) tOr(tFunc(tStr,tStr),tVoid),tVoid), 0); +  add_program_constant("ShiftJisEnc", sjise_program = end_program(), ID_PROTECTED|ID_FINAL); +  +  prog.u.program = std_rfc_program; +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  /* function(string:object) */ +  ADD_FUNCTION("feed", f_feed_94,tFunc(tStr,tObj), 0); +  std_94_program = end_program(); +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  /* function(string:object) */ +  ADD_FUNCTION("feed", f_feed_96,tFunc(tStr,tObj), 0); +  std_96_program = end_program(); +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  /* function(string:object) */ +  ADD_FUNCTION("feed", f_feed_9494,tFunc(tStr,tObj), 0); +  std_9494_program = end_program(); +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  /* function(string:object) */ +  ADD_FUNCTION("feed", f_feed_9696,tFunc(tStr,tObj), 0); +  std_9696_program = end_program(); +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  /* function(string:object) */ +  ADD_FUNCTION("feed", f_feed_big5,tFunc(tStr,tObj), 0); +  std_big5_program = end_program(); +  +  start_new_program(); +  do_inherit(&prog, 0, NULL); +  std_misc_stor_offs = ADD_STORAGE(struct std_misc_stor); +  /* function(string:object) */ +  ADD_FUNCTION("feed", f_feed_8bit,tFunc(tStr,tObj), 0); +  std_8bit_program = end_program(); +  +  PIKE_MODULE_EXPORT (_Charset, transcode_error_va); + } +  + PIKE_MODULE_EXIT + { +  EXIT; +  +  if(utf7e_program != NULL) +  free_program(utf7e_program); +  +  if(utf8e_program != NULL) +  free_program(utf8e_program); +  +  if(utf7_program != NULL) +  free_program(utf7_program); +  +  if(utf8_program != NULL) +  free_program(utf8_program); +  +  if(utf_ebcdic_program != NULL) +  free_program(utf_ebcdic_program); +  +  if(utf_ebcdice_program != NULL) +  free_program(utf_ebcdice_program); +  +  if(utf7_5_program != NULL) +  free_program(utf7_5_program); +  +  if(utf7_5e_program != NULL) +  free_program(utf7_5e_program); +  +  if(euc_program != NULL) +  free_program(euc_program); +  +  if(sjis_program != NULL) +  free_program(sjis_program); +  +  if(euce_program != NULL) +  free_program(euce_program); +  +  if(sjise_program != NULL) +  free_program(sjise_program); +  +  if(std_94_program != NULL) +  free_program(std_94_program); +  +  if(std_96_program != NULL) +  free_program(std_96_program); +  +  if(std_9494_program != NULL) +  free_program(std_9494_program); +  +  if(std_9696_program != NULL) +  free_program(std_9696_program); +  +  if(std_big5_program != NULL) +  free_program(std_big5_program); +  +  if(std_8bit_program != NULL) +  free_program(std_8bit_program); +  +  if(std_8bite_program != NULL) +  free_program(std_8bite_program); +  +  if(std_16bite_program != NULL) +  free_program(std_16bite_program); +  +  if(rfc_base_program != NULL) +  free_program(rfc_base_program); +  +  if(std_rfc_program != NULL) +  free_program(std_rfc_program); +  +  if(gb18030e_program != NULL) +  free_program(gb18030e_program); +  +  if(gbke_program != NULL) +  free_program(gbke_program); +  +  if(multichar_program != NULL) +  free_program(multichar_program); +  +  iso2022_exit(); +  +  if (TYPEOF(encode_err_prog) != T_INT) free_svalue (&encode_err_prog); +  if (TYPEOF(decode_err_prog) != T_INT) free_svalue (&decode_err_prog); +  +  free_array(double_custom_chars); +  free_array(double_combiner_chars); + } +  + /*! @endmodule +  */   Newline at end of file added.