# # patch "ChangeLog" # from [96b212e1483a8f673f6a6698f1a4d27dd940ba07] # to [2f5adc260a5402249b85ae8d6122a82a41155b5b] # # patch "commands.cc" # from [6c142e074fc47c0d2fd22e4a326480e8d507b512] # to [c8342080295451a7e1679618fabc396f9452f448] # # patch "netsync.cc" # from [ce285644b38da5591669e97b986c2cf5a287ff7f] # to [71d961a2e668c7b4f96ab03520eb72d6c90c4914] # # patch "transforms.cc" # from [05437d611e11ac3f6a0cbef9eb352a112c60d401] # to [4fe3d6c38f7fe8f7761b32e08a8d2d2de2f89e3a] # # patch "transforms.hh" # from [934c5f0c68d4ee8c18a2237398d43a59107e067a] # to [893ecdf33c3131406a499902f125f0003915aab9] # # patch "ui.cc" # from [3cbe9c661750040b4663d3f1b05d85ff964707ff] # to [b36b029d0461552bbc5d7ef80bd97a17c16396aa] # ======================================================================== --- ChangeLog 96b212e1483a8f673f6a6698f1a4d27dd940ba07 +++ ChangeLog 2f5adc260a5402249b85ae8d6122a82a41155b5b @@ -1,3 +1,13 @@ +2005-10-14 Matthew Gregan + + * commands.cc (message_width): Refactor into display_width() and + remove message_width(). + * transforms.{cc,hh} (display_width): Rename length() to + display_width() and use the code from message_width(). + * ui.cc, commands.cc: Change calls to length() to display_width(). + * netsync.cc: Remove length() calls, test for string emptiness + instead. + 2005-10-13 Emile Snyder * commands.cc (CMD(revert)): use --missing for revert a'la drop. ======================================================================== --- commands.cc 6c142e074fc47c0d2fd22e4a326480e8d507b512 +++ commands.cc c8342080295451a7e1679618fabc396f9452f448 @@ -173,25 +173,6 @@ return _(msgid); } - // returns the columns needed for printing the translated msgid - size_t message_width(const char * msgid) - { - const char * msg = safe_gettext(msgid); - - // convert from multi-byte to wide-char string - size_t wchars = mbstowcs(0, msg, 0) + 1; - if (wchars == (size_t)-1) - return std::strlen(msgid); // conversion failed; punt and return original length - boost::scoped_array wmsg(new wchar_t[wchars]); - mbstowcs(wmsg.get(), msg, wchars); - - // and get printed width - size_t width = wcswidth(wmsg.get(), wchars); - - return width; - } - - void explain_usage(string const & cmd, ostream & out) { map::const_iterator i; @@ -230,7 +211,7 @@ size_t col2 = 0; for (size_t i = 0; i < sorted.size(); ++i) { - size_t cmp = message_width(idx(sorted, i)->cmdgroup.c_str()); + size_t cmp = display_width(utf8(safe_gettext(idx(sorted, i)->cmdgroup.c_str()))); col2 = col2 > cmp ? col2 : cmp; } @@ -241,7 +222,7 @@ curr_group = idx(sorted, i)->cmdgroup; out << endl; out << " " << safe_gettext(idx(sorted, i)->cmdgroup.c_str()); - col = message_width(idx(sorted, i)->cmdgroup.c_str()) + 2; + col = display_width(utf8(safe_gettext(idx(sorted, i)->cmdgroup.c_str()))) + 2; while (col++ < (col2 + 3)) out << ' '; } @@ -578,7 +559,7 @@ if (colon_pos != string::npos) { string substr(str, 0, colon_pos); - colon_pos = length(substr); + colon_pos = display_width(substr); extra_str = string(colon_pos, ' ') + ": %s\n"; } ======================================================================== --- netsync.cc ce285644b38da5591669e97b986c2cf5a287ff7f +++ netsync.cc 71d961a2e668c7b4f96ab03520eb72d6c90c4914 @@ -3340,10 +3340,10 @@ timeout(static_cast(timeout_seconds)), instant(0,1); - if (length(app.bind_port)) + if (!app.bind_port().empty()) default_port = ::atoi(app.bind_port().c_str()); Netxx::Address addr; - if (length(app.bind_address)) + if (!app.bind_address().empty()) addr.add_address(app.bind_address().c_str(), default_port); else addr.add_all_addresses (default_port); ======================================================================== --- transforms.cc 05437d611e11ac3f6a0cbef9eb352a112c60d401 +++ transforms.cc 4fe3d6c38f7fe8f7761b32e08a8d2d2de2f89e3a @@ -538,13 +538,28 @@ utf = out; } -// hack: this is an unexposed function in libidna -extern "C" long g_utf8_strlen(const char * p, size_t max); - size_t -length(utf8 const & utf) +display_width(utf8 const & utf) { - return g_utf8_strlen(utf().c_str(), utf().size()); + // this function is called many thousands of times by the tickers, so we + // try and avoid performing heap allocations by starting with a reasonable + // size buffer, and only ever growing the buffer if needed. + static size_t widebuf_sz = 128; + static boost::scoped_array widebuf(new wchar_t[widebuf_sz]); + + size_t len = mbstowcs(0, utf().c_str(), 0) + 1; + + if (len == static_cast(-1)) + return utf().length(); // conversion failed; punt and return original length + + if (len > widebuf_sz) { + widebuf.reset(new wchar_t[len]); + widebuf_sz = len; + } + + mbstowcs(widebuf.get(), utf().c_str(), widebuf_sz); + + return wcswidth(widebuf.get(), widebuf_sz); } // Lots of gunk to avoid charset conversion as much as possible. Running ======================================================================== --- transforms.hh 934c5f0c68d4ee8c18a2237398d43a59107e067a +++ transforms.hh 893ecdf33c3131406a499902f125f0003915aab9 @@ -179,7 +179,7 @@ void utf8_to_ace(utf8 const & utf, ace & a); // returns length in characters (not bytes) -size_t length(utf8 const & utf); +size_t display_width(utf8 const & utf); // specific internal / external conversions for various vocab terms void internalize_cert_name(utf8 const & utf, cert_name & c); ======================================================================== --- ui.cc 3cbe9c661750040b4663d3f1b05d85ff964707ff +++ ui.cc b36b029d0461552bbc5d7ef80bd97a17c16396aa @@ -93,17 +93,17 @@ for (map::const_iterator i = ui.tickers.begin(); i != ui.tickers.end(); ++i) { - width = 1 + length(utf8(i->second->name)); + width = 1 + display_width(utf8(i->second->name)); if (!first_tick) { tickline1 += " | "; tickline2 += " |"; } first_tick = false; - if (length(utf8(i->second->name)) < minwidth) + if (display_width(utf8(i->second->name)) < minwidth) { - tickline1.append(minwidth - length(utf8(i->second->name)),' '); - width += minwidth - length(utf8(i->second->name)); + tickline1.append(minwidth - display_width(utf8(i->second->name)),' '); + width += minwidth - display_width(utf8(i->second->name)); } tickline1 += i->second->name; @@ -133,16 +133,16 @@ count = (F("%d") % i->second->ticks).str(); } - if (length(utf8(count)) < width) + if (display_width(utf8(count)) < width) { - tickline2.append(width - length(utf8(count)),' '); + tickline2.append(width - display_width(utf8(count)),' '); } - else if (length(utf8(count)) > width) + else if (display_width(utf8(count)) > width) { // FIXME: not quite right, because substr acts on bytes rather than // characters; but there are always more bytes than characters, so // at worst this will just chop off a little too much. - count = count.substr(length(utf8(count)) - width); + count = count.substr(display_width(utf8(count)) - width); } tickline2 += count; } @@ -153,7 +153,7 @@ tickline2 += ui.tick_trailer; } - size_t curr_sz = length(utf8(tickline2)); + size_t curr_sz = display_width(utf8(tickline2)); if (curr_sz < last_tick_len) tickline2.append(last_tick_len - curr_sz, ' '); last_tick_len = curr_sz; @@ -161,7 +161,7 @@ unsigned int tw = terminal_width(); if(!ui.last_write_was_a_tick) { - if (tw && length(utf8(tickline1)) > tw) + if (tw && display_width(utf8(tickline1)) > tw) { // FIXME: may chop off more than necessary (because we chop by // bytes, not by characters) @@ -169,7 +169,7 @@ } clog << tickline1 << "\n"; } - if (tw && length(utf8(tickline2)) > tw) + if (tw && display_width(utf8(tickline2)) > tw) { // first character in tickline2 is "\r", which does not take up any // width, so we add 1 to compensate.