Одним из популярных файловых менеджеров в среде Microsoft Windows является Far Manager, принявший эстафету у Norton Commander, созданной еще для DOS. Far Manager позволяет облегчить работу с файловой системой (создание, редактирование, просмотр, копирование, перемещение, поиск, удаление файлов), а также расширяет стандартный функционал (работа с сетью, архивами, резервными копиями и т.д.). Недавно была произведена работа по портированию Far Manager на Linux, и на текущий момент была выпущена альфа-версия. Команда PVS-Studio не могла обойти стороной данное событие и решила проверить качество адаптированного кода.
Picture 24

Немного о Far Manager


Far Manager — консольный файловый менеджер для операционных систем семейства Microsoft Windows, ориентированный на работу с клавиатурой. FAR Manager наследует двухоконную идеологию, стандартную (по умолчанию) расцветку и систему команд (управление с клавиатуры) у известного файлового менеджера Norton Commander и предоставляет удобный интерфейс пользователя для работы с файлами (создания файлов и каталогов, просмотра, редактирования, копирования, переименования, удаления и т.д.).

Рисунок 1 - Far Manager 2 на Windows (нажмите на картинку для увеличения)


Рисунок 1 — Far Manager 2 на Windows (нажмите на картинку для увеличения)

Автор программы — Евгений Рошал. Первая версия была выпущена 10 сентября 1996 года. Последняя версия, к которой приложил руку Рошал, датируется 23 июня 2000 года (версия 1.65). Фактически с того момента разработкой FAR Manager начала заниматься группа «FAR Group». Следующий релиз v1.70 датируется уже 29 марта 2006 года. 13 декабря 2008 года выходит версия 2.0, программа стала бесплатной (open source) и распространяется под модифицированной лицензией BSD. Все версии Far от 1.70 до 2.0 практически не имеют внешних отличий, и не требуют от пользователя каких-либо дополнительных усилий по освоению программы при переходе на новую версию. Начиная с версии 1.80 появилась поддержка Unicode. Последней выпущенной версией считается 3.0 от 4 ноября 2016 года.

10 августа 2016 года была опубликована первая тестовая сборка файлового менеджера Far2l (Linux). На данный момент сборка содержит встроенный работающий терминал, а также плагины Align, AutoWrap, Colorer, DrawLine, Editcase, FarFTP, FarLng, MultiArc, NetBox, SimpleIndent, TmpPanel. Код распространяется под лицензией GPLv2.

Рисунок 2 - Far Manager 2 на Linux (нажмите на картинку для увеличения)


Рисунок 2 — Far Manager 2 на Linux (нажмите на картинку для увеличения)

От слов к делу


После проверки проекта Far2l было получено 1038 предупреждений общего назначения. На следующей диаграмме представлено распределение предупреждений по уровням достоверности:

Рисунок 1 - Распределение предупреждений по уровням достоверности (важности)


Рисунок 1 — Распределение предупреждений по уровням достоверности (важности)

Кратко прокомментируем приведенную диаграмму: было получено 153 предупреждения уровня High, 336 предупреждений уровня Medium, 549 предупреждений уровня Low.

Несмотря на достаточно большое число предупреждений, стоит помнить, что не каждое из них является реальной ошибкой. Просмотрев отчет, содержащий только предупреждения уровня High и Medium, мной было выделено 250 случаев, являющихся скорее всего реальными ошибками.

Если брать уровни High и Medium, то получается, что процент ложных срабатываний составил около 49%. Другими словами, каждое второе предупреждение выявляет дефект в коде.

Теперь определим относительную плотность реальных ошибок, найденных анализатором PVS-Studio. Суммарное количество строк исходного кода (SLOC) — 538675. Следовательно, плотность будет равна 0.464 ошибки на 1000 строк кода. Когда-нибудь мы соберем эти числа и напишем обобщающую статью о качестве кода различных проектов.

Стоит отметить, что данный показатель не демонстрирует общую плотность ошибок по всему проекту — она может быть, как больше (анализатор не сработал на реальной ошибке), так и меньше (анализатор сработал на правильном коде). Как правило, на других проектах мы получаем большую плотность найденных ошибок. Можно сказать, что с точки зрения качества кода портирование прошло успешно. Впрочем, настоятельно рекомендуется исправить найденные ошибки, ведь они далеко небезобидные.

Результаты проверки


Хочу заранее предупредить, что для удобства чтения код будет подвергаться рефакторингу. Также, в статье содержатся далеко не все ошибки, обнаруженные в ходе проверки, а только наиболее интересные из них.

Copy-Paste


Picture 28


Предупреждение анализатора: V501 There are identical sub-expressions 'Key == MCODE_F_BM_GET' to the left and to the right of the '||' operator. macro.cpp 4819

