35# ifndef _RWSTD_NO_ICONV
38# include _RWSTD_CERRNO
68#define MAX_SYM_NAME_LEN 256
76#ifndef _RWSTD_NO_ICONV
79my_iconv_open (
const char *to_codeset,
const char *from_codeset)
81 typedef std::vector<std::string> StrVec;
85 const bool to_utf8 = !std::strcmp (to_codeset,
"UTF-8");
86 const bool from_utf8 = !to_utf8;
94 typedef StrVec::iterator VecIter;
96 std::string tried_names [2];
98 for (VecIter
i = aliases [to_utf8].begin ();
i != aliases [to_utf8].end ();
101 for (VecIter
j = aliases [from_utf8].begin ();
102 j != aliases [from_utf8].end (); ++
j) {
104 const char*
const to_code = (*i).c_str ();
105 const char*
const from_code = (*j).c_str ();
107 const iconv_t ret = iconv_open (to_code, from_code);
109 if (ret != iconv_t (-1))
112 if (
i == aliases [to_utf8].begin ()) {
114 if (tried_names [from_utf8].
size ()) {
115 tried_names [from_utf8] +=
',';
116 tried_names [from_utf8] +=
' ';
119 tried_names [from_utf8] +=
'"';
120 tried_names [from_utf8] += *
j;
121 tried_names [from_utf8] +=
'"';
125 if (tried_names [to_utf8].
size ()) {
126 tried_names [to_utf8] +=
',';
127 tried_names [to_utf8] +=
' ';
130 tried_names [to_utf8] +=
'"';
131 tried_names [to_utf8] += *
i;
132 tried_names [to_utf8] +=
'"';
139 "iconv_open(\"%s\", \"%s\") failed; "
140 "tried { %s } and { %s }\n",
141 aliases [to_utf8][0].c_str (),
142 aliases [from_utf8][0].c_str (),
143 tried_names [to_utf8].c_str (),
144 tried_names [from_utf8].c_str ());
150iconv_t Charmap::open_iconv_to_utf8 ()
const
155 return my_iconv_open (
"UTF-8", code_set_name_.c_str ());
158# ifndef _RWSTD_NO_ISO_10646_WCHAR_T
160iconv_t Charmap::open_iconv_to_ext ()
162 return my_iconv_open (code_set_name_.c_str (),
"UTF-8");
172static wchar_t utf8_decode (
const char* from,
const char* to)
176 const unsigned char*
const ch =
179 const unsigned char*
const ch_end =
182 size_t num_bytes = 0;
193 if (*ch >= 0xc2 && *ch < 0xe0) {
200 else if (*ch >= 0xe0 && *ch < 0xf0) {
204 else if (*ch >= 0xf0 && *ch < 0xf8) {
208 else if (*ch >= 0xf8 && *ch < 0xfc) {
212 else if (*ch >= 0xfc && *ch < 0xfe) {
218 "illegal multibyte prefix '\\x%02x' in character "
222 if (ch_end < ch + num_bytes - 1) {
225 "incomplete multibyte character in character "
226 "map file: expecting %u bytes, found %u\n",
227 num_bytes, ch_end - ch);
232 for (
size_t i = 1;
i < num_bytes; ++
i)
233 ret = (ret << 6) | (ch [
i] & 0x3f);
243 std::size_t
count = 1;
247 for (std::size_t idx = 0; ; ++idx, ++
count) {
248 idx =
str.find (escape, idx);
250 if (std::string::npos == idx)
295 "<exclamation-mark>",
302 "<left-parenthesis>",
303 "<right-parenthesis>",
324 "<greater-than-sign>",
353 "<left-square-bracket>",
355 "<right-square-bracket>",
395 const std::string& ext_enc,
wchar_t& wc)
397#ifndef _RWSTD_NO_ISO_10646_WCHAR_T
405 if (UCS4_internal_ || Clocale_.empty ()) {
415 if (-1 == std::mbtowc (&wc, ext_enc.c_str (), ext_enc.size ())) {
417 const char*
const locname = std::setlocale (
LC_CTYPE, 0);
418 const char*
const errtext = std::strerror (errno);
423 "mbtowc failed to convert character in locale "
424 "\"%s\": %s\n", locname, errtext);
436char* Charmap::convert_to_utf8 (
const char *inbuf,
size_t inbuf_s,
437 char *outbuf,
size_t outbuf_s)
const
439#ifndef _RWSTD_NO_ICONV
441 if (ic_to_utf8_ == iconv_t (-1))
444 char* outbufp = outbuf;
446# ifndef _RWSTD_NO_ICONV_CONST_CHAR
447 const char* inbufp = inbuf;
452 if (std::size_t (-1) ==
453 iconv (ic_to_utf8_, &inbufp, &inbuf_s, &outbufp, &outbuf_s)) {
454 const char*
const errtext = std::strerror (errno);
457 "iconv failed to convert \"%s\" "
458 "to UTF-8: %s\n", inbuf, errtext);
477 const std::string::size_type idx = charmap_name_.rfind (
_RWSTD_PATH_SEP);
479 if (idx != std::string::npos)
480 return charmap_name_.substr (idx + 1);
482 return charmap_name_;
488#ifndef _RWSTD_NO_ISO_10646_WCHAR_T
498 const rmb_cmap_iter it = rmb_cmap_.find (
val);
500 if (it != rmb_cmap_.end ()) {
505 std::string encoding = it->second;
513 int last_elm = int (encoding.size ()) - 1;
515 while (last_elm >= 0) {
517 typedef unsigned char UChar;
519 const unsigned ic =
UChar (encoding [last_elm]) + 1;
525 encoding [last_elm--] =
'\0';
527 encoding [last_elm] = char (ic);
535 }
while ((ret = mb_cmap_.find (encoding)) == mb_cmap_.end ());
548increment_encoding (std::string &encoding)
552 const std::string::size_type
pos =
574 static const char xdigits[] =
"0123456789ABCDEF";
577 char *pdig = byte_str;
579 switch (encoding [
pos + 1]) {
581 const unsigned hundreds = last_byte / 100;
582 const unsigned tens = (last_byte - hundreds) / 10;
583 const unsigned units = last_byte % 10;
597 const unsigned hi = last_byte >> 4;
598 const unsigned lo = last_byte & 0xfU;
607 const unsigned hi = last_byte >> 6;
608 const unsigned mid = (last_byte >> 3) & 07U;
609 const unsigned lo = last_byte & 07
U;
621 encoding.replace (
pos + 1, std::string::npos, byte_str);
628encoding_to_mbchar (
const std::string &encoding)
const
632 for (
const char *pbyte = encoding.c_str (); pbyte && *pbyte; )
643 std::string::const_iterator it (sym.begin ());
645 if ( sym.size () < 4 || *it !=
'<' || *++it !=
'U'
646 || !(std::isxdigit)(*++it)) {
648 "Unable to convert symbolic name %s to UCS.\n",
652 const unsigned long val = std::strtoul (&*it, (
char**)0, 16);
654 if (_RWSTD_WCHAR_MAX <=
val)
656 "UCS value %lu of symbolic character %s out of range.\n",
665 const std::string &encoding,
wchar_t& wc)
670 wc = utf8_decode (encoding.c_str (), &*(encoding.end () - 1));
675 char utf8_enc [8 + 1 ];
677 const char*
const ch_end =
678 convert_to_utf8 (encoding.c_str (), encoding.size (),
679 utf8_enc,
sizeof utf8_enc);
682 wc = utf8_decode (utf8_enc, ch_end);
691 if (0 != codepage_) {
692 wchar_t ret[2] = {0};
693 const int res = MultiByteToWideChar (codepage_, 0,
694 encoding.c_str(), -1,
696 if (!
res && ERROR_INVALID_PARAMETER == GetLastError ()) {
702 if (!
res || ret[1] != 0)
716void Charmap::add_to_cmaps (
const std::string &sym_name,
717 const std::string &encoding,
722 const std::string mbchar =
723 is_mbchar ? encoding : encoding_to_mbchar (encoding);
725 symnames_list_.push_back (sym_name);
727 if (1 == mbchar.size ()) {
730 const unsigned char ch = mbchar [0];
736 n_cmap_.insert (std::make_pair (sym_name, ch));
740 rn_cmap_.insert (std::make_pair (ch, sym_name));
742 if (ch > largest_nchar_)
755 w_cmap_.insert (std::make_pair (sym_name, wch));
759 rw_cmap_.insert (std::make_pair (wch, sym_name));
763 mb_cmap_.insert (std::make_pair (mbchar, wch));
764 rmb_cmap_.insert (std::make_pair (wch, mbchar));
774 ucs4_cmap_.insert (std::make_pair (sym_name, uch));
775 rucs4_cmap_.insert (std::make_pair (uch, sym_name));
793 std::string mbchar = encoding_to_mbchar (encoding);
796 add_to_cmaps (beg_tok.
name, mbchar,
true);
805 const std::size_t beg_len = beg_tok.
name.size ();
809 if (2 == num_ellipsis) {
814 while (idx < beg_len && !(std::isxdigit)(beg_tok.
name [idx]))
822 while (idx < beg_len && !(std::isdigit)(beg_tok.
name [idx]))
827 const std::size_t pfx_len = idx;
832 const unsigned long beg_val =
833 1 + std::strtoul (beg_tok.
name.c_str () + pfx_len, &num_end,
base);
836 const std::size_t num_size =
837 num_end - (beg_tok.
name.c_str () + pfx_len);
842 const std::size_t end_len = end_tok.
name.size ();
844 if (2 == num_ellipsis) {
846 while (idx < end_len && !(std::isxdigit)(end_tok.
name [idx]))
851 while (idx < end_len && !(std::isdigit)(end_tok.
name [idx]))
855 const unsigned long end_val =
856 std::strtoul (end_tok.
name.c_str () + idx, (
char**)0,
base);
860 if (end_val < beg_val)
862 "invalid range found in character map file\n");
868 const char*
const pfx = beg_tok.
name.c_str ();
872 std::sprintf (next_name, fmat, pfx_len, pfx, num_size,
val);
878 const unsigned char last_byte = mbchar [mbchar.size () - 1];
880 mbchar [mbchar.size () - 1] = last_byte + 1;
881 add_to_cmaps (next_name, mbchar,
true);
887 "encoding of an element in range contains NUL\n");
897void Charmap::process_chars()
901 std::size_t ntokens = 0;
902 std::size_t nellips = 0;
911 switch (next.
token) {
926 switch (nextnext.
token) {
930 nchars += process_ellipsis (next, 3);
936 nchars += process_ellipsis (next, 2);
942 add_to_cmaps (next.
name, nextnext.
name);
948 "byte value expected following symbolic "
949 "name in character map file\n");
957 "symbolic name expected in character map file\n");
965 "done processing CHARMAP section (%lu tokens, "
966 "%lu ellipses, %lu characters)\n",
967 ntokens, nellips,
nchars);
972 verify_portable_charset();
976void Charmap::verify_portable_charset ()
const
978 const std::size_t
nchars =
981 for (std::size_t
i = 0;
i <
nchars; ++
i) {
987 "member of portable character set %s not found "
995 bool in_utf8,
bool create_forward_maps,
996 bool create_reverse_maps,
bool use_UCS4)
998 charmap_name_ (fname),
1002 forward_maps (create_forward_maps),
1003 reverse_maps (create_reverse_maps),
1006#ifndef _RWSTD_NO_ICONV
1011 scanner_.
open (fname,
'#',
'\\');
1016 code_set_name_ = slash ? slash + 1 : fname;
1021 switch (next.
token) {
1027 code_set_name_ = next.
name.substr (1, next.
name.size () - 2);
1030 code_set_name_ = next.
name;
1034 "string expected following <code_set_name>\n");
1038#ifndef _RWSTD_NO_ICONV
1040 ic_to_utf8_ = open_iconv_to_utf8 ();
1041# if !defined (_RWSTD_NO_ISO_10646_WCHAR_T)
1042 ic_to_ext_ = open_iconv_to_ext ();
1050 if (codepage_ == 0) {
1052 "iconv_open (%s to UTF-8) failed\n",
1053 code_set_name_.c_str());
1085 "unknown token %s in character map file\n",
1086 next.
name.c_str ());
void count(T, T, const U &,...)
#define _RWSTD_REINTERPRET_CAST(T, x)
#define _RWSTD_CONST_CAST(T, x)
void get_cname_aliases(const std::string &name, StringVector &aliases)
unsigned int get_codepage(const std::string &)
bool convert_to_wc(const std::string &, const std::string &, wchar_t &)
Charmap(const char *, const char *, bool, bool, bool, bool)
static const char *const portable_charset[]
std::string get_charmap_name() const
bool convert_to_ucs(const std::string &, const std::string &, wchar_t &)
wchar_t convert_sym_to_ucs(const std::string &) const
std::size_t mbcharlen(const std::string &) const
wchar_t increment_wchar(wchar_t) const
void open(std::string, char='#', char='\\')
unsigned long convert_escape(const char *, const char **=0, bool=false) const
bool issue_diag(int type, bool, const Scanner::token_t *token, const char *fmt,...)