From 03788340718a0c1d93ea664db25d78c6df3b749e Mon Sep 17 00:00:00 2001 From: Alex Alabuzhev Date: Fri, 19 May 2017 22:38:55 +0000 Subject: [PATCH] #3434 and other format-related --- far/FarEng.hlf.m4 | 11 +-- far/FarRus.hlf.m4 | 10 +- far/changelog | 7 ++ far/clipboard.cpp | 2 +- far/copy_progress.cpp | 4 +- far/datetime.cpp | 2 +- far/diskmenu.cpp | 8 +- far/farlang.templ.m4 | 20 ++-- far/filelist.cpp | 27 +++--- far/infolist.cpp | 4 +- far/locale.cpp | 12 +-- far/macro.cpp | 2 +- far/panelctype.hpp | 19 ++-- far/plugapi.cpp | 8 +- far/qview.cpp | 6 +- far/strmix.cpp | 211 ++++++++++++++++++------------------------ far/strmix.hpp | 3 +- far/vbuild.m4 | 2 +- 18 files changed, 168 insertions(+), 190 deletions(-) diff --git a/far/FarEng.hlf.m4 b/far/FarEng.hlf.m4 index a058af45a7..65b7c9e0a7 100644 --- a/far/FarEng.hlf.m4 +++ b/far/FarEng.hlf.m4 @@ -1773,10 +1773,9 @@ Allowed column types are: G[C,T,F,E] - size of file streams where: C - format file size; T - use 1000 instead of 1024 as a divider; - F - show file sizes similar to Windows - Explorer (i.e. 999 bytes will be - displayed as 999 and 1000 bytes will - be displayed as 0.97 K); + F - show size as a decimal fraction + using the most appropriate unit, + e. g. 0.97 K, 1.44 M, 3.5 G etc. E - economic mode, no space between file size and suffix will be shown (i.e. 0.97K); @@ -3454,8 +3453,8 @@ $ #Change Drive Menu Options# Показать общее и свободное место на диске. Комбинация клавиш в меню: Ctrl-5 - #Показывать размер в стиле Windows Explorer# - Уточние опции показа размеров диска в стиле Windows Explorer (в виде числа с плавающей точкой). + #Показывать размер в виде десятичной дроби# + Показать общее и свободное место на диске в виде десятичной дроби. Комбинация клавиш в меню: Ctrl-5 (повторное нажатие). #Показывать сетевое имя/путь SUBST/имя VHD# diff --git a/far/FarRus.hlf.m4 b/far/FarRus.hlf.m4 index c94ec4e090..31482dbbdd 100644 --- a/far/FarRus.hlf.m4 +++ b/far/FarRus.hlf.m4 @@ -1804,9 +1804,9 @@ $ #Дополнительные параметры поиска# G[C,T,F,E] - размер потоков файла где: C - форматировать размер файла; T - использовать 1000 вместо 1024 как делитель; - F - показывать размер файла в стиле Windows - Explorer (т.е. 999 байт будут показаны - как 999, а 1000 байт как 0.97 K); + F - показывать размер в виде десятичной дроби, используя + наиболее подходящую единицу измерения, например + 0,97 К, 1,44 М, 53,2 Г. E - экономичный режим, не показывать пробел перед суффиксом размера файла (т.е. 0.97KB); @@ -3525,8 +3525,8 @@ $ #Настройка меню выбора диска# Показать общее и свободное место на диске. Комбинация клавиш в меню: Ctrl-5 - #Показывать размер в стиле Windows Explorer# - Уточние опции показа размеров диска в стиле Windows Explorer (в виде числа с плавающей точкой). + #Показывать размер в виде десятичной дроби# + Показать общее и свободное место на диске в виде десятичной дроби. Комбинация клавиш в меню: Ctrl-5 (повторное нажатие). #Показывать сетевое имя/путь SUBST/имя VHD# diff --git a/far/changelog b/far/changelog index 5385379800..a2217f2235 100644 --- a/far/changelog +++ b/far/changelog @@ -1,3 +1,10 @@ +drkns 19.05.2017 23:29:09 +0000 - build 4963 + +1. 0003434: В функции FormatFileSize параметр Width не полностью соотвествуют документации. + Изменение в API: "сколько получится" теперь подразумевается при 0, а не при -1. + +2. Прочие исправления (а возможно и новые баги) в той же функции и окресностях. + drkns 16.05.2017 07:34:39 +0000 - build 4962 1. Уточение процесса загрузки плагинов. diff --git a/far/clipboard.cpp b/far/clipboard.cpp index c17871ea29..1dd3489c8f 100644 --- a/far/clipboard.cpp +++ b/far/clipboard.cpp @@ -131,7 +131,7 @@ class system_clipboard: noncopyable, public Clipboard hMem.release(); - auto Locale = os::memory::global::copy(LOCALE_USER_DEFAULT); + auto Locale = os::memory::global::copy(GetThreadLocale()); if (!Locale) return false; diff --git a/far/copy_progress.cpp b/far/copy_progress.cpp index fc7d95d54d..32c2189697 100644 --- a/far/copy_progress.cpp +++ b/far/copy_progress.cpp @@ -137,8 +137,8 @@ static string FormatCounter(lng CounterId, lng AnotherId, unsigned long long Cur const auto PaddedLabelSize = std::max(Label.size(), msg(AnotherId).size()) + 1; Label.resize(PaddedLabelSize, L' '); - auto StrCurrent = InsertCommas(CurrentValue); - auto StrTotal = ShowTotal? InsertCommas(TotalValue) : string(); + const auto StrCurrent = GroupDigits(CurrentValue); + const auto StrTotal = ShowTotal? GroupDigits(TotalValue) : string(); auto Value = ShowTotal? concat(StrCurrent, L" / "_sv, StrTotal) : StrCurrent; if (MaxWidth > PaddedLabelSize) diff --git a/far/datetime.cpp b/far/datetime.cpp index 499ae596c8..818907377c 100644 --- a/far/datetime.cpp +++ b/far/datetime.cpp @@ -139,7 +139,7 @@ void OnIntlSettingsChange() DWORD ConvertYearToFull(DWORD ShortYear) { DWORD UpperBoundary = 0; - if(!GetCalendarInfo(LOCALE_USER_DEFAULT, CAL_GREGORIAN, CAL_ITWODIGITYEARMAX|CAL_RETURN_NUMBER, nullptr, 0, &UpperBoundary)) + if(!GetCalendarInfo(GetThreadLocale(), CAL_GREGORIAN, CAL_ITWODIGITYEARMAX|CAL_RETURN_NUMBER, nullptr, 0, &UpperBoundary)) { UpperBoundary = 2029; // Magic, current default value. } diff --git a/far/diskmenu.cpp b/far/diskmenu.cpp index 9023d57bee..86917ef4c7 100644 --- a/far/diskmenu.cpp +++ b/far/diskmenu.cpp @@ -744,14 +744,14 @@ static int ChangeDiskMenu(panel_ptr Owner, int Pos, bool FirstCall) if (Global->Opt->ChangeDriveMode & DRIVE_SHOW_SIZE) { //размер как минимум в мегабайтах - NewItem.TotalSize = FileSizeToStr(TotalSize, 9, COLUMN_COMMAS | COLUMN_MULTIPLIER_M); - NewItem.FreeSize = FileSizeToStr(UserFree, 9, COLUMN_COMMAS | COLUMN_MULTIPLIER_M); + NewItem.TotalSize = FileSizeToStr(TotalSize, 9, COLUMN_COMMAS | COLUMN_UNIT_M); + NewItem.FreeSize = FileSizeToStr(UserFree, 9, COLUMN_COMMAS | COLUMN_UNIT_M); } else { //размер с точкой и для 0 добавляем букву размера (B) - NewItem.TotalSize = FileSizeToStr(TotalSize, 9, COLUMN_FLOATSIZE | COLUMN_SHOWMULTIPLIER); - NewItem.FreeSize = FileSizeToStr(UserFree, 9, COLUMN_FLOATSIZE | COLUMN_SHOWMULTIPLIER); + NewItem.TotalSize = FileSizeToStr(TotalSize, 9, COLUMN_FLOATSIZE | COLUMN_SHOWUNIT); + NewItem.FreeSize = FileSizeToStr(UserFree, 9, COLUMN_FLOATSIZE | COLUMN_SHOWUNIT); } RemoveExternalSpaces(NewItem.TotalSize); RemoveExternalSpaces(NewItem.FreeSize); diff --git a/far/farlang.templ.m4 b/far/farlang.templ.m4 index 5b237f66f5..de13d21eab 100644 --- a/far/farlang.templ.m4 +++ b/far/farlang.templ.m4 @@ -16390,16 +16390,16 @@ upd:"Show &size" "Показувати &розмір" MChangeDriveShowSizeFloat -"Показывать ра&змер в стиле Windows Explorer" -"Show size in &Windows Explorer style" -"Zobrazit velikost ve stylu Průzkumníka &Windows" -"Größe als in &Windows Explorer anzeigen" -upd:"Show size in &Windows Explorer style" -upd:"Show size in &Windows Explorer style" -"Mostrar tamaño estilo &Windows Explorer" -"Zobraziť veľkosť v štýle Prieskumníka &Windows" -"Mostra Dimensione Come &Windows" -"Показувати ро&змір у стилі Windows Explorer" +"Показывать ра&змер в виде десятичной дроби" +"Show size as a decimal fraction" +upd:"Show size as a decimal fraction" +upd:"Show size as a decimal fraction" +upd:"Show size as a decimal fraction" +upd:"Show size as a decimal fraction" +upd:"Show size as a decimal fraction" +upd:"Show size as a decimal fraction" +upd:"Show size as a decimal fraction" +"Показувати ро&змір у вигляді десяткового дробу" MChangeDriveShowRemovableDrive "Показывать параметры см&енных дисков" diff --git a/far/filelist.cpp b/far/filelist.cpp index 19f5be60db..c9771cb6f6 100644 --- a/far/filelist.cpp +++ b/far/filelist.cpp @@ -7799,27 +7799,24 @@ void FileList::SetShowColor(int Position, bool FileColor) const SetColor(GetShowColor(Position,FileColor)); } -static string size2str(ULONGLONG Size, int width, int short_mode = -1) +static string size2str(ULONGLONG Size, int width, bool FloatStyle, bool short_mode) { - if (short_mode < 0) - short_mode = Global->Opt->ShowBytes ? 0 : +1; - if (!short_mode) { - return InsertCommas(Size); + return GroupDigits(Size); } - else if (width <= 0) // float style + else if (FloatStyle) // float style { - auto str = FileSizeToStr(Size, 10, COLUMN_FLOATSIZE | COLUMN_SHOWMULTIPLIER); + auto str = FileSizeToStr(Size, width, COLUMN_FLOATSIZE | COLUMN_SHOWUNIT); RemoveExternalSpaces(str); return str; } else { string Str = str(Size); - if (Str.size() > static_cast(width)) + if (static_cast(Str.size()) > width) { - Str = FileSizeToStr(Size, width, COLUMN_SHOWMULTIPLIER); + Str = FileSizeToStr(Size, width, COLUMN_SHOWUNIT); RemoveExternalSpaces(Str); } return Str; @@ -7847,12 +7844,12 @@ void FileList::ShowSelectedSize() } if (m_SelFileCount) { - auto strFormStr = size2str(SelFileSize, 6, 0); + auto strFormStr = size2str(SelFileSize, 6, false, false); auto strSelStr = format(lng::MListFileSize, strFormStr, m_SelFileCount-m_SelDirCount, m_SelDirCount); auto avail_width = static_cast(std::max(0, m_X2 - m_X1 - 1)); if (strSelStr.size() > avail_width) { - strFormStr = size2str(SelFileSize, 6, +1); + strFormStr = size2str(SelFileSize, 6, false, true); strSelStr = format(lng::MListFileSize, strFormStr, m_SelFileCount-m_SelDirCount, m_SelDirCount); if (strSelStr.size() > avail_width) TruncStrFromEnd(strSelStr, static_cast(avail_width)); @@ -7870,12 +7867,12 @@ void FileList::ShowTotalSize(const OpenPanelInfo &Info) if (!Global->Opt->ShowPanelTotals && m_PanelMode == panel_mode::PLUGIN_PANEL && !(Info.Flags & OPIF_REALNAMES)) return; - const auto& calc_total_string = [this, Info](int short_mode) + const auto& calc_total_string = [this, Info](bool short_mode) { string strFreeSize, strTotalSize; - auto strFormSize = size2str(TotalFileSize, 6, short_mode); + auto strFormSize = size2str(TotalFileSize, 6, false, short_mode); if (Global->Opt->ShowPanelFree && (m_PanelMode != panel_mode::PLUGIN_PANEL || (Info.Flags & (OPIF_REALNAMES | OPIF_USEFREESIZE)))) - strFreeSize = (FreeDiskSize != static_cast(-1)) ? size2str(FreeDiskSize, 0, short_mode) : L"?"; + strFreeSize = (FreeDiskSize != static_cast(-1)) ? size2str(FreeDiskSize, 10, true, short_mode) : L"?"; if (Global->Opt->ShowPanelTotals) { @@ -7897,7 +7894,7 @@ void FileList::ShowTotalSize(const OpenPanelInfo &Info) }; auto avail_width = static_cast(std::max(0, m_X2 - m_X1 - 1)); - auto strTotalStr = calc_total_string(-1); + auto strTotalStr = calc_total_string(!Global->Opt->ShowBytes); if (strTotalStr.size() > avail_width) { if (Global->Opt->ShowBytes) diff --git a/far/infolist.cpp b/far/infolist.cpp index f5f0e6ba0f..fc090e6203 100644 --- a/far/infolist.cpp +++ b/far/infolist.cpp @@ -375,11 +375,11 @@ void InfoList::DisplayObject() string str; if (Global->Opt->ShowBytes) { - str = InsertCommas(Size); // + L' '; + str = GroupDigits(Size); // + L' '; } else { - str = FileSizeToStr(Size, 16, COLUMN_FLOATSIZE | COLUMN_SHOWMULTIPLIER); + str = FileSizeToStr(Size, 16, COLUMN_FLOATSIZE | COLUMN_SHOWUNIT); if (str.back() != bytes_suffix[0]) str += bytes_suffix; } diff --git a/far/locale.cpp b/far/locale.cpp index 987841ab65..42c9c8fba4 100644 --- a/far/locale.cpp +++ b/far/locale.cpp @@ -40,7 +40,7 @@ int locale::GetDateFormat() int Result; // TODO: log - if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDATE | LOCALE_RETURN_NUMBER, reinterpret_cast(&Result), sizeof(Result) / sizeof(wchar_t))) + if (!GetLocaleInfo(GetThreadLocale(), LOCALE_IDATE | LOCALE_RETURN_NUMBER, reinterpret_cast(&Result), sizeof(Result) / sizeof(wchar_t))) return 0; return Result; @@ -49,7 +49,7 @@ int locale::GetDateFormat() wchar_t locale::GetDateSeparator() { wchar_t Info[100]; - if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, Info, static_cast(std::size(Info)))) + if (!GetLocaleInfo(GetThreadLocale(), LOCALE_SDATE, Info, static_cast(std::size(Info)))) { // TODO: log return L'/'; @@ -60,7 +60,7 @@ wchar_t locale::GetDateSeparator() wchar_t locale::GetTimeSeparator() { wchar_t Info[100]; - if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, Info, static_cast(std::size(Info)))) + if (!GetLocaleInfo(GetThreadLocale(), LOCALE_STIME, Info, static_cast(std::size(Info)))) { // TODO: log return L':'; @@ -71,7 +71,7 @@ wchar_t locale::GetTimeSeparator() wchar_t locale::GetDecimalSeparator() { wchar_t Separator[4]; - if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, Separator, static_cast(std::size(Separator)))) + if (!GetLocaleInfo(GetThreadLocale(), LOCALE_SDECIMAL, Separator, static_cast(std::size(Separator)))) { // TODO: log *Separator = L'.'; @@ -86,7 +86,7 @@ wchar_t locale::GetDecimalSeparator() wchar_t locale::GetThousandSeparator() { wchar_t Separator[4]; - if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, Separator, static_cast(std::size(Separator)))) + if (!GetLocaleInfo(GetThreadLocale(), LOCALE_STHOUSAND, Separator, static_cast(std::size(Separator)))) { // TODO: log *Separator = L','; @@ -106,7 +106,7 @@ string locale::GetValue(LCID lcid, LCTYPE id) string locale::GetTimeFormat() { wchar_t TimeBuffer[MAX_PATH]; - const size_t Size = ::GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, nullptr, nullptr, TimeBuffer, static_cast(std::size(TimeBuffer))); + const size_t Size = ::GetTimeFormat(GetThreadLocale(), TIME_NOSECONDS, nullptr, nullptr, TimeBuffer, static_cast(std::size(TimeBuffer))); if (!Size) { diff --git a/far/macro.cpp b/far/macro.cpp index 7d79bbf83f..3098de2b23 100644 --- a/far/macro.cpp +++ b/far/macro.cpp @@ -2908,7 +2908,7 @@ static bool size2strFunc(FarMacroCall* Data) { const auto Params = parseParams(3, Data); const auto Width = static_cast(Params[2].asInteger()); - PassString(FileSizeToStr(Params[0].asInteger(), !Width? -1 : Width, Params[1].asInteger()), Data); + PassString(FileSizeToStr(Params[0].asInteger(), Width, Params[1].asInteger()), Data); return true; } diff --git a/far/panelctype.hpp b/far/panelctype.hpp index c81b7a8667..7f638caa9b 100644 --- a/far/panelctype.hpp +++ b/far/panelctype.hpp @@ -69,20 +69,23 @@ enum FILEPANEL_COLUMN_MODES: unsigned long long COLUMN_THOUSAND = 0x0400000000000000LL, // Вместо делителя 1024 использовать делитель 1000 COLUMN_BRIEF = 0x0200000000000000LL, COLUMN_MONTH = 0x0100000000000000LL, - COLUMN_FLOATSIZE = 0x0080000000000000LL, // Показывать размер файла в стиле Windows Explorer (т.е. 999 байт будут показаны как 999, а 1000 байт как 0.97 K) + COLUMN_FLOATSIZE = 0x0080000000000000LL, // Показывать размер в виде десятичной дроби, используя наиболее подходящую единицу измерения, например 0,97 К, 1,44 М, 53,2 Г. + COLUMN_ECONOMIC = 0x0040000000000000LL, // Экономичный режим, не показывать пробел перед суффиксом размера файла (т.е. 0.97K) - COLUMN_SHOWMULTIPLIER = 0x0010000000000000LL, // Показывать суффиксы B,K,M,G,T,P,E + COLUMN_SHOWUNIT = 0x0010000000000000LL, // Показывать суффиксы B,K,M,G,T,P,E COLUMN_FULLOWNER = 0x0008000000000000LL, COLUMN_NOEXTENSION = 0x0004000000000000LL, COLUMN_RIGHTALIGNFORCE = 0x0001000000000000LL, COLUMN_MARK_DYNAMIC = 0x0000800000000000LL, - COLUMN_USE_MULTIPLIER = 0x0020000000000000LL, // Минимально допустимый множитель при форматировании - COLUMN_MULTIPLIER_K = COLUMN_USE_MULTIPLIER | 0, - COLUMN_MULTIPLIER_M = COLUMN_USE_MULTIPLIER | 1, - COLUMN_MULTIPLIER_G = COLUMN_USE_MULTIPLIER | 2, - COLUMN_MULTIPLIER_T = COLUMN_USE_MULTIPLIER | 3, - COLUMN_MULTIPLIER_MASK = 0x0000000000000003LL // может быть только 0, 1, 2 или 3 (K,M,G,T), например, 1 - "размер как минимум в мегабайтах" + COLUMN_USE_UNIT = 0x0020000000000000LL, // Минимально допустимыая единица измерения при форматировании например, 1 - "размер как минимум в мегабайтах" + COLUMN_UNIT_K = COLUMN_USE_UNIT | 0, + COLUMN_UNIT_M = COLUMN_USE_UNIT | 1, + COLUMN_UNIT_G = COLUMN_USE_UNIT | 2, + COLUMN_UNIT_T = COLUMN_USE_UNIT | 3, + COLUMN_UNIT_P = COLUMN_USE_UNIT | 4, + COLUMN_UNIT_E = COLUMN_USE_UNIT | 5, + COLUMN_UNIT_MASK = 0x000000000000000FLL }; enum col_width diff --git a/far/plugapi.cpp b/far/plugapi.cpp index 0184cdd39d..2cf19577de 100644 --- a/far/plugapi.cpp +++ b/far/plugapi.cpp @@ -2800,13 +2800,13 @@ size_t WINAPI apiFormatFileSize(unsigned long long Size, intptr_t Width, FARFORM { {FFFS_COMMAS, COLUMN_COMMAS}, // Вставлять разделитель между тысячами {FFFS_THOUSAND, COLUMN_THOUSAND}, // Вместо делителя 1024 использовать делитель 1000 - {FFFS_FLOATSIZE, COLUMN_FLOATSIZE}, // Показывать размер файла в стиле Windows Explorer (т.е. 999 байт будут показаны как 999, а 1000 байт как 0.97 K) + {FFFS_FLOATSIZE, COLUMN_FLOATSIZE}, // Показывать размер в виде десятичной дроби, используя наиболее подходящую единицу измерения, например 0,97 К, 1,44 М, 53,2 Г. {FFFS_ECONOMIC, COLUMN_ECONOMIC}, // Экономичный режим, не показывать пробел перед суффиксом размера файла (т.е. 0.97K) - {FFFS_MINSIZEINDEX, COLUMN_USE_MULTIPLIER}, // Минимально допустимый множитель при форматировании - {FFFS_SHOWBYTESINDEX, COLUMN_SHOWMULTIPLIER}, // Показывать суффиксы B,K,M,G,T,P,E + {FFFS_MINSIZEINDEX, COLUMN_USE_UNIT}, // Минимально допустимая единица измерения при форматировании + {FFFS_SHOWBYTESINDEX, COLUMN_SHOWUNIT}, // Показывать суффиксы B,K,M,G,T,P,E }; - unsigned long long FinalFlags = std::accumulate(ALL_CONST_RANGE(FlagsPair), Flags & COLUMN_MULTIPLIER_MASK, [Flags](auto FinalFlags, const auto& i){ return FinalFlags | ((Flags & i.first)? i.second : 0); }); + unsigned long long FinalFlags = std::accumulate(ALL_CONST_RANGE(FlagsPair), Flags & COLUMN_UNIT_MASK, [Flags](auto FinalFlags, const auto& i){ return FinalFlags | ((Flags & i.first)? i.second : 0); }); auto strDestStr = FileSizeToStr(Size, Width, FinalFlags); diff --git a/far/qview.cpp b/far/qview.cpp index 7104675dfc..dbf297e3b1 100644 --- a/far/qview.cpp +++ b/far/qview.cpp @@ -233,11 +233,11 @@ void QuickView::DisplayObject() { if (Global->Opt->ShowBytes) { - return InsertCommas(Size); // + L' ' + bytes_suffix; + return GroupDigits(Size); // + L' ' + bytes_suffix; } else { - auto str = FileSizeToStr(Size, 10, COLUMN_FLOATSIZE | COLUMN_SHOWMULTIPLIER); + auto str = FileSizeToStr(Size, 10, COLUMN_FLOATSIZE | COLUMN_SHOWUNIT); RemoveExternalSpaces(str); if (str.back() != bytes_suffix[0]) str += bytes_suffix; @@ -278,7 +278,7 @@ void QuickView::DisplayObject() GotoXY(m_X1+2,m_Y1+11); PrintText(msg(lng::MQuickViewCluster)); SetColor(iColor); - PrintText(prefix + InsertCommas(Data.ClusterSize)); + PrintText(prefix + GroupDigits(Data.ClusterSize)); SetColor(COL_PANELTEXT); GotoXY(m_X1+2,m_Y1+12); diff --git a/far/strmix.cpp b/far/strmix.cpp index 7d49756eb7..8e6e7fab42 100644 --- a/far/strmix.cpp +++ b/far/strmix.cpp @@ -51,32 +51,26 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace strmix { -string FormatNumber(const string& Src, int NumDigits) +string GroupDigits(unsigned long long Value) { - static bool first = true; - static NUMBERFMT fmt; - static wchar_t DecimalSep[4] = {}; - static wchar_t ThousandSep[4] = {}; + NUMBERFMT Fmt{}; - if (first) - { - DecimalSep[0] = locale::GetDecimalSeparator(); - ThousandSep[0] = locale::GetThousandSeparator(); - - fmt.LeadingZero = 1; - fmt.Grouping = 3; - fmt.lpDecimalSep = DecimalSep; - fmt.lpThousandSep = ThousandSep; - fmt.NegativeOrder = 1; - first = false; - } + wchar_t DecimalSeparator[] = { locale::GetDecimalSeparator(), L'\0' }; + wchar_t ThousandSeparator[] = { locale::GetThousandSeparator(), L'\0' }; + + // TODO pick regional settings + Fmt.NumDigits = 0; + Fmt.LeadingZero = 1; + Fmt.Grouping = 3; + Fmt.lpDecimalSep = DecimalSeparator; + Fmt.lpThousandSep = ThousandSeparator; + Fmt.NegativeOrder = 1; - fmt.NumDigits = NumDigits; - string strSrc=Src; - int Size=GetNumberFormat(LOCALE_USER_DEFAULT,0,strSrc.data(),&fmt,nullptr,0); + string strSrc = str(Value); + const size_t Size = GetNumberFormat(GetThreadLocale(), 0, strSrc.data(), &Fmt, nullptr, 0); wchar_t_ptr Dest(Size); - GetNumberFormat(LOCALE_USER_DEFAULT,0,strSrc.data(),&fmt, Dest.get(), Size); - return string(Dest.get(), Size - 1); + GetNumberFormat(GetThreadLocale(), 0, strSrc.data(), &Fmt, Dest.get(), static_cast(Size)); + return { Dest.get(), Size - 1 }; } static wchar_t * InsertCustomQuote(wchar_t *Str,wchar_t QuoteChar) @@ -500,150 +494,129 @@ enum UNIT_COUNT = 7, // byte, kilobyte, megabyte, gigabyte, terabyte, petabyte, exabyte. }; -static string& UnitStr(size_t B, size_t Div) +static string& UnitStr(size_t Unit, bool Binary) { static string Data[UNIT_COUNT][2]; - return Data[B][Div]; + return Data[Unit][Binary? 1 : 0]; } void PrepareUnitStr() { for (int i=0; i{1}.{1}}{2}{3}"; - // Library doesn't support dynamic alignment currently. TODO: fix it? - if (LeftAlign) + const auto& FitToWidth = [&](string&& Str) { - Format[3] = L'<'; - } - return format(Format, Str, Width, Economic? L"" : L" ", UnitStr(IndexB, IndexDiv).front()); - }; + if (!Width) + return Str; - const auto ReduceWidth = [&] - { - const auto Subtraction = Economic? 1u : 2u; - Width = Width > Subtraction? Width - Subtraction : 0; - }; + if (Str.size() <= Width) + return (LeftAlign? pad_right : pad_left)(std::move(Str), Width, L' '); - const auto Align = LeftAlign? fit_to_left : fit_to_right; + Str = (LeftAlign? cut_right : cut_left)(std::move(Str), Width - 1); + Str.insert(LeftAlign? Str.end() : Str.begin(), L'\x2026'); + return Str; + }; - if (FloatSize) - { - unsigned long long Divider64F = 1, Divider64F_mul = 1000, Divider64F2 = 1, Divider64F2_mul = Divider; + if (!UnitIndex && !ShowUnit) + return FitToWidth(std::move(StrSize)); - //выравнивание идёт по 1000 но само деление происходит на Divider - //например 999 bytes покажутся как 999 а вот 1000 bytes уже покажутся как 0.97 K - size_t IndexB = 0; - for (; IndexB != UNIT_COUNT - 1; ++IndexB) - { - if (Sz < Divider64F*Divider64F_mul) - break; + return FitToWidth(concat(StrSize, UseCompact? L""_sv : L" "_sv, UnitStr(UnitIndex, UseBinaryUnit).front())); + }; - Divider64F = Divider64F*Divider64F_mul; - Divider64F2 = Divider64F2*Divider64F2_mul; - } + if (UseFloatSize) + { + const size_t UnitIndex = FileSize? std::log(FileSize) / Divider.second : 0; string Str; - if (!IndexB) + if (!UnitIndex) { - Str = str(Sz); + Str = str(FileSize); } else { - Sz = (OldSize=Sz) / Divider64F2; - OldSize = (OldSize % Divider64F2) / (Divider64F2 / Divider64F2_mul); - DWORD Decimal = (DWORD)(0.5+(double)(DWORD)OldSize/(double)Divider*100.0); - - if (Decimal >= 100) + const auto SizeInUnits = FileSize / std::pow(Divider.first, UnitIndex); + + double Parts[2]; + Parts[1] = std::modf(SizeInUnits, &Parts[0]); + + const auto Integral = static_cast(Parts[0]); + Str = str(Integral); + if (const auto NumDigits = Integral < 10? 2 : Integral < 100? 1 : 0) { - Decimal -= 100; - Sz++; - } - // BUGBUG too complex - Str = FormatNumber(format(L"{0}.{1:02}", Sz, Decimal), 2); - } + auto Fractional = static_cast(std::round(Parts[1] * (NumDigits == 2? 100 : 10)) * (NumDigits == 1? 10 : 1)); + if (Fractional == 100) + { + Str = str(Integral + 1); + Fractional = 0; + } - if (IndexB <= 0 && !ShowMultiplier) - return Align(Str, Width); + // Explorer-style + //auto Fractional = static_cast(Parts[1] * 100); - ReduceWidth(); - return FormatSize(Str, IndexB); + const auto Div = std::div(Fractional, 10); + const wchar_t StrFractional[] = { wchar_t(L'0' + Div.quot), wchar_t(L'0' + Div.rem), L'\0' }; + append(Str, locale::GetDecimalSeparator(), string_view(StrFractional, NumDigits)); + } + } + + return FormatSize(std::move(Str), UnitIndex); } + const auto& ToStr = [UseCommas](auto Size) { - auto Str = Commas? InsertCommas(Sz) : str(Sz); - - if ((!UseMultiplier && Str.size() <= Width) || Width < 5) - { - if (!ShowMultiplier) - return Align(Str, Width); + return UseCommas? GroupDigits(Size) : str(Size); + }; - ReduceWidth(); - return FormatSize(Str, 0); - } - } + size_t UnitIndex = 0; + auto Str = ToStr(FileSize); - ReduceWidth(); - size_t IndexB = 0; - string Str; + const auto SuffixSize = UseCompact? 1u : 2u; + const auto MaxNumberWidth = Width > SuffixSize? Width - SuffixSize : 0; - do + while ((UseUnit && UnitIndex < MinUnit) || (Width && Str.size() > MaxNumberWidth)) { - //Sz=(Sz+Divider2)/Divider64; - Sz = (OldSize=Sz) / Divider64; - - if (OldSize % Divider64 > Divider2) - ++Sz; - - IndexB++; - Str = Commas? InsertCommas(Sz) : str(Sz); + if (unsigned long long SizeInUnits = std::round(FileSize / std::pow(Divider.first, UnitIndex + 1))) + { + ++UnitIndex; + Str = ToStr(SizeInUnits); + } + else + break; } - while ((UseMultiplier && IndexB < Multiplier) || Str.size() > Width); - return FormatSize(Str, IndexB); + return FormatSize(std::move(Str), UnitIndex); } diff --git a/far/strmix.hpp b/far/strmix.hpp index 22a63a5a5a..cc6c8ab4d1 100644 --- a/far/strmix.hpp +++ b/far/strmix.hpp @@ -80,8 +80,7 @@ void PrepareUnitStr(); string FileSizeToStr(unsigned long long Size, int Width = -1, unsigned long long ViewFlags = COLUMN_COMMAS); bool CheckFileSizeStringFormat(const string& FileSizeStr); unsigned long long ConvertFileSizeString(const string& FileSizeStr); -string FormatNumber(const string& Src, int NumDigits=0); -inline string InsertCommas(unsigned long long Value) { return FormatNumber(str(Value)); } +string GroupDigits(unsigned long long Value); inline bool IsWordDiv(const string& WordDiv, wchar_t Chr) { return !Chr || contains(WordDiv, Chr); } diff --git a/far/vbuild.m4 b/far/vbuild.m4 index ec1478f0a5..df35712396 100644 --- a/far/vbuild.m4 +++ b/far/vbuild.m4 @@ -1 +1 @@ -m4_define(BUILD,4962)m4_dnl +m4_define(BUILD,4963)m4_dnl