int KeyMacro::GetKey()
{
  ....
  DWORD Key = !MR ? MCODE_OP_EXIT : GetOpCode(MR, Work.ExecLIBPos++);
  ....
  switch (Key)
  {
  ....
  case MCODE_F_BM_POP:
  {
    TVar p1, p2;

    if (Key == MCODE_F_BM_GET)
      VMStack.Pop(p2);

    if (   Key == MCODE_F_BM_GET    // <=
        || Key == MCODE_F_BM_DEL 
        || Key == MCODE_F_BM_GET    // <=
        || Key == MCODE_F_BM_GOTO)
    {
      VMStack.Pop(p1);
    }
    ....
  }
  }
}

Переменную Key дважды сравнили с константой MCODE_F_BM_GET. Вероятно, это опечатка, и Key следовало сравнить ещё c какой-то константой. Анализатор нашел еще 3 похожих места:

  • V501 There are identical sub-expressions '!StrCmpN(CurStr, L"!/", 2)' to the left and to the right of the '||' operator. fnparce.cpp 291
  • V501 There are identical sub-expressions '!StrCmpN(CurStr, L"!=/", 3)' to the left and to the right of the '||' operator. fnparce.cpp 291
  • V501 There are identical sub-expressions 'KEY_RCTRL' to the left and to the right of the '|' operator. keyboard.cpp 1830

Предупреждение анализатора: V581 The conditional expressions of the 'if' operators situated alongside each other are identical. Check lines: 267, 268. APIStringMap.cpp 268

static BOOL WINPORT(GetStringType)( DWORD type,
                                    LPCWSTR src,
                                    INT count,
                                    LPWORD chartype )
{
  ....
  while (count--)
  {
    int c = *src;
    WORD type1, type3 = 0; /* C3_NOTAPPLICABLE */
    ....
    if ((c>=0xFFE0)&&(c<=0xFFE6)) type3 |= C3_FULLWIDTH; // <=
    if ((c>=0xFFE0)&&(c<=0xFFE6)) type3 |= C3_SYMBOL;    // <=
    ....
  }
  ....
}

Видимо, второе условие писалось по принципу Copy-Paste и оно абсолютно идентично первому. Однако, если замысел в этом и заключался, то можно упростить код, убрав второе условие:

....
if ((c>=0xFFE0)&&(c<=0xFFE6)) type3 |= C3_FULLWIDTH | C3_SYMBOL; 
....

Найденная ошибка оказалась далеко не единственной:

  • V581 The conditional expressions of the 'if' operators situated alongside each other are identical. Check lines: 272, 273. APIStringMap.cpp 273
  • V581 The conditional expressions of the 'if' operators situated alongside each other are identical. Check lines: 274, 275. APIStringMap.cpp 275
  • V581 The conditional expressions of the 'if' operators situated alongside each other are identical. Check lines: 6498, 6503. macro.cpp 6503
  • V581 The conditional expressions of the 'if' operators situated alongside each other are identical. Check lines: 1800, 1810. vmenu.cpp 1810
  • V581 The conditional expressions of the 'if' operators situated alongside each other are identical. Check lines: 3353, 3355. wrap.cpp:3355

Предупреждение анализатора: V523 The 'then' statement is equivalent to the 'else' statement. Queque.cpp 358

void FTP::AddToQueque(FAR_FIND_DATA* FileName, 
                      LPCSTR Path, 
                      BOOL Download)
{
  ....
  char *m;
  ....
  if(Download)
    m = strrchr(FileName->cFileName, '/'); // <=
  else
    m = strrchr(FileName->cFileName, '/'); // <=
  ....
}

Подозреваю, что и здесь условие писалось по принципу «Copy-Paste»: вне зависимости от значения Download (TRUE, FALSE), в указатель m будет сохранена позиция последнего вхождения символа '/'.

Неопределенное поведение


Picture 37


Предупреждение анализатора: V567 Undefined behavior. The 'Item[FocusPos]->Selected' variable is modified while being used twice between sequence points. dialog.cpp 3827

int Dialog::Do_ProcessSpace()
{
  ....
  if (Item[FocusPos]->Flags & DIF_3STATE)
    (++Item[FocusPos]->Selected) %= 3;       // <=
  else
    Item[FocusPos]->Selected = !Item[FocusPos]->Selected;
  ....
}

Здесь налицо явное неопределенное поведение: переменную Item[FocusPos]->Selected дважды меняют в одной точке следования (инкремент и деление по модулю 3 с присвоением результата).

Было найдено еще одно место с подобным неопределенным поведением:

  • V567 Undefined behavior. The '::ViewerID' variable is modified while being used twice between sequence points. viewer.cpp 117

