Приветствую Вас, Гость
Главная » Статьи » Мои статьи

Русские буквы в именах файлов для dmd 2.067.0

С выходом dmd 2.067.0, ошибка, связанная с невозможностью работы с именами файлов в Windows содержащими в имени и/или полном пути русские буквы (cp1251), сохранилась. Например, следующая программа даёт ошибку во время выполнения:

import std.stdio;
int main(string[] args) {
    string nameFile = `«Ёлки Объект №876».txt`;
    File f = File(nameFile, "w");
    f.writeln("Привет!");
    return 0;
}

Эта ошибка вида:

std.exception.ErrnoException@std\stdio.d(372): Cannot open file `┬л╨Б╨╗╨║╨╕ ╨Ю╨▒
╤К╨╡╨║╤876┬╗.txt' in mode `w' (Invalid argument)

Связано это с тем, что функция _wfopen() из С++ библиотеки (база для std.stdio), в качестве аргументов должна принимать wchar* с указателем на строку имени файла. Однако, в русскоязычной Windows, по умолчанию имя файла кодируется в cp1251 и std.stdio сработает правильно только на первую половину кодовой таблицы, (коды до 128). 

Для исправления данной ошибки придется внести изменения в файл: src\phobos\std\stdio.d 

Ниже представлена часть текста stdio.d с внесенными изменениями (отмечены красным цветом):


private FILE* fopen(in char[] name, in char[] mode = "r") @trusted // nothrow @nogc - mgw отключено из-за fromUtf8toAnsiW
{
 import std.internal.cstring : tempCString;
 version(Windows)
 {
 // MGW 04.10.2014 Исправление русских букв в именах файлов
 // 02.04.2015 8:31:19 Адаптированно для dmd 2.067.0 
 wchar* fromUtf8toAnsiW(in char[] s, uint codePage = 0) @trusted {
 import std.c.windows.windows: WideCharToMultiByte, GetLastError;
 import std.windows.syserror: sysErrorString;
 import std.conv: to;
 char[] result, rez; int readLen; auto ws = std.utf.toUTF16z(s);
 result.length = WideCharToMultiByte(codePage, 0, ws, -1, null, 0, null, null);
 if (result.length) {
 readLen = WideCharToMultiByte(codePage, 0, ws, -1, result.ptr, to!int(result.length), null, null);
 for(int i; i != result.length; i++) { rez ~= result[i]; rez ~= 0; } rez ~= 0; rez ~= 0;
 }
 if (!readLen || readLen != result.length) {
 throw new Exception("Couldn't convert string: " ~ sysErrorString(GetLastError()));
 }
 return cast(wchar*)rez.ptr;
 }

 import std.internal.cstring : tempCStringW;
  // return _wfopen(name.tempCStringW(), mode.tempCStringW()); // mgw отключено из-за fromUtf8toAnsiW
 return _wfopen(fromUtf8toAnsiW(name), mode.tempCStringW());
 }
 else version(Posix)
 {
 /*
 * The new opengroup large file support API is transparently
 * included in the normal C bindings. http://opengroup.org/platform/lfs.html#1.0
 * if _FILE_OFFSET_BITS in druntime is 64, off_t is 64 bit and
 * the normal functions work fine. If not, then large file support
 * probably isn't available. Do not use the old transitional API
 * (the native extern(C) fopen64, http://www.unix.org/version2/whatsnew/lfs20mar.html#3.0)
 */
 import core.sys.posix.stdio : fopen;
 return fopen(name.tempCString(), mode.tempCString());
 }
 else
 {
 return .fopen(name.tempCString(), mode.tempCString());
 }
}

После того, как в файл src\phobos\std\stdio.d внесены изменения, следует заново собрать библиотеку phobos.lib. Для этого перейдите в каталог  src\phobos и выполните команду:

make -f win32.mak

при этом будет собрана новая версия библиотеки phobos. Обратите внимание, что уже должна присутствовать druntime\lib\druntime.lib. 

После сборки новой phobos.lib  положите её в каталог dmd2\windows\lib

Теперь наша тестовая программа (см выше) после сборки с новой phobos.lib будет выполнятся без ошибок.

Категория: Мои статьи | Добавил: mgw (02.04.2015) | Автор: Мохов Геннадий Владимирович E
Просмотров: 631 | Рейтинг: 0.0/0
Всего комментариев: 0
Имя *:
Email *:
Код *: