void Def::write_messages(std::string dir_name) { assert (!dir_name.empty()); if (messages_written_) return; if (!messages_def_found_) { issue_diag (I_SKIP, false, 0, "%s section not found, skipping\n", lc_name); return; } (dir_name += _RWSTD_PATH_SEP) += lc_name; issue_diag (I_OPENWR, false, 0, "writing %s\n", dir_name.c_str ()); std::ofstream out (dir_name.c_str(), std::ios::binary); out.exceptions (std::ios::failbit | std::ios::badbit); // now calculate the offsets for the wide string representations messages_out_.yesexpr_off[1] = 0; messages_out_.noexpr_off[1] = unsigned (messages_out_.yesexpr_off[1] + (messages_st_.wyesexpr.size() + 1) * sizeof (wchar_t)); // now calculate the offsets for the narrow string representations messages_out_.yesexpr_off[0] = unsigned (messages_out_.noexpr_off[1] + (messages_st_.wnoexpr.size() + 1) * sizeof (wchar_t)); messages_out_.noexpr_off[0] = unsigned (messages_out_.yesexpr_off[0] + (messages_st_.yesexpr.size() + 1) * sizeof (char)); messages_out_.codeset_off = unsigned (messages_out_.noexpr_off[0] + (messages_st_.noexpr.size() + 1) * sizeof (char)); messages_out_.charmap_off = unsigned (messages_out_.codeset_off + (charmap_.get_code_set_name().size() + 1) * sizeof (char)); // first write out the messages structure out.write ((char*)&messages_out_, sizeof(messages_out_)); // now write out all the strings out.write ((const char*)messages_st_.wyesexpr.c_str(), (messages_st_.wyesexpr.size() + 1) * sizeof (wchar_t)); out.write ((const char*)messages_st_.wnoexpr.c_str(), (messages_st_.wnoexpr.size() + 1) * sizeof (wchar_t)); out << messages_st_.yesexpr << std::ends; out << messages_st_.noexpr << std::ends; out << charmap_.get_code_set_name() << std::ends; out << charmap_.get_charmap_name() << std::ends; out.close(); }
Scanner::token_t Def:: extract_string_array (std::string *str, std::wstring *wstr, std::size_t nelems) { assert (0 != str); assert (0 != wstr); Scanner::token_t tok; for (std::size_t i = 0; i != nelems; ++i) { tok = scanner_.next_token (); if (tok.token != Scanner::tok_string) { issue_diag (W_MISSING, false, &tok, "expected string"); break; } str [i] = convert_string (tok.name); wstr [i] = convert_wstring (tok); } return tok; }
static void generate_locales (const char* map_name, const char* /*alias_name*/, const char* charmap_dir, const char* src_dir, const char* output_dir, bool use_ucs, bool no_position, bool link_aliases) { std::ifstream f (map_name); if (!f) { issue_diag (E_OPENRD, true, 0, "the generation list '%s' " "could not be opened\n", map_name); return; } while (f) { std::string s1; std::string s2; f >> s1 >> s2; if (f) { std::string lname = s1.substr (0, s1.find('.')); std::string cname = s2.substr (0, s2.find('.')); // our name for a locale database is <locale>.<codeset> std::string std_locale(lname + "." + cname); // create the locale database std::cout << "creating locale " << std_locale << '\n'; try { create_locale ((std::string(src_dir) + s1), (std::string(charmap_dir) + s2), std::string (output_dir), std_locale, true, use_ucs, no_position, link_aliases); } catch (const std::ios::failure& error) { std::cerr << "I/O exception " << error.what() << '\n'; } catch (loc_exception& e) { std::cerr << "Unable to create locale " << std_locale << " : " << e.what () << '\n'; } catch (const std::exception& error) { std::cerr <<"ERROR: " << error.what() << '\n'; } catch (...) { std::cerr << "Unable to create locale " << std_locale << '\n'; } } } }
static wchar_t convert_literal_to_ucs4 (Scanner::token_t& t) { if ( t.name.size() < 4 || t.name [0] != '<' || t.name [1] != 'U') { issue_diag (E_CVT, true, &t, "Symbol could not be converted to UCS-4 value" "(literal form should have been <Uxxxxxxxx>)"); } long w = std::strtol (t.name.substr (2, t.name.size ()).c_str (), 0, 16); if (w > _RWSTD_WCHAR_MAX) { // issue_diag intercepted in process_transliteration_statement // but will render -w switch useless; just throw here throw loc_exception ("symbol could not be converted to UCS-4 " "value (value outside wchar_t range)"); } return wchar_t (w); }
void Def:: process_ctype () { issue_diag (I_STAGE, false, 0, "processing %s section\n", lc_name); ctype_def_found_ = true; // used in processing the copy/include directive int nesting_level = 0; while ((next = scanner_.next_token()).token != Scanner::tok_ctype) { switch(next.token) { case Scanner::tok_copy: { // when we see the copy directive in the ctype definition we // are going to either create the shared database and create a // symbolic link to it, or we are going to create a symbolic link // to the already existing shared ctype database. next = scanner_.next_token(); if (next.token != Scanner::tok_string) issue_diag (E_SYNTAX, true, &next, "expected string following \"copy\" directive\n"); #if !defined (_WIN32) && !defined (__CYGWIN__) ctype_symlink_ = true; // first lets make sure that the ctype database for this // locale hasn't already been generated ctype_filename_ = output_name_; // strip off the last directory ctype_filename_ = ctype_filename_.substr (0, ctype_filename_.rfind (_RWSTD_PATH_SEP, ctype_filename_.length() - 1) + 1); ctype_filename_ += strip_quotes(next.name); ctype_filename_ += ".ctype."; ctype_filename_ += charmap_.get_charmap_name(); std::ifstream f (ctype_filename_.c_str(), std::ios::binary); if (f) { // the database exists so simply create a sym link to it ctype_written_ = true; f.close(); continue; } #endif // !_WIN32 && !__CYGWIN__ // bump up the nesting level nesting_level++; issue_diag (I_STAGE, false, 0, "processing copy directive\n"); // open the file scanner_.open (get_pathname (strip_quotes (next.name), next.file)); // get comment char and escape char; // these informations are stored by the scanner while ((next = scanner_.next_token ()).token != Scanner::tok_ctype ){ // the LC_IDENTIFICATION section may also have a // LC_CTYPE token that will mess up the parsing if (next.token == Scanner::tok_ident) { while ((next = scanner_.next_token()).token != Scanner::tok_end ); next = scanner_.next_token(); } } break; } case Scanner::tok_nl: break; case Scanner::tok_upper: process_mask (std::ctype_base::upper, "upper"); break; case Scanner::tok_lower: process_mask (std::ctype_base::lower, "lower"); break; case Scanner::tok_alpha: process_mask (std::ctype_base::alpha, "alpha"); break; case Scanner::tok_digit: process_mask (std::ctype_base::digit, "digit"); break; case Scanner::tok_space: process_mask (std::ctype_base::space, "space"); break; case Scanner::tok_cntrl: process_mask (std::ctype_base::cntrl, "cntrl"); break; case Scanner::tok_punct: process_mask (std::ctype_base::punct, "punct"); break; case Scanner::tok_graph: process_mask (std::ctype_base::graph, "graph"); break; case Scanner::tok_print: process_mask (std::ctype_base::print, "print"); break; case Scanner::tok_xdigit: process_mask (std::ctype_base::xdigit, "xdigit"); break; case Scanner::tok_toupper: process_upper_lower (Scanner::tok_toupper); break; case Scanner::tok_tolower: process_upper_lower (Scanner::tok_tolower); break; case Scanner::tok_blank: scanner_.ignore_line(); break; case Scanner::tok_xlit_start: process_xlit (); break; case Scanner::tok_end: next = scanner_.next_token(); if (next.token == Scanner::tok_ctype) { // end of ctype block if (nesting_level == 0) return; nesting_level--; scanner_.close (); } else issue_diag (E_SYNTAX, true, &next, "wrong section name in END directive\n"); break; default: // ignore locale specific character classes because the c++ // library does not make use of them scanner_.ignore_line(); break; } } }
void Def:: process_xlit () { issue_diag (I_STAGE, false, 0, "processing transliteration\n"); std::size_t nchars = 0; // used in processing the include directive int nesting_level = 0; std::list<std::string> file_list; while (true) { next = scanner_.next_token (); switch (next.token) { case Scanner::tok_include: { // extract all file names from the list std::list<std::string> tmp_list; while (next.token != Scanner::tok_nl) { next = scanner_.next_token (); if (next.token == Scanner::tok_string && next.name.size () > 2) tmp_list.push_back (next.name); } // insert this list into the main list - at beginning file_list.insert (file_list.begin (), tmp_list.begin (), tmp_list.end ()); // get the top of the list std::string fname (file_list.front ()); file_list.pop_front (); // bump up the nesting level nesting_level++; // get the full path for the included file and open it scanner_.open (get_pathname (strip_quotes (fname), next.file)); // get comment char and escape char; // these informations are stored by the scanner while ((next = scanner_.next_token ()).token != Scanner::tok_xlit_start ); break; } case Scanner::tok_sym_name: { process_xlit_statement (nchars); break; } case Scanner::tok_xlit_end: { if (nesting_level == 0) return; // decrement nesting level, close opened file nesting_level--; scanner_.close (); // check if the list of files is empty or not if (file_list.empty ()) break; // if not take the following file and open it std::string fname (file_list.front ()); file_list.pop_front (); // bump up the nesting level nesting_level++; // get the full path for the included file and open it scanner_.open (get_pathname (strip_quotes (fname), next.file)); // get comment char and escape char; // these informations are stored by the scanner while ((next = scanner_.next_token ()).token != Scanner::tok_xlit_start); } default: break; } } issue_diag (I_STAGE, false, 0, "done processing transliteration " "(%lu tokens, %lu characters)"); }
void Def:: process_xlit_statement (std::size_t &nchars) { // convert the name we have for a symbolic name std::string sym_s (next.name); wchar_t sym_w; try { sym_w = convert_literal_to_ucs4 (next); } catch (loc_exception&) { scanner_.ignore_line (); return; } catch (...) { throw; } // add a new element to the transliteration map std::pair<xlit_map_t::iterator, bool> res = xlit_map_.insert (std::make_pair(sym_w, std::list<std::string>())); if (res.second == false) { scanner_.ignore_line (); return; } xlit_map_t::iterator& it = res.first; next = scanner_.next_token (); while (next.token != Scanner::tok_nl) { switch (next.token) { case Scanner::tok_sym_name: { // convert this symbol to a string with the external encoding w_cmap_iter w_pos = charmap_.get_w_cmap().find (next.name); if (w_pos != charmap_.get_w_cmap().end()) { it->second.push_back(convert_to_ext(w_pos->second)); ++nchars; } break; } case Scanner::tok_string: { // for empty names there is no processing if (next.name.size () <= 2) break; // convert this symbol or string of symbols to a string // with the external encoding std::string enc = convert_string (next.name); if (enc.empty()) break; it->second.push_back (enc); ++nchars; break; } default: issue_diag (W_SYNTAX, false, &next, "ignoring unexpected token in " "transliteration statement\n"); break; } next = scanner_.next_token (); } // if the transliteration statement contained only symbols undefined in // the character map, dump this balast if (it->second.empty ()) xlit_map_.erase (it); }
// process_upper_lower processes the toupper and tolower ctype categories // These categories consist of pairs of characters in the format '(<a>,<b>)' void Def:: process_upper_lower (Scanner::token_id tok) { assert (Scanner::tok_toupper == tok || Scanner::tok_tolower == tok); const char* const name = Scanner::tok_toupper == tok ? "upper" : "lower"; issue_diag (I_STAGE, false, 0, "processing ctype to%s map\n", name); std::size_t nchars = 0; // process the toupper and tolower ctype categories next = scanner_.next_token(); for (; next.token != Scanner::tok_nl; ) { std::string sym, sym2; // seperate the symbolic names in the toupper or tolower pair // and place the result in sym and sym2 strip_pair(next.name, sym, sym2); // first process toupper or tolower for the narrow characters const n_cmap_iter sym1_pos = charmap_.get_n_cmap().find (sym); const n_cmap_iter sym2_pos = charmap_.get_n_cmap().find (sym2); if ( sym1_pos != charmap_.get_n_cmap().end() && sym2_pos != charmap_.get_n_cmap().end()) { if (tok == Scanner::tok_toupper) ctype_out_.toupper_tab [sym1_pos->second] = sym2_pos->second; else ctype_out_.tolower_tab [sym1_pos->second] = sym2_pos->second; ++nchars; } // now process toupper or tolower fot the wide characters const w_cmap_iter wsym1_pos = charmap_.get_w_cmap().find (sym); const w_cmap_iter wsym2_pos = charmap_.get_w_cmap().find (sym2); if (wsym1_pos == charmap_.get_w_cmap().end ()) warnings_occurred_ = issue_diag (W_SYM, false, &next, "unknown symbol name %s found in " "%s definition\n", sym.c_str (), lc_name) || warnings_occurred_; else if (wsym2_pos == charmap_.get_w_cmap().end()) warnings_occurred_ = issue_diag (W_SYM, false, &next, "unknown symbol name %s found in " "%s definition\n", sym2.c_str (), lc_name) || warnings_occurred_; else { if (tok == Scanner::tok_toupper) upper_.insert (std::make_pair (wsym1_pos->second, wsym2_pos->second)); else lower_.insert (std::make_pair (wsym1_pos->second, wsym2_pos->second)); ++nchars; } next = scanner_.next_token(); } issue_diag (I_STAGE, false, 0, "done processing to%s map (%lu characters)\n", name, nchars); }
// process_mask is called from process_ctype when process_ctype reaches // a mask defintion (ie. upper, lower, digit). It processes each token // until a new line is reached (which designates the end of the mask // definition). If the token is a symbolic name then it looks up the name // in the cmap map to find the value of the character, otherwise it uses // the value of the character and adds the character to the mask map (if // the character is not alreay there) with the current mask. void Def:: process_mask (std::ctype_base::mask m, const char *name) { issue_diag (I_STAGE, false, 0, "processing %s class\n", name); next = scanner_.next_token (); Scanner::token_t nextnext = scanner_.next_token (); std::size_t nchars = 0; typedef unsigned char UChar; for ( ; next.token != Scanner::tok_nl; ) { switch (nextnext.token) { case Scanner::tok_abs_ellipsis: { // if there are ellipses then include all characters // in between the values that surround the ellipsis // the next token will be the end of the range nextnext = scanner_.next_token (); nchars += process_abs_ellipsis (nextnext, m); break; } case Scanner::tok_hex_ellipsis: case Scanner::tok_dec_ellipsis: case Scanner::tok_dbl_ellipsis: { const Scanner::token_id id = nextnext.token; // the next token will be the end of the range nextnext = scanner_.next_token (); nchars += process_sym_ellipsis (next.name, nextnext.name, id, m); break; } case Scanner::tok_nl: case Scanner::tok_sym_name: case Scanner::tok_char_value: { UChar n_val; // if the value is <= UCHARMAX then add this mask // to the mask table if (get_n_val (next, n_val)) { ctype_out_.mask_tab [n_val] |= m; ++nchars; } wchar_t w_val; if (get_w_val (next, w_val)) { // add the mask to the mask map const mask_iter mask_pos = mask_.find (w_val); if (mask_pos == mask_.end ()) mask_.insert (std::make_pair (w_val, m)); else { mask_pos->second |= m; } ++nchars; } else { // if the value is not in the charmap // then we cannot continue (???) /* warnings_occurred_ = issue_diag (W_SYM, false, &next, "symbolic name %s " "was not found in the character map; " "ignoring character\n", next.name.c_str()) || warnings_occurred_; */ } next = nextnext; break; } default: { // the ctype category definition contains non-symbolic characters // the actual value of the characters will be used. This is // unportable warnings_occurred_ = issue_diag (W_SYM, false, &next, "non-symbolic character %s found in ctype " "definition.\n", next.name.c_str()) || warnings_occurred_; if (next.name.size () != 1) warnings_occurred_ = issue_diag (W_SYM, false, &next, "non-symbolic character %s in ctype " "definition is longer than one char in " "length. Ignoring character\n", next.name.c_str()) || warnings_occurred_; else { ctype_out_.mask_tab [UChar (next.name [0])] |= m; wchar_t mb_val = wchar_t (UChar (next.name [0])); mask_iter mask_pos = mask_.find (mb_val); if (mask_pos != mask_.end()) mask_pos->second |= m; else mask_.insert (std::make_pair (mb_val, m)); ++nchars; } next = nextnext; } } // if we are not at the newline get the next token if (Scanner::tok_nl != next.token) nextnext = scanner_.next_token (); } issue_diag (I_STAGE, false, 0, "done processing %s class (%lu characters)\n", name, nchars); }
void Def::process_messages() { issue_diag (I_STAGE, false, 0, "processing %s section\n", lc_name); // nesting level int nesting_level = 0; messages_def_found_ = true; std::string name; while ((next = scanner_.next_token()).token != Scanner::tok_messages) { switch(next.token) { case Scanner::tok_end: next = scanner_.next_token(); if (next.token == Scanner::tok_messages) { // end of numeric block if (nesting_level == 0) return; nesting_level--; scanner_.close (); } else issue_diag (E_SYNTAX, true, &next, "wrong section name in END directive\n"); break; case Scanner::tok_copy: { next = scanner_.next_token(); if (next.token != Scanner::tok_string) issue_diag (E_SYNTAX, true, &next, "expected string following \"copy\" directive\n"); // bump up the nesting level nesting_level++; issue_diag (I_STAGE, false, 0, "processing copy directive\n"); // open the file scanner_.open (get_pathname (strip_quotes (next.name), next.file)); // get comment char and escape char; // these informations are stored by the scanner while ((next = scanner_.next_token ()).token != Scanner::tok_messages ){ // the LC_IDENTIFICATION section may also have a // LC_MESSAGES token that will mess up the parsing if (next.token == Scanner::tok_ident) { while ((next = scanner_.next_token()).token != Scanner::tok_end ); next = scanner_.next_token(); } } break; } case Scanner::tok_yesexpr: { next = scanner_.next_token(); messages_st_.yesexpr = convert_string (next.name); messages_st_.wyesexpr = convert_wstring (next); break; } case Scanner::tok_noexpr: { next = scanner_.next_token(); messages_st_.noexpr = convert_string (next.name); messages_st_.wnoexpr = convert_wstring (next); break; } default: break; } } }
void Def:: parse_era (const token_t& tok) { // to make processing the era a little easier, first convert // the era_str with possible symbolic names to a narrow string // without symbolic names std::string era = convert_string (tok.name); if (era.empty ()) return; // we need to also parse the wide version of this string so that we // may get the wide version of the era name and format const std::wstring wera = convert_wstring (tok); char* const erap = _RWSTD_CONST_CAST (char*, era.c_str ()); const wchar_t* const werap = wera.c_str (); // first get the direction char* tokp = std::strtok (erap, ":"); const char direction = tokp ? *tokp : '\0'; era_st tmp_era = era_st (); // now get the offset tokp = std::strtok (0, ":"); if (0 == tokp) issue_diag (E_SYNTAX, true, &tok, "expected ':' in era definition\n"); assert (0 != tokp); std::sscanf (tokp, "%d", &tmp_era.era_out.offset); if (direction == '-') tmp_era.era_out.offset *= -1; // now get the start date tokp = std::strtok (0, ":"); if (0 == tokp) issue_diag (E_SYNTAX, true, &tok, "expected ':' in era definition\n"); assert (0 != tokp); unsigned int tmp_mon, tmp_day; std::sscanf (tokp, "%d/%u/%u", &tmp_era.era_out.year[0], &tmp_mon, &tmp_day); // the month is offset by one ot be in the range [0-11] tmp_era.era_out.month[0] = char(tmp_mon - 1); tmp_era.era_out.day[0] = char(tmp_day); // now get the end date (this may be the beginning or end of time tokp = std::strtok (0, ":"); if (0 == tokp) issue_diag (E_SYNTAX, true, &tok, "expected ':' in era definition\n"); assert (0 != tokp); if (std::strcmp (tokp, "-*") == 0) { tmp_era.era_out.year[1] = _RWSTD_INT_MIN; tmp_era.era_out.month[1] = _RWSTD_CHAR_MIN; tmp_era.era_out.day[1] = _RWSTD_CHAR_MIN; } else if (std::strcmp (tokp, "+*") == 0) { tmp_era.era_out.year[1] = _RWSTD_INT_MAX; tmp_era.era_out.month[1] = _RWSTD_CHAR_MAX; tmp_era.era_out.day[1] = _RWSTD_CHAR_MAX; } else { std::sscanf (tokp, "%d/%u/%u", &tmp_era.era_out.year[1], &tmp_mon, &tmp_day); // the month is offset by one to be in the range [0-11] tmp_era.era_out.month[1] = char(tmp_mon - 1); tmp_era.era_out.day[1] = char(tmp_day); } // now get the name of the era tokp = std::strtok (0, ":"); tmp_era.name = tokp; // finally get the format string if one is available tokp = std::strtok (0, ":"); if (0 != tokp) tmp_era.fmt = tokp; // FIXME: check the values //advance to name of the era inside the wide char string const wchar_t *wtokp = werap; for (int i = 0; i < 4 && *wtokp; i++) while (*wtokp && *(wtokp++) != L':'); if (*wtokp) { while (*wtokp != L':') tmp_era.wname += *wtokp++; // advance past the current ':' wtokp++; } if (*wtokp) tmp_era.wfmt = wtokp; era_list_.push_back (tmp_era); time_out_.num_eras++; }
void Def::write_time(std::string dir_name) { assert (!dir_name.empty()); if (time_written_) return; if (!time_def_found_) { issue_diag (I_SKIP, false, 0, "%s section not found, skipping\n", lc_name); return; } // write out all the information in the LC_TIME category (dir_name += _RWSTD_PATH_SEP) += lc_name; issue_diag (I_OPENWR, false, 0, "writing %s\n", dir_name.c_str ()); std::ofstream out (dir_name.c_str(), std::ios::binary); out.exceptions (std::ios::failbit | std::ios::badbit); int i; time_out_.num_alt_digits = alt_digits_.size(); time_out_.era_off = 0; time_out_.alt_digits_off = time_out_.era_off + sizeof (_RW::__rw_time_t::era_t) * era_list_.size(); // now calculate all the offsets for the wide string representations time_out_.abday_off[1][0] = time_out_.alt_digits_off + 2 * sizeof (unsigned int) * time_out_.num_alt_digits; for (i = 1; i < 7; i++) { time_out_.abday_off[1][i] = time_out_.abday_off[1][i-1] + (time_st_.wabday[i-1].size() * sizeof (wchar_t)) + sizeof(wchar_t); } time_out_.day_off[1][0] = time_out_.abday_off[1][6] + time_st_.wabday[6].size() * sizeof (wchar_t) + sizeof (wchar_t); for (i = 1; i < 7; i++) { time_out_.day_off[1][i] = time_out_.day_off[1][i-1] + time_st_.wday[i-1].size() * sizeof (wchar_t) + sizeof (wchar_t); } time_out_.abmon_off[1][0] = time_out_.day_off[1][6] + time_st_.wday[6].size() * sizeof (wchar_t) + sizeof (wchar_t); for (i = 1; i < 12; i++) { time_out_.abmon_off[1][i] = time_out_.abmon_off[1][i-1] + time_st_.wabmon[i-1].size() * sizeof (wchar_t) + sizeof (wchar_t); } time_out_.mon_off[1][0] = time_out_.abmon_off[1][11] + time_st_.wabmon[11].size() * sizeof (wchar_t) + sizeof (wchar_t); for (i = 1; i < 12; i++) { time_out_.mon_off[1][i] = time_out_.mon_off[1][i-1] + time_st_.wmon[i-1].size() * sizeof (wchar_t) + sizeof (wchar_t); } time_out_.am_pm_off[1][0] = time_out_.mon_off[1][11] + time_st_.wmon[11].size() * sizeof (wchar_t) + sizeof (wchar_t); time_out_.am_pm_off[1][1] = time_out_.am_pm_off[1][0] + time_st_.wam_pm[0].size() * sizeof (wchar_t) + sizeof (wchar_t); time_out_.d_t_fmt_off[1] = time_out_.am_pm_off[1][1] + time_st_.wam_pm[1].size() * sizeof (wchar_t) + sizeof (wchar_t); time_out_.d_fmt_off[1] = time_out_.d_t_fmt_off[1] + time_st_.wd_t_fmt.size() * sizeof (wchar_t) + sizeof (wchar_t); time_out_.t_fmt_off[1] = time_out_.d_fmt_off[1] + time_st_.wd_fmt.size() * sizeof (wchar_t) + sizeof (wchar_t); time_out_.t_fmt_ampm_off[1] = time_out_.t_fmt_off[1] + time_st_.wt_fmt.size() * sizeof (wchar_t) + sizeof (wchar_t); time_out_.era_d_t_fmt_off[1] = time_out_.t_fmt_ampm_off[1] + time_st_.wt_fmt_ampm.size() * sizeof (wchar_t) + sizeof (wchar_t); time_out_.era_d_fmt_off[1] = time_out_.era_d_t_fmt_off[1] + time_st_.wera_d_t_fmt.size() * sizeof (wchar_t) + sizeof (wchar_t); time_out_.era_t_fmt_off[1] = time_out_.era_d_fmt_off[1] + time_st_.wera_d_fmt.size() * sizeof (wchar_t) + sizeof (wchar_t); unsigned int next_off = time_out_.era_t_fmt_off[1] + time_st_.wera_t_fmt.size() * sizeof (wchar_t) + sizeof (wchar_t); era_list_iter era_list_it; for (era_list_it = era_list_.begin(); era_list_it != era_list_.end(); era_list_it ++) { era_list_it->era_out.name_off[1] = next_off; next_off += era_list_it->wname.size() * sizeof (wchar_t) + sizeof (wchar_t); era_list_it->era_out.fmt_off[1] = next_off; next_off += era_list_it->wfmt.size() * sizeof (wchar_t) + sizeof (wchar_t); } alt_digits_iter alt_digits_it; for (alt_digits_it = alt_digits_.begin(); alt_digits_it != alt_digits_.end(); alt_digits_it ++ ){ alt_digits_it->w_offset = next_off; next_off += (alt_digits_it->w_alt_digit.size() + 1) * sizeof(wchar_t); } time_out_.abday_off[0][0] = next_off; for (i = 1; i < 7; i++) { // calculate the offsets for the abreviated days time_out_.abday_off[0][i] = time_out_.abday_off[0][i-1] + time_st_.abday[i - 1].size() + 1; } time_out_.day_off[0][0] = time_out_.abday_off[0][6] + time_st_.abday[6].size() + 1; for (i = 1; i < 7; i++) { // calculate the offsets for the days time_out_.day_off[0][i] = time_out_.day_off[0][i-1] + time_st_.day[i-1].size() + 1; } time_out_.abmon_off[0][0] = time_out_.day_off[0][6] + time_st_.day[6].size() + 1; for (i = 1; i < 12; i++) { // calculate the offsets for the abreviated months time_out_.abmon_off[0][i] = time_out_.abmon_off[0][i-1] + time_st_.abmon[i-1].size() + 1; } time_out_.mon_off[0][0] = time_out_.abmon_off[0][11] + time_st_.abmon[11].size() + 1; for (i = 1; i < 12; i++) { // calculate the offsets for the months time_out_.mon_off[0][i] = time_out_.mon_off[0][i-1] + time_st_.mon[i-1].size() + 1; } // calculate the offsets for am and pm time_out_.am_pm_off[0][0] = time_out_.mon_off[0][11] + time_st_.mon[11].size() + 1; time_out_.am_pm_off[0][1] = time_out_.am_pm_off[0][0] + time_st_.am_pm[0].size() + 1; time_out_.d_t_fmt_off[0] = time_out_.am_pm_off[0][1] + time_st_.am_pm[1].size() + 1; time_out_.d_fmt_off[0] = time_out_.d_t_fmt_off[0] + time_st_.d_t_fmt.size() + 1; time_out_.t_fmt_off[0] = time_out_.d_fmt_off[0] + time_st_.d_fmt.size() + 1; time_out_.t_fmt_ampm_off[0] = time_out_.t_fmt_off[0] + time_st_.t_fmt.size() + 1; time_out_.era_d_t_fmt_off[0] = time_out_.t_fmt_ampm_off[0] + time_st_.t_fmt_ampm.size() + 1; time_out_.era_d_fmt_off[0] = time_out_.era_d_t_fmt_off[0] + time_st_.era_d_t_fmt.size() + 1; time_out_.era_t_fmt_off[0] = time_out_.era_d_fmt_off[0] + time_st_.era_d_fmt.size() + 1; next_off = time_out_.era_t_fmt_off[0] + time_st_.era_t_fmt.size() + 1; for (era_list_it = era_list_.begin(); era_list_it != era_list_.end(); era_list_it ++) { era_list_it->era_out.name_off[0] = next_off; next_off += era_list_it->name.size() + 1; era_list_it->era_out.fmt_off[0] = next_off; next_off += era_list_it->fmt.size() + 1; } for (alt_digits_it = alt_digits_.begin(); alt_digits_it != alt_digits_.end(); alt_digits_it ++ ){ alt_digits_it->n_offset = next_off; next_off += alt_digits_it->n_alt_digit.size() + 1; } time_out_.codeset_off = next_off; time_out_.charmap_off = time_out_.codeset_off + charmap_.get_code_set_name().size() + 1; // write the time struct out.write ((char*)&time_out_, sizeof(time_out_)); // first write out the era structs for (era_list_it = era_list_.begin(); era_list_it != era_list_.end(); era_list_it ++) { out.write ((const char*) &era_list_it->era_out, sizeof (era_list_it->era_out)); } // next write out the offsets to where the alternate digits are stored for (alt_digits_it = alt_digits_.begin(); alt_digits_it != alt_digits_.end(); alt_digits_it ++ ){ out.write ((const char*) &alt_digits_it->n_offset, sizeof (alt_digits_it->n_offset)); out.write ((const char*) &alt_digits_it->w_offset, sizeof (alt_digits_it->w_offset)); } // now write out the wchar_t version of LC_TIME for (i = 0; i < 7; i++){ out.write ((const char*)time_st_.wabday[i].c_str(), (time_st_.wabday[i].size() + 1) * sizeof (wchar_t)); } for (i = 0; i < 7; i++) out.write ((const char*)time_st_.wday[i].c_str(), (time_st_.wday[i].size() + 1) * sizeof (wchar_t)); for (i = 0; i < 12; i++) out.write ((const char*)time_st_.wabmon[i].c_str(), (time_st_.wabmon[i].size() + 1) * sizeof (wchar_t)); for (i = 0; i < 12; i++) out.write ((const char*)time_st_.wmon[i].c_str(), (time_st_.wmon[i].size() + 1) * sizeof (wchar_t)); for (i = 0; i < 2; i++) out.write ((const char*)time_st_.wam_pm[i].c_str(), (time_st_.wam_pm[i].size() + 1) * sizeof (wchar_t)); out.write ((const char*)time_st_.wd_t_fmt.c_str(), (time_st_.wd_t_fmt.size() + 1) * sizeof (wchar_t)); out.write ((const char*)time_st_.wd_fmt.c_str(), (time_st_.wd_fmt.size() + 1) * sizeof (wchar_t)); out.write ((const char*)time_st_.wt_fmt.c_str(), (time_st_.wt_fmt.size() + 1) * sizeof (wchar_t)); out.write ((const char*)time_st_.wt_fmt_ampm.c_str(), (time_st_.wt_fmt_ampm.size() + 1) * sizeof (wchar_t)); out.write ((const char*)time_st_.wera_d_t_fmt.c_str(), (time_st_.wera_d_t_fmt.size() + 1) * sizeof (wchar_t)); out.write ((const char*)time_st_.wera_d_fmt.c_str(), (time_st_.wera_d_fmt.size() + 1) * sizeof (wchar_t)); out.write ((const char*)time_st_.wera_t_fmt.c_str(), (time_st_.wera_t_fmt.size() + 1) * sizeof (wchar_t)); for (era_list_it = era_list_.begin(); era_list_it != era_list_.end(); era_list_it ++) { out.write ((const char*) era_list_it->wname.c_str(), (era_list_it->wname.size() + 1) * sizeof (wchar_t)); out.write ((const char*) era_list_it->wfmt.c_str(), (era_list_it->wfmt.size() + 1) * sizeof (wchar_t)); } for (alt_digits_it = alt_digits_.begin(); alt_digits_it != alt_digits_.end(); alt_digits_it ++ ){ out.write ((const char*) alt_digits_it->w_alt_digit.c_str(), (alt_digits_it->w_alt_digit.size() + 1) * sizeof (wchar_t)); } // write out the char version of LC_TIME for (i = 0; i < 7; i++) out << time_st_.abday[i] << std::ends; for (i = 0; i < 7; i++) out << time_st_.day[i] << std::ends; for (i = 0; i < 12; i++) out << time_st_.abmon[i] << std::ends; for (i = 0; i < 12; i++) out << time_st_.mon[i] << std::ends; for (i = 0; i < 2; i++) out << time_st_.am_pm[i] << std::ends; out << time_st_.d_t_fmt << std::ends; out << time_st_.d_fmt << std::ends; out << time_st_.t_fmt << std::ends; out << time_st_.t_fmt_ampm << std::ends; out << time_st_.era_d_t_fmt << std::ends; out << time_st_.era_d_fmt << std::ends; out << time_st_.era_t_fmt << std::ends; for (era_list_it = era_list_.begin(); era_list_it != era_list_.end(); era_list_it ++) { out << era_list_it->name << std::ends; out << era_list_it->fmt << std::ends; } for (alt_digits_it = alt_digits_.begin(); alt_digits_it != alt_digits_.end(); alt_digits_it ++ ){ out << alt_digits_it->n_alt_digit << std::ends; } out << charmap_.get_code_set_name() << std::ends; out << charmap_.get_charmap_name() << std::ends; }
void Def::process_time () { issue_diag (I_STAGE, false, 0, "processing %s section\n", lc_name); // nesting level int nesting_level = 0; time_def_found_ = true; while ((next = scanner_.next_token ()).token != Scanner::tok_time) { switch (next.token) { case Scanner::tok_end: next = scanner_.next_token (); if (next.token == Scanner::tok_time) { // end of numeric block if (nesting_level == 0) return; --nesting_level; scanner_.close (); } else issue_diag (E_SYNTAX, true, &next, "wrong section name in END directive\n"); break; case Scanner::tok_copy: { next = scanner_.next_token(); if (next.token != Scanner::tok_string) issue_diag (E_SYNTAX, true, &next, "expected string following \"copy\" directive\n"); // bump up the nesting level ++nesting_level; // open the file scanner_.open (get_pathname (strip_quotes (next.name), next.file)); // get comment char and escape char; // these informations are stored by the scanner while ((next = scanner_.next_token ()).token != Scanner::tok_time) { // the LC_IDENTIFICATION section may also have a // LC_TIME token that will mess up the parsing if (next.token == Scanner::tok_ident) { while ((next = scanner_.next_token ()).token != Scanner::tok_end); next = scanner_.next_token (); } } break; } case Scanner::tok_abday: { const std::size_t nelems = sizeof time_st_.abday / sizeof *time_st_.abday; next = extract_string_array (time_st_.abday, time_st_.wabday, nelems); break; } case Scanner::tok_day: { const std::size_t nelems = sizeof time_st_.day / sizeof *time_st_.day; next = extract_string_array (time_st_.day, time_st_.wday, nelems); break; } case Scanner::tok_abmon: { const std::size_t nelems = sizeof time_st_.abmon / sizeof *time_st_.abmon; next = extract_string_array (time_st_.abmon, time_st_.wabmon, nelems); break; } case Scanner::tok_mon: { const std::size_t nelems = sizeof time_st_.mon / sizeof *time_st_.mon; next = extract_string_array (time_st_.mon, time_st_.wmon, nelems); break; } case Scanner::tok_d_t_fmt: next = scanner_.next_token(); time_st_.d_t_fmt = convert_string (next.name); time_st_.wd_t_fmt = convert_wstring (next); break; case Scanner::tok_d_fmt: next = scanner_.next_token(); time_st_.d_fmt = convert_string (next.name); time_st_.wd_fmt = convert_wstring (next); break; case Scanner::tok_t_fmt: next = scanner_.next_token(); time_st_.t_fmt = convert_string (next.name); time_st_.wt_fmt = convert_wstring (next); break; case Scanner::tok_am_pm: { const std::size_t nelems = sizeof time_st_.am_pm / sizeof *time_st_.am_pm; next = extract_string_array (time_st_.am_pm, time_st_.wam_pm, nelems); break; } case Scanner::tok_t_fmt_ampm: next = scanner_.next_token(); time_st_.t_fmt_ampm = convert_string (next.name); time_st_.wt_fmt_ampm = convert_wstring (next); break; // The time_get and time_put facets do not make use of eras or // alternate digits, so we will ignore this part of the locale // definition case Scanner::tok_era: while ((next = scanner_.next_token()).token == Scanner::tok_string) parse_era (next); break; case Scanner::tok_era_d_fmt: next = scanner_.next_token(); time_st_.era_d_fmt = convert_string (next.name); time_st_.wera_d_fmt = convert_wstring (next); break; case Scanner::tok_era_t_fmt: next = scanner_.next_token(); time_st_.era_t_fmt = convert_string (next.name); time_st_.wera_t_fmt = convert_wstring (next); break; case Scanner::tok_era_d_t_fmt: next = scanner_.next_token(); time_st_.era_d_t_fmt = convert_string (next.name); time_st_.wera_d_t_fmt = convert_wstring (next); break; case Scanner::tok_alt_digits: while ((next = scanner_.next_token()).token == Scanner::tok_string) { alt_digit_t digit; digit.n_alt_digit = convert_string (next.name); digit.w_alt_digit = convert_wstring (next); digit.n_offset = 0; digit.w_offset = 0; alt_digits_.push_back (digit); } break; default: break; } } }
static bool process_command_line (ProgramOptions *opts, int argc, char* argv[]) { opts->program_name = argv [0]; opts->charmap_name = ""; opts->source_name = ""; opts->map_file = 0; opts->alias_file = 0; opts->locale_name = 0; opts->gen = false; opts->force_output = false; opts->use_ucs = false; opts->no_position = false; opts->link_aliases = false; int i; // index of command line argument being processed for (i = 1; i < argc && '-' == argv [i][0]; ++i) { switch (argv [i][1]) { case 'f': // set character set description file name if (argv [i + 1]) opts->charmap_name = argv [++i]; break; case 'i': // set locale definition file name if (argv [i + 1]) opts->source_name = argv [++i]; break; case 'c': // create output even if warnings are issued opts->force_output = true; break; case 'g': // generate more than one locale database opts->gen = true; break; case 'm': if (argv [i + 1]) opts->map_file = argv [++i]; break; case 'a': if (argv [i + 1]) opts->alias_file = argv [++i]; break; case 'r': if (argv [i + 1]) opts->charmap_dir = argv [++i]; break; case 's': if (argv [i + 1]) opts->src_dir = argv [++i]; break; case 'd': if (argv [i + 1]) opts->output_dir = argv [++i]; break; case 'w': // disable one or all warnings if (argv [i][2]) issue_diag (std::atoi (argv [i] + 2), false, 0, 0); else issue_diag (W_DISABLE, false, 0, 0); break; case '?': print_help_msg (); return false; case '-': if (0 == std::strcmp (argv [i] + 2, "help")) { print_help_msg (); return false; } if (0 == std::strcmp (argv [i] + 2, "ucs")) { // --ucs: use UCS as the internal wchar_t encoding opts->use_ucs = true; break; } else if (0 == std::strcmp (argv [i] + 2, "no_position")) { opts->no_position = true; break; } else if (0 == std::strcmp (argv [i] + 2, "aliases")) { opts->link_aliases = true; break; } else if (0 == std::strcmp (argv [i] + 2, "notes")) { // --notes: enable informational messages (notes) issue_diag (I_ENABLE, false, 0, 0); break; } // fall through default: issue_diag (E_CMDARG, true, 0, "invalid option %s\n", argv [i]); } } if (opts->gen) { bool errors = false; // make sure that all the required options are specified if (0 == opts->map_file) { issue_diag (E_NOARG, true, 0, "option %s requires a string argument\n", "-m"); } if (opts->charmap_dir.empty ()) { issue_diag (E_NOARG, true, 0, "option %s requires a string argument\n", "-r"); } if (opts->src_dir.empty ()) { issue_diag (E_NOARG, true, 0, "option %s requires a string argument\n", "-s"); } if (opts->output_dir.empty ()) { issue_diag (E_NOARG, true, 0, "option %s requires a string argument\n", "-d"); } // append a slash to the directories if the user didn't if (opts->output_dir [opts->output_dir.size () - 1] != _RWSTD_PATH_SEP) opts->output_dir += _RWSTD_PATH_SEP; if (opts->src_dir [opts->src_dir.size () - 1] != _RWSTD_PATH_SEP) opts->src_dir += _RWSTD_PATH_SEP; if (opts->charmap_dir [opts->charmap_dir.size () - 1] != _RWSTD_PATH_SEP) opts->charmap_dir += _RWSTD_PATH_SEP; } if (0 == argv [i] && !opts->gen) { issue_diag (E_NOARG, true, 0, "missing command line argument\n"); } opts->locale_name = argv [i]; if (argv [i + 1]) { issue_diag (E_XARG, true, 0, "extra command line arguments after %s\n", argv [i]); } return true; }
static void create_locale (std::string std_src, std::string std_cmap, std::string outdir, std::string std_locale, bool force_output, bool use_ucs, bool no_position, bool link_aliases) { // extract the names of the locale and of the codeset std::string lname (std_src); std::string cname (std_cmap); if (lname.rfind(_RWSTD_PATH_SEP) != std::string::npos) lname = lname.substr(lname.rfind(_RWSTD_PATH_SEP) + 1, lname.size()); if (cname.rfind(_RWSTD_PATH_SEP) != std::string::npos) cname = cname.substr(cname.rfind(_RWSTD_PATH_SEP) + 1, cname.size()); if (lname.find('.') != std::string::npos) lname = lname.substr(0, lname.find('.')); if (cname.find('.') != std::string::npos) cname = cname.substr(0, cname.find('.')); // the vector of corresponding C locales StringVector C_locales; #ifndef _MSC_VER get_same_encoding_C_locale (lname, cname, C_locales); #endif // _MSC_VER // C library locale using same encoding std::string enc_C_locale; #ifdef _RWSTD_NO_ISO_10646_WCHAR_T // the encoding C locale enc_C_locale = get_C_encoding_locale (cname); // platforms with locale dependant wchar_t encodings need the current // C locale to be set. If there is no C locale with the same name // or that uses the same encoding as the locale we are creating // issue warning if (enc_C_locale.empty ()) { issue_diag (W_COMPAT, false, 0, "no compatible locale found\n"); } else std::setlocale (LC_ALL, enc_C_locale.c_str ()); #endif // _RWSTD_NO_ISO_10646_WCHAR_T // if no charmap is present assume ISO-8859-1 if (std_cmap.empty ()) std_cmap = "ISO-8859-1"; // retrieve UTF-8 encoding aliases std::string utf8_cname("UTF-8"); StringVector utf8_aliases; get_cname_aliases (utf8_cname, utf8_aliases); // is it a UTF-8 encoded locale? bool is_utf8 = false; StringVector::iterator pos = utf8_aliases.begin(); for (; pos != utf8_aliases.end (); pos++) if (ci_compare (cname, *pos) == 0) { is_utf8 = true; break; } // retrieve the charmap/codeset object Charmap* charmap_p = 0; std::vector <Charmap*>::iterator charmaps_it = charmaps.begin(); for (; charmaps_it != charmaps.end(); charmaps_it++){ if ((*charmaps_it)->get_full_charmap_name() == std_cmap) { charmap_p = *charmaps_it; break; } } // if none found, create one and parse the corresponding file if (0 == charmap_p) { issue_diag (I_STAGE, false, 0, "processing character set description file %s\n", std_cmap.c_str ()); charmap_p = new Charmap (enc_C_locale.c_str (), std_cmap.c_str (), is_utf8, true, true, use_ucs); charmaps.push_back (charmap_p); } // parse the source definition files bool def_error = false; issue_diag (I_STAGE, false, 0, "processing locale definition file %s\n", std_src.c_str ()); Def def (std_src.c_str (), (outdir + std_locale).c_str (), *charmap_p, no_position); try { // try to parse the input files def.process_input (); } catch (...) { def_error = true; } // create the locale directory std::string locale_dir (outdir + std_locale); makedir (locale_dir.c_str ()); if (def_error) { // write out the codecvt database and exit if parsing failed def.write_codecvt (locale_dir); throw loc_exception ("abort."); } // no output when it hasn't been forced and warnings were present if (!force_output && def.warnings_occurred_) { std::cerr << "Warnings occurred - No output produced\n"; return; } // and write out the locale categories data issue_diag (I_STAGE, false, 0, "generating LC_CTYPE database\n"); def.write_ctype (locale_dir); issue_diag (I_STAGE, false, 0, "generating codeset database\n"); def.write_codecvt (locale_dir); issue_diag (I_STAGE, false, 0, "generating LC_MONETARY database\n"); def.write_monetary (locale_dir); issue_diag (I_STAGE, false, 0, "generating LC_NUMERIC database\n"); def.write_numeric (locale_dir); issue_diag (I_STAGE, false, 0, "generating LC_TIME database\n"); def.write_time (locale_dir); issue_diag (I_STAGE, false, 0, "generating LC_COLLATE database\n"); def.write_collate (locale_dir); #ifndef _MSC_VER issue_diag (I_STAGE, false, 0, "generating LC_MESSAGES database\n"); def.write_messages (locale_dir); #endif // _MSC_VER // no C library locales equivalents if (C_locales.empty ()) return; #if !defined (_MSC_VER) if (link_aliases == false) return; // some corresponding C lib locale names where found for this name StringVector::iterator it = C_locales.begin (); for (; it != C_locales.end (); it++) { // check if the name actually exists if (*it == std_locale) continue; // set a symlink with the name of the C lib locale // pointing to our locale database create_symlink (outdir, std_locale, *it); } #endif // _MSC_VER }
void Def:: write_ctype (std::string dir_name) { // dir_name cannot be empty assert (!dir_name.empty()); if (ctype_filename_.empty ()) { ctype_filename_ = dir_name + _RWSTD_PATH_SEP + lc_name; ctype_symlink_ = false; } // if a CTYPE section was not found or ctype info has been already written // in the database if (ctype_def_found_ && !ctype_written_) { issue_diag (I_OPENWR, false, 0, "writing %s\n", ctype_filename_.c_str ()); std::ofstream out (ctype_filename_.c_str(), std::ios::binary); out.exceptions (std::ios::failbit | std::ios::badbit); // calculate the offsets for the wchar_t arrays ctype_out_.wtoupper_off = 0; ctype_out_.wtolower_off = unsigned (ctype_out_.wtoupper_off + upper_.size() * sizeof (_RW::__rw_upper_elm)); ctype_out_.wmask_off = unsigned (ctype_out_.wtolower_off + lower_.size() * sizeof (_RW::__rw_lower_elm)); ctype_out_.wmask_s = unsigned (mask_.size()); // calculate the offsets for the codeset name string and character // map name string ctype_out_.codeset_off = unsigned (ctype_out_.wmask_off + mask_.size() * sizeof (_RW::__rw_mask_elm)); ctype_out_.charmap_off = unsigned (ctype_out_.codeset_off + charmap_.get_code_set_name().size() + 1); ctype_out_.mb_cur_max = charmap_.get_mb_cur_max(); std::size_t i; for (i = 0; i <= UCHAR_MAX; i++) { if(0 == ctype_out_.toupper_tab[i]) ctype_out_.toupper_tab[i] = (char)i; if(0 == ctype_out_.tolower_tab[i]) ctype_out_.tolower_tab[i] = (char)i; } // write the ctype_out structure out.write ((char*)&ctype_out_, sizeof(ctype_out_)); // print out the wide character arrays for(upper_iter u_pos = upper_.begin(); u_pos != upper_.end(); u_pos++){ _RW::__rw_upper_elm elm = {u_pos->first, u_pos->second}; out.write((char*)&elm, sizeof(elm)); } for(lower_iter l_pos = lower_.begin(); l_pos != lower_.end(); l_pos++){ _RW::__rw_lower_elm elm = {l_pos->first, l_pos->second}; out.write((char*)&elm, sizeof(elm)); } for(mask_iter m_pos = mask_.begin(); m_pos != mask_.end(); m_pos++){ _RW::__rw_mask_elm elm = {m_pos->first, m_pos->second}; out.write((char*)&elm, sizeof(elm)); } // write the code_set_name string and charmap string out << charmap_.get_code_set_name() << std::ends << charmap_.get_charmap_name() << std::ends; } #if !defined (_WIN32) && !defined (__CYGWIN__) if (ctype_symlink_) { std::string xname (ctype_filename_); if (xname [0] != _RWSTD_PATH_SEP) { xname = std::string (".."); xname += _RWSTD_PATH_SEP; xname += ctype_filename_.substr ( ctype_filename_.rfind (_RWSTD_PATH_SEP) + 1, ctype_filename_.size ()); } std::string sname (lc_name); create_symlink (output_name_, xname, sname); return; } #endif // !_WIN32 && !__CYGWIN__ }
// returns a character array consisting of NUL-separated names // of locales intalled on a system; if `loc_cat' is other than // LC_INVALID_CAT, will eliminate names that do not refer to // valid locales (i.e., those for which setlocale(loc_cat, // name) will return 0 char* get_installed_locales (int loc_cat /* = LC_INVALID_CAT */) { static char* slocname = 0; static std::size_t size = 0; // number of elements in array static std::size_t total_size = 5120; // the size of the array // allocate first time through if (!slocname) { slocname = new char [16384]; *slocname = '\0'; } char* locname = slocname; // save the current locale setting and set the locale to "C" const char* const save_localename = std::setlocale (LC_ALL, 0); std::setlocale (LC_ALL, "C"); #if __GNUG__ == 2 && __GNUC_MINOR__ == 96 // create a temporary file for the output of `locale -a' char fname_buf [L_tmpnam] = "/tmp/tmpfile-XXXXXX"; const char *fname = fname_buf; // avoid using tmpnam() to prevent the bogus gcc 2.96 warning: // the use of `tmpnam' is dangerous, better use `mkstemp' const int fd = mkstemp (fname_buf); if (-1 == fd) { std::perror ("mkstemp() failed"); std::abort(); } close (fd); #else // if !defined (gcc 2.96) // create a temporary file for the output of `locale -a' char fname_buf [L_tmpnam]; const char *fname = std::tmpnam (fname_buf); #endif // gcc 2.96 if (!fname) { std::perror ("tmpnam() failed"); std::abort (); } // create a shell command and redirect its output into the file // cmd must be at least this large: // sizeof ("locale -a | grep \"\" > ") // 22 // + strlen (fname) // must be <= L_tmpnam char cmd [80 + L_tmpnam]; std::sprintf (cmd, "LC_ALL=C /usr/bin/locale -a >%s 2>/dev/null", fname); const int ret = std::system (cmd); if (ret) issue_diag (W_NOTSUP, false, 0, "call to system(\"%s\") failed: %s\n", cmd, std::strerror (errno)); // open file containing the list of installed locales std::FILE *f = std::fopen (fname, "r"); if (f) { // even simple locale names can be very long (e.g., on HP-UX, // where a locale name always consists of the names of all // categories, such as "C C C C C C") char last_name [256]; *last_name = '\0'; // if successful, construct a char array with the locales while (std::fgets (cmd, sizeof cmd, f)) { cmd [std::strlen (cmd) - 1] = '\0'; // if our buffer is full then dynamically allocate a new one if ((size += (std::strlen (cmd) + 1)) > total_size) { total_size += 5120; char* newBuf = new char[total_size]; std::memcpy (newBuf, slocname, total_size - 5120); std::free (slocname); slocname = newBuf; locname = slocname + size - std::strlen (cmd) - 1; } #ifdef _WIN64 // prevent a hang (OS/libc bug?) std::strcpy (locname, cmd); locname += std::strlen (cmd) + 1; #else if (loc_cat != int (LC_INVALID_CAT)) { // set the C locale to verify that the name is valid const char *name = std::setlocale (loc_cat, cmd); // if it is and if the actual locale name different // from the last one, append it to the list if (name && std::strcmp (last_name, name)) { std::strcpy (locname, cmd); locname += std::strlen (cmd) + 1; // save the last locale name assert (std::strlen (name) < sizeof last_name); std::strcpy (last_name, name); } } else { std::strcpy (locname, cmd); locname += std::strlen (cmd) + 1; } #endif // _WIN64 } *locname = '\0'; } // restore the original locale if (save_localename) std::setlocale (LC_ALL, save_localename); std::fclose (f); std::remove (fname); return slocname; }
// process absolute ellipsis std::size_t Def:: process_abs_ellipsis (const Scanner::token_t &nextnext, std::ctype_base::mask m) { std::size_t nchars = 0; typedef unsigned char UChar; // first we need to handle narrow chars if the range is a range // of narrow characters UChar first; UChar last; // check to see if the start value is in the narrow map // if it is then we have to add some values to the narrow mask_tab if (get_n_val (next, first) && get_n_val (nextnext, last)) { // both the start value and end value are in the mask table // so add the mask to the narrow table from start value // to end_value. Make sure that start < end if (last < first) issue_diag (E_RANGE, true, &next, "illegal range [%u, %u] in LC_CTYPE definition\n", last, first); for (unsigned val = first; val <= last; ++val) ctype_out_.mask_tab [val] |= m; nchars += last - first; } wchar_t wfirst; wchar_t wlast; if (get_w_val (next, wfirst) && get_w_val (nextnext, wlast)) { for (wchar_t val = wfirst; val != wlast; ) { const mask_iter mask_pos = mask_.find (val); if (mask_pos == mask_.end ()) mask_.insert (std::make_pair (val, m)); else mask_pos->second |= m; val = charmap_.increment_wchar (val); ++nchars; } // now add the end_value mask_iter mask_pos = mask_.find (wlast); if(mask_pos == mask_.end ()) mask_.insert (std::make_pair (wlast, m)); else { mask_pos->second |= m; } } else { warnings_occurred_ = issue_diag (W_RANGE, false, &next, "beginning or endpoint of range " "was not found in the character map; " "ignoring range\n") || warnings_occurred_; } next = scanner_.next_token (); return nchars; }