Предупреждение анализатора: V610 Undefined behavior. Check the shift operator '<<'. The right operand 'sizeof (wchar_t) * 8' is greater than or equal to the length in bits of the promoted left operand. RegExp.cpp 4467

#define rechar wchar_t
#define RE_CHAR_COUNT (1 << sizeof(rechar) * 8)

int RegExp::Optimize()
{
  ....
  for (op=code; ; op=op->next)
  {
    switch (OP.op)
    {
    ....
    case opType:
    {
      for (int i = 0; i < RE_CHAR_COUNT; i++)    // <=
      {
        if (ISTYPE(i, OP.type))
        {
          first[i]=1;
        }
      }
      
      break;
    }
    }
    ....
  }
  ....
}

Суть ошибки заключается в следующем: в Linux тип wchar_t имеет размер 4 байта. Следовательно, происходит сдвиг знакового int (4 байта) на 32 бита влево. Согласно стандарту C++11, если левый операнд является знаковым положительным числом, сдвиг влево на N бит приведет к неопределенному поведению, если N не меньше, чем количество бит в левом операнде. Корректный код будет выглядеть следующим образом:

#define rechar wchar_t
#define RE_CHAR_COUNT (static_cast<int64_t>(1) << sizeof(rechar) * 8)

int RegExp::Optimize()
{
  ....
  for (int64_t i = 0; i < RE_CHAR_COUNT; i++)
  {
    ....
  }
  ....
}

Были найдены еще несколько мест, ведущие к неопределенному поведению при сдвиге влево:

  • V610 Undefined behavior. Check the shift operator '<<'. The right operand 'sizeof (wchar_t) * 8' is greater than or equal to the length in bits of the promoted left operand. RegExp.cpp 4473
  • V610 Undefined behavior. Check the shift operator '<<'. The right operand 'sizeof (wchar_t) * 8' is greater than or equal to the length in bits of the promoted left operand. RegExp.cpp 4490
  • V610 Undefined behavior. Check the shift operator '<<'. The right operand 'sizeof (wchar_t) * 8' is greater than or equal to the length in bits of the promoted left operand. RegExp.cpp 4537
  • V610 Undefined behavior. Check the shift operator '<<'. The right operand 'sizeof (wchar_t) * 8' is greater than or equal to the length in bits of the promoted left operand. RegExp.cpp 4549
  • V610 Undefined behavior. Check the shift operator '<<'. The right operand 'sizeof (wchar_t) * 8' is greater than or equal to the length in bits of the promoted left operand. RegExp.cpp 4561

Неверная работа с памятью


Picture 41



Начнем новый раздел с небольшой разминки. Предлагаю попытаться найти ошибку самостоятельно (подсказка — она в функции TreeItem::SetTitle).

class UnicodeString
{
  ....
  UnicodeString(const wchar_t *lpwszData) 
  { 
    SetEUS(); 
    Copy(lpwszData); 
  }
  ....
  const wchar_t *CPtr() const { return m_pData->GetData(); }
  operator const wchar_t *() const { return m_pData->GetData(); }
  ....
}

typedef UnicodeString FARString;

struct TreeItem
{
  FARString strName;
  ....
}

TreeItem **ListData;
void TreeList::SetTitle()
{
  ....
  if (GetFocus())
  {
    FARString strTitleDir(L"{");
    const wchar_t *Ptr = ListData 
                         ? ListData[CurFile]->strName
                         : L""; 
    ....
  }
  ....
}

Предупреждение анализатора: V623 Consider inspecting the '?:' operator. A temporary object of the 'UnicodeString' type is being created and subsequently destroyed. Check third operand. treelist.cpp 2093

Неочевидная ошибка, не правда ли? В текущем контексте переменная ListData[CurFile]->strName является объектом класса UnicodeString. В классе UnicodeString перегружен оператор неявного преобразования в тип const wchar_t*. Теперь обратите внимание на тернарный оператор в функции TreeList::SetTitle: второй и третий операнды являются разными типами (UnicodeString и const char[1] соответственно). Подразумевалось, что если первый операнд вернет false, то указатель Ptr будет адресоваться на пустую строку. Поскольку конструктор класса UnicodeString не объявлен как explicit, на самом деле будет создан временный объект, содержащий пустую строку, который неявно приведется к типу const wchar_t*; далее временный объект уничтожится и Ptr будет указывать на невалидные данные. Исправленный код будет выглядеть таким образом:

....
const wchar_t *Ptr = ListData 
                     ? ListData[CurFile]->strName.CPtr()
                     : L"";
....

Следующий код примечателен тем, что на него сработали одновременно две диагностики.

Предупреждения анализатора:

  • V779 Unreachable code detected. It is possible that an error is present. 7z.cpp 203
  • V773 The function was exited without releasing the 't' pointer. A memory leak is possible. 7z.cpp 202

