Неправильная кодировка при вызове оболочки

9

Я экспериментировал с диаграммой DOT и пытался сделать следующее:

:! dot -Tpng -oFab.png %

Я получил ошибку, потому что мое имя файла имеет специальный символ (" ó" в "Fabricación"):

C:\windows\system32\cmd.exe /c ( dot -Tpng -oFab.png Fabricaci├│n.gv)
Error: dot: can't open Fabricaci├│n.gv
shell returned 2
Hit any key to close this window...

Как видите, специальный символ меняется на " ├│". Это с vim и gVim 7.4 под Win7 и NTFS, поэтому я предполагаю, что имя файла в UTF16 . Я также предполагаю, что при вызове shell / cmd имя файла интерпретируется как некоторая другая кодировка (спасибо Carpetsmoker за указание на то, что по умолчанию используется кодовая страница 850 ).

Как я могу это исправить?

Конечно, я могу просто переименовать файл, но я хотел бы знать, почему это происходит и как это исправить.

Обновление : я только что нашел этот вопрос в superuser.SE (благодаря обратной связи @ ChristianBrabandt ), но, похоже, он тоже не помогает.

Roflo
источник
1
Мне любопытно, если бы вы получили ту же ошибку, используя Vim в командной строке под Cygwin или MobaXterm (переносимые Unix-подобные среды для Windows). Я подозреваю, что нет. Возможно, есть способ исправить это, чтобы Windows cmdприняла имя файла, но установка Unix-подобной среды была бы моей собственной предпочтительной обработкой.
Wildcard
2
Из того, что я прочитал, по умолчанию для cmd.exeне Unicode, а кодовая страница 850 . Также посмотрите этот ответ .
Мартин Турной
Спасибо @Carpetsmoker. Я позволил себе дополнить свой вопрос информацией, которую вы предоставили.
Roflo
Я не совсем уверен, но вы можете настроить опцию 'termencoding'.
Кристиан Брабандт
@ChristianBrabandt Если я не делаю что-то не так, похоже, это не поможет. Я попытался установить tenc в latin1, utf8 и cp850. Никто, кажется, не делает трюк.
Roflo

Ответы:

2

Короткий ответ

Проблема заключается в dot.exe. GraphViz может открывать файлы с путями Unicode в Linux, но не в Windows, если (возможно), если они скомпилированы с Visual Studio 2005.

Исследование

Кодовая страница установлена ​​в 850, Vim кодировка в UTF-8.

введите описание изображения здесь

Это не дает точно такую ​​же ошибку, но, dot.exeкажется, получает неправильный аргумент. Я попытался передать то же имя файла другой программе.

введите описание изображения здесь

И это сработало как раз правильно. Выполнение обоих dot.exeи typeнепосредственно из cmd.exeдает один и тот же результат, поэтому ни Windows Console, ни Vim не являются проблемой. Следующее, что могло вызвать эту ошибку, было dot.exeсамо по себе. Я подозревал, что он просто не знает, как правильно обрабатывать закодированные аргументы Unicode, как это делают даже не все консольные команды:

https://ss64.com/nt/chcp.html

Если вам нужна полная поддержка Unicode, используйте PowerShell. Все еще ОЧЕНЬ ограниченная поддержка Unicode в оболочке CMD, трубопровод, перенаправление, и большинство команд по-прежнему только ANSI. Единственными работающими командами являются DIR, FOR / F и TYPE, это позволяет читать и записывать (UTF-16LE / BOM) файлы и имена файлов, но не намного.

Я искал в Интернете, есть ли поддержка Unicode в GraphViz и обнаружил, что он поддерживает файлы Unicode, но ничего о поддержке Unicode для имен файлов. На трекере ошибок GraphViz и в сообщениях на форуме я не нашел никаких сообщений о том, что кто-то еще заинтересован в чтении файла с именами Unicode. Так что я посмотрел в источнике. Вот как dot.exeвыглядит точка входа:

graphviz-2.40.1\cmd\dot\dot.c

int main(int argc, char **argv)
{
    . . .

/* --------------------> ARGS ARE BEING PASSED HERE */
    gvParseArgs(Gvc, argc, argv);

    . . .

Следуя argvвниз по кроличьей норе:graphviz-2.40.1\lib\common\args.c

int gvParseArgs(GVC_t *gvc, int argc, char** argv)
{
    int rv;
    if ((argc = neato_extra_args(gvc, argc, argv)) < 0)    return (1-argc);
    if ((argc = fdp_extra_args(gvc, argc, argv)) < 0)      return (1-argc);
    if ((argc = memtest_extra_args(gvc, argc, argv)) < 0)  return (1-argc);
    if ((argc = config_extra_args(gvc, argc, argv)) < 0)   return (1-argc);

/* -------------------->  HERE GO ALL NON-FLAG ARTUMENTS */
    if ((rv = dotneato_args_initialize(gvc, argc, argv)))  return rv;

    if (Verbose) gvplugin_write_status(gvc);
    return 0;
}

graphviz-2.40.1\lib\common\input.c

int dotneato_args_initialize(GVC_t * gvc, int argc, char **argv)
{
    for (i = 1; i < argc; i++) {
        if (argv[i] && argv[i][0] == '-') {

            . . .

/* -------------------->  JUST CASUALLY COPYING CHAR POINTERS */
        } else if (argv[i])
            gvc->input_filenames[nfiles++] = argv[i];
    }

И наконец graphviz-2.40.1\lib\common\input.c

graph_t *gvNextInputGraph(GVC_t *gvc)
{
    . . . .

/* -------------------->  OPENING THE FILES FOR READ WITH FOPEN */
    while ((fn = gvc->input_filenames[fidx++]) && !(fp = fopen(fn, "r")))  {

        . . .

    }

Как утверждает MDSN:

Функция fopen открывает файл, указанный в имени файла. _wfopen - широкоформатная версия fopen ; аргументы _wfopen - строки широких символов. _wfopen и fopen ведут себя одинаково иначе. Простое использование _wfopen не влияет на набор кодированных символов, используемый в файловом потоке.

В Visual C ++ 2005 fopen поддерживает файловые потоки Unicode.

К сожалению, единственный вариант - переименовать файл.


источник