BOOL WINAPI _export SEVENZ_OpenArchive(const char *Name,
                                       int *Type)
{
  Traverser *t = new Traverser(Name);
  if (!t->Valid()) 
  {
    return FALSE;
    delete t;
  }
  
  delete s_selected_traverser;
  s_selected_traverser = t;
  return TRUE;
}

Что же здесь можно обнаружить? Во-первых, действительно, в операторе if имеется недостижимый код: если условие выполняется, то функция возвращает FALSE, завершая свою работу. А из-за недостижимого кода всего-навсего произошла утечка памяти — объект по указателю t не удаляется. Чтобы исправить ошибки, достаточно поменять два оператора местами внутри блока.

Следующий код покажет, как можно ошибиться при определении размера объекта класса (структуры) через указатель.

Предупреждения анализатора:

  • V568 It's odd that 'sizeof()' operator evaluates the size of a pointer to a class, but not the size of the 'PInfo' class object. filelist.cpp 672
  • V568 It's odd that 'sizeof()' operator evaluates the size of a pointer to a class, but not the size of the 'PInfo' class object. filelist.cpp 673

int64_t FileList::VMProcess(int OpCode,
                            void *vParam,
                            int64_t iParam)
{
  switch (OpCode)
  {
  ....
  case MCODE_V_PPANEL_PREFIX:           // PPanel.Prefix
  {
    PluginInfo *PInfo = (PluginInfo *)vParam;
    memset(PInfo, 0, sizeof(PInfo));          // <=
    PInfo->StructSize = sizeof(PInfo);        // <=
    ....
  }
  ....
  }
}

Обе ошибки заключаются в том, что sizeof(PInfo) вместо ожидаемого размера структуры вернет размер указателя (4 или 8 байт). Соответственно, memset заполнит нулями только первые 4 (8) байт структуры, а также в поле PInfo->StructSize запишется размер указателя. Корректный код будет выглядеть следующим образом:

....
PluginInfo *PInfo = (PluginInfo*)vParam;
memset(PInfo, 0, sizeof(*PInfo));
PInfo->StructSize = sizeof(*PInfo);
....

Анализатор обнаружил еще пару похожих мест:

  • V568 It's odd that 'sizeof()' operator evaluates the size of a pointer to a class, but not the size of the 'HistoryItem' class object. history.cpp 594
  • V568 It's odd that 'sizeof()' operator evaluates the size of a pointer to a class, but not the size of the 'handle' class object. plugins.cpp 682

Странные условия


Picture 39


И снова предлагаю небольшую разминку — попробуйте самостоятельно найти ошибку в следующей части кода:

int FTP::ProcessKey(int Key, unsigned int ControlState)
{
  ....
  if(   !ShowHosts 
     && (ControlState == 0 || ControlState == PKF_SHIFT) 
     && Key == VK_F6)
  {
    FTP *ftp = OtherPlugin(this);
    int  rc;

    if(   !ftp 
       && ControlState == 0 
       && Key == VK_F6)
    {
      return FALSE;
    }
    ....
  }
  ....
}

Предупреждение анализатора: V560 A part of conditional expression is always true: Key == 0x75. Key.cpp 493

Обратите внимание на внешнее и внутреннее условия: в них Key сравнивается с константой VK_F6. Если поток управления достигает внутреннего условия, то переменная Key гарантировано будет равна VK_F6 и вторая проверка этой переменной будет лишней. В упрощённом виде второе условие будет выглядеть так:

....
if(   !ftp 
   && ControlState == 0)
{
  return FALSE;
}
....

Анализатор предупреждает об этой ошибке и о некоторых подобных:

  • V560 A part of conditional expression is always true: !cps. DString.cpp 47
  • V560 A part of conditional expression is always true: !ShowHosts. FGet.cpp 139
  • V560 A part of conditional expression is always false: !wsz. cnDownload.cpp 190
  • V560 A part of conditional expression is always true: !UserReject. extract.cpp 485
  • And 8 additional diagnostic messages.

Предупреждение анализатора: V503 This is a nonsensical comparison: pointer <= 0. fstd_exSCPY.cpp 8

char *WINAPI StrCpy(char *dest, LPCSTR src, int dest_sz)
{
  if(dest <= 0)   // <=
    return NULL;
  ....
}

Данный код содержит бессмысленное сравнение указателя с отрицательным числом (указатели не работают с областями памяти с отрицательными адресами). Исправленный код может выглядеть следующим образом:

....
if(dest == nullptr)
  return NULL;
....

Предупреждение анализатора: V584 The FADC_ALLDISKS value is present on both sides of the '==' operator. The expression is incorrect or it can be simplified. findfile.cpp 3116

enum FINDASKDLGCOMBO
{
  FADC_ALLDISKS,
  FADC_ALLBUTNET,
  ....
};

FindFiles::FindFiles()
{
  
  ....
  if (   FADC_ALLDISKS + SearchMode == FADC_ALLDISKS     // <=
      || FADC_ALLDISKS + SearchMode == FADC_ALLBUTNET)
  {
    ....
  }
  ....
}

Анализатор обнаружил подозрительное первое подусловие. Исходя из перечисления FINDASKDLGCOMBO, константа FADC_ALLDISKS равна 0, FADC_ALLBUTNET равна 1. Если подставить численные значения констант в условные выражение, то получим следующее:

if (   0 + SearchMode == 0
    || 0 + SearchMode == 1)
{
  ....
}

Исходя из кода выше, все условие можно упростить:

if (   SearchMode == FADC_ALLDISKS
    || SearchMode == FADC_ALLBUTNET)
{
  ....
}

Некорректная работа с форматной строкой


Picture 40


Предупреждение анализатора: V576 Incorrect format. Consider checking the fourth actual argument of the 'swprintf' function. The char type argument is expected. FarEditor.cpp 827

void FarEditor::showOutliner(Outliner *outliner)
{
  ....
  wchar_t cls = 
    Character::toLowerCase((*region)[region->indexOf(':') + 1]);
  
  si += swprintf(menuItem+si, 255-si, L"%c ", cls); // <=
  ....
}

Вероятно, это ошибка портирования. Проблема заключается в том, что в Visual C++ в функциях вывода широких строк нестандартно интерпретируются спецификаторы в форматной строке: %c ожидает широкий символ (wide char, wchar_t). В Linux дела обстоят иначе: в соответствии со стандартом по спецификатору %c будет ожидаться многобайтовый символ (multibyte symbol, char). Корректный код будет выглядеть следующим образом:

si += swprintf(menuItem+si, 255-si, L"%lc ", cls);

Предупреждение анализатора: V576 Incorrect format. Consider checking the fourth actual argument of the 'swprintf' function. The pointer to string of char type symbols is expected. cmddata.cpp 257

void CommandData::ReadConfig()
{
  ....
  wchar Cmd[16];
  ....
  wchar SwName[16+ASIZE(Cmd)];
  swprintf(SwName,ASIZE(SwName), L"switches_%s=", Cmd);  // <=
  ....
}

Похожая ситуация: форматная строка содержит спецификатор %s, следовательно, ожидается многобайтовая строка (char*). Однако, следующим параметром была передана широкая строка (wchar_t*). Корректный код будет выглядеть следующим образом:

swprintf(SwName,ASIZE(SwName), L"switches_%ls=", Cmd);

Анализатор также предупреждает и о двух других неверных способах передачи параметров в соответствии с форматной строкой:

  • V576 Incorrect format. Consider checking the third actual argument of the 'fprintf' function. The char type argument is expected. vtansi.cpp 1033
  • V576 Incorrect format. Consider checking the third actual argument of the 'fprintf' function. The char type argument is expected. vtansi.cpp 1038

Выводы


Что можно сказать про порт Far на Linux? Да, ошибок было найдено достаточно, однако не стоит забывать, что проект находится в состоянии альфа-версии и продолжает развиваться. Применяя методологию статического анализа кода, ошибки можно найти еще на раннем этапе и не допустить их в репозиторий. Стоит отметить, что все преимущества статического анализа будут проявляться только при его регулярном использовании (в крайнем случае — во время «ночных» сборок).

От своего лица я предлагаю оценить пользу статического анализа с помощью PVS-Studio: продукт доступен для Microsoft Windows и deb/rpm-based дистрибутивов Linux, позволяя быстро и регулярно проверять Ваш проект. Также, если Вы студент, индивидуальный разработчик, или участвуете в разработке открытого некоммерческого проекта, то предлагается возможность бесплатного использования PVS-Studio.

В этом ознакомительном видео Вы можете узнать, как установить PVS-Studio для Linux и быстро проверить свой проект (на примере Far Manager):



Также, если Вы знаете интересный проект, который следовало бы проверить, то Вы можете предложить его нам на GitHub. Подробнее в статье: "Предложи проект для проверки анализатором PVS-Studio: теперь и на GitHub".



Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Phillip Khandeliants. Porting is a Delicate Matter: Checking Far Manager under Linux

Прочитали статью и есть вопрос?
Часто к нашим статьям задают одни и те же вопросы. Ответы на них мы собрали здесь: Ответы на вопросы читателей статей про PVS-Studio, версия 2015. Пожалуйста, ознакомьтесь со списком.
Поделиться с друзьями
-->

Комментарии (55)


  1. kotov666
    16.02.2017 11:19
    -2

    MC не ?!


    1. Andrey2008
      16.02.2017 11:22
      +1

      1. kotov666
        16.02.2017 11:29

        Я имел ввиду, зачем портировать Far если уже есть Midnight Commander.


        1. Andrey2008
          16.02.2017 11:31
          +5

          Ой, это не к нам. Мы просто разместили объяву проверили проект.


        1. kvaps
          16.02.2017 11:40
          +10

          image


          1. ogustbiller
            16.02.2017 12:27

            рекомендую file commander линуксовый, хоть и не совсем фришный как замену мц в линуксе.


            1. mao_zvezdun
              16.02.2017 13:53

              У меня не получилось запустить его в полноэкранной консоли, в ubuntu mate пробовал. Может где-то настраивается, но не нашел.


              1. ogustbiller
                16.02.2017 15:37

                С такой необходимостью не сталкивался. Да, возможно, что не выйдет. :(


        1. AndreyDmitriev
          16.02.2017 11:46
          +8

          Ну вот я из тех, кто пользуется Far под Windows и MC под Linux. Мне было бы удобно, если бы Far был портирован под Linux, тем более что большую часть времени я провожу как раз в Windows, и пересаживаясь на Linux, бывает на автомате жму там горячие клавиши, которые в MC отличаются. Теоретически Far под wine можно запустить, но надо будет на досуге и Far2l попробовать.


          1. mihmig
            16.02.2017 16:06
            +5

            Да, чёрт возьми, если я в Far-е просмотрел файл по F3 то нажимаю (что логично) Esc чтобы вернуться в консоль. Какого хрена mc мне гадит в командную строку?

            +в Far-е горячие клавиши работают вне зависимости от текущей раскладки (по крайней мере для ENG+RUS). Вот что бывает, когда программист пользуется программой, которую пишет.


            1. rbobot
              16.02.2017 17:25
              +1

              Скорее, что бывает, когда у программиста на машине более одной локали.


            1. win32asm
              17.02.2017 05:40
              +2

              Это не совсем MC, это терминал.
              По спецификации VT102 должны быть непечатные символы для разнообразной фигни типа управления терминалом, цветами, положением на экране и всё такое — http://man7.org/linux/man-pages/man4/console_codes.4.html
              MC не пытается перехватывать эти коды и работает на том, что до него докатывается. 8-)

              Но Far/win + MC/lin это, конечно, боль.
              Меня вот только ConEmu + mintty как-то спасают. 8-)


              1. mihmig
                17.02.2017 09:20
                +3

                Блин, ка графическую подсистему менять каждые 2 года (это я про ubuntu) — так нормально — «развиваем опенсорс». А как тащить десятилетиями VT102 — так это обратная совместимость?

                А можно подробнее — как Вы используете ConEmu + mintty?


                1. win32asm
                  17.02.2017 10:20

                  конема управляет табами, в табах фар и mintty
                  mintty запускает баш от вингита, и в принципе служит только для запуска ssh — а все локальные задачи выполняются в фаре.


        1. lieff
          16.02.2017 11:54
          +5

          Использую и то и другое ежедневно, mc в основном на маке т.к. пока там с фаром проблемы. Вот пара примеров:

          В фаре я просто набираю «ff» и высвечивается уже фильтрованная история всех моих запусков ffmpeg. В mc надо alt-h и искать самому в полной истории, где может быть много мусора.

          Заливка по sftp, mc: F9-L-SFTP Link, появляется окно выбора, по дефолту там последний, чтобы выбрать другой, надо мышкой нажать дропдавн бокс хистори, табом на нем не фокусируется (или alt-h). Причем т.к. это хистори — редактировать этот список нельзя.
          Far: Alt-F1->Netbox появляется панель со всеми сохраненными сетевыми путями, Enter и все (под линь он правда еще полностью не портирован, так что это сравнение с виндовой версией).

          Проблемы которые вставляет консоль из-за чего надо нажимать esc-esc как я понял тоже принципиально не решаются, не ломая какие то другие приложения, можно только закостылить. В консоли по ssh это можно терпеть, но для локального файл менеджера — это можно решить и будет работать везде из коробки без настроек, что и было сделано. Сейчас фар позиционируется именно как локальный ФМ, но консоль и веб версии позже тоже присоединятся.

          Так же не маловажная вещь — палгины. У фара есть мощный и гибкий API плагинов.


          1. Zardos
            16.02.2017 14:33

            Вот насчет Alt-F1 — не уверен, что удастся перенести.


            1. lieff
              16.02.2017 14:50
              +2

              Ну оно уже работает, я просто отключил эти горячие клавиши в настройках, на маке это требуется и для нормальной работы в mc тоже. Вот если кто-то к ним уже привык — тут да, придется или переучиваться или в фаре комбинацию поменять.


              1. monah_tuk
                21.02.2017 06:14

                Может завезёте "липкий" Alt? К примеру комбинацией Alt+A. Для чего: в современных DE да и привычки ради Alt+F1, Alt+F2 делают уже полезную работу. Начнём с того, что вы выше сказали о теоретической возможности портироваться на консоль, а там это будет отрабатывать как переключение виртуальных терминалов. В иксах Alt+F2 часто используется для вызова диалого запуска программ, всяких gmrun или krunner и компания.


                Смысл: нажимаем Alt+A, отпускаем, но Far начинает считать, что клавиша Alt зажата и не отпущена. И следующая клавиша даст комбинацию с Alt.


                Таким образом Alt+F1 можно будет вызвать: Alt+A, F1.


                Для завершения режима: Esc, или повторный Alt+A.


          1. win32asm
            17.02.2017 11:48

            5 копеек про дропдаун в mc: по нему можно гонять через CTRL-Up/Down
            Но не везде.
            в SLES12 (mc 4.8.11), RH7 (4.8.7), RH6 (4.7.0.2), ubuntu14 (mc 4.8.11) — можно, SLES11 (mc 4.6.2) — не получается. 8-)
            По виду эту фичу где-то в mc 4.7 прикрутили.


            1. lieff
              17.02.2017 11:52

              Да, я знаю это, но чтобы высветить весь список — надо или мышкой нажать или alt-h.


              1. win32asm
                17.02.2017 11:59

                О, а про alt-h я не знал (или, скорее, забыл). Спасибо. 8-)


        1. Faramant
          16.02.2017 12:22
          +1

          Еще одна попытка затащить виндузятников на Linux :-)


          1. Jogger
            16.02.2017 18:46

            Нет, скорее попытка сделать жизнь виндузятников, которые иногда пользуются линуксом, комфортнее.


        1. mistergrim
          16.02.2017 13:15
          +3

          Вот именно поэтому.


    1. akubintsev
      16.02.2017 13:29

      Разве его не забросили в прошлом году?


  1. Jogger
    16.02.2017 16:55
    +1

    Можно немного оффтопа?
    Вот с недавних пор PVS-Studio можно использовать бесплатно для личных проектов. Меня интересует такой аспект (описанная ситуация — гипотетическая, я пока не использовал анализатор) — вот допустим я форкнул какой-то проект на гитхаб. И для своего форка пользуюсь PVS-Studio, соответственно добавил требуемые комментарии. Всё у меня хорошо и замечательно. А потом я допустим нахожу баг в коде исходного проекта. Могу ли я отправить владельцу исходного кода пул-реквест? Ну, то есть, технически меня никто не остановит, но не будет ли по факту это нарушением вашей лицензии — ведь владелец-то никаких комментариев в код не добавлял. Или тут как у матроскина — корова государственная, а всё что она даёт — молоко или телят — это уже наше?


    1. EvgeniyRyzhkov
      16.02.2017 16:56
      +7

      Можете отправить пул-реквест. Если еще и в комментарии к нему укажете PVS-Studio — вообще хорошо.


  1. olekl
    16.02.2017 17:08

    А не планировали ввести упрощенные пороговые критерии по результатам проверки? Типа «Очень хорошо», «Так себе» и «Говнокод»?


    1. SvyatoslavMC
      16.02.2017 17:16
      +3

      Критерии и так понятны, вот чего действительно не хватает:

      «Пометить как ложное срабатывание говнокод»


      1. Andrey2008
        16.02.2017 17:56
        +5

        Кстати, у нас же есть в контекстном меню «Add TODO comment selected messages». Можно в настройках указать, что-бы вставлялось: "// Это говнокод, переделывай!". :)


  1. heximal
    16.02.2017 19:19
    +5

    Люблю фар, не могу без него жить) Первое, что я поставил на мак, когда в 2010 году мигрировал на него с винды — это фар. По сей день им пользуюсь. Один нюанс — работает он под wine'ом.
    Новость о том, что кто-то взялся за портирование под *nix взволновала.
    Если удастся добиться стабильной работы, сложно ли будет сделать то же самое для macOS?


    1. lieff
      16.02.2017 19:37
      +4

      Он уже компилится под macos, осталось только решить проблему скорости рендера текста, но уже можно пользоваться.


      1. heximal
        16.02.2017 22:59
        +1

        это прекрасная новость.
        как можно подписаться на вас, чтобы следить за развитием событий?


        1. lieff
          16.02.2017 23:16
          +1

          Ну можете на гитхабе, и на автора и на меня. Конкретно по скорости рендера обсуждение сейчас идет в этом issue.


      1. monah_tuk
        20.02.2017 15:15

        Если бы он ещё консольным был… Кстати, раз уж он на Linux, стоит прикрутить прокрутку буффера в консоли, как это сделано в ConEmu+Far Plugin. Про F3/F4 вкурсе. Не удобно.


  1. Mingun
    16.02.2017 21:10
    +1

    А никто не подскажет, почему под Linux стали портировать вторую версию, ведь давно уже третья в ходу?


    1. lieff
      16.02.2017 21:30

      Вот тут от автора пояснения http://forum.farmanager.com/viewtopic.php?p=139821#p139821


      1. Jogger
        17.02.2017 03:20

        Мда. Судя по тому что там написано, этот порт теряет главное (лично для меня) достоинство far'а — консольность. То есть работать это будет только под иксами, а значит (опять же, лично для меня) полностью бесполезно. Или это устаревший пост и сейчас что-то поменялось?


        1. lieff
          17.02.2017 10:50

          Поменялось, консольная версия планируется.


          1. monah_tuk
            20.02.2017 15:16

            Ох, удачи вам на этом пути. Искренне! Буду ждать, как минимум, из-за "Рисование линий" :-D


  1. wOvAN
    16.02.2017 21:29
    +2

    Far для меня это всегда первая устанавливаемая программа, если теперь это заработает под Linux, то препядствий для перехода на Линукс станет на 1 меньше, спасибо вам за вклад.


    1. wOvAN
      16.02.2017 21:42

      Почитав дальше понял что это не тру консольная версия а графическая, что конечно огорчило.


      1. lieff
        16.02.2017 22:08

        Консольная версия будет.


  1. snuk182
    16.02.2017 23:10
    +2

    Раз пошла такая пьянка, попрошу проверить еще один файловый менеджер, благодаря которому переход на Линукс существенно облегчился.
    http://doublecmd.sourceforge.net/


    1. selivanov_pavel
      17.02.2017 01:10
      +1

      Он написан на FreePascal/Lazarus, с целью совместимости с плагинами к Total Commander под Windows. PVS-Studio его проверить не сможет


      1. lobzanoff
        20.02.2017 08:42

        А вот жаль, что для Паскаля нет хорошего анализатора. Причина понятна, но все же печально.


        1. lany
          26.02.2017 17:22

          Программисты на Паскале смотрят на ряд диагностик PVS-Studio с ухмылкой: то что в C/C++ требует статических анализаторов, в Паскале просто не пропускается компилятором. К примеру, случайное присваивание в условии, отсутствие скобок в низкоприоритетной логической операции и другое.


          1. Jogger
            26.02.2017 21:10

            Ну, логические ошибки типа условий которые всегда верны, либо сравнения с самим собой, либо несколько одинаковых условий подряд — компилятор не отловит. Так что статический анализатор таки полезен и для паскаля. Но да, возможностей выстрелить себе в ногу там таки поменьше.


  1. nikakoy131
    17.02.2017 08:55

    А ffmpeg не проверяли? Очень хороший инструмент, интересно насколько хорош изнутри


    1. SvyatoslavMC
      17.02.2017 12:07
      -1

      Не проверяли, но предложение уже принял: add FFmpeg #18


  1. Denkenmacht
    17.02.2017 08:55
    -3

    Ну когда уже портируют Тотал Комманднер под *nix? Он же Фару (при всем уважении) во многом фору даст. На андроиде уже есть.
    Пусть бы даже денег стоил сколько-то.


    1. Faramant
      17.02.2017 14:25

      Far на Андроиде тоже есть. А самая главная фича Far'а — это его консольность.


    1. mistergrim
      17.02.2017 15:54
      +1

      Total Commander под Windows и под Android — ну, имхо, это как десктопный фотошоп и мобильный.


    1. Jogger
      18.02.2017 05:03
      +3

      Давайте называть вещи своими именами. Не «во многом фору даст» а «лично мне больше нравится». Потому что, например, для меня — тотал коммандер неудобен и практически бесполезен, а фаром при этом пользуюсь активно.
      А если вам так нужен аналог тотала на линуксе — то вон выше ссылку давали на double commander — это бесплатный аналг тотала, совместимый с плагинами от него (чем и интересен, имхо).


  1. zbestr
    18.02.2017 11:29
    +3

    Уряяяя!!! Far на Line!
    Под Ubuntu За пару минут завелся:

    sudo apt-get install gawk m4 libglib2.0-dev libwxgtk3.0-dev cmake g++
    git clone https://github.com/elfmz/far2l
    mkdir build
    cd build
    cmake -DCMAKE_BUILD_TYPE=Release ../far2l
    sudo make -j4
    ls
    cd install/
    ls
    ./far2l
    

    ВАУ!