С выходом 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 будет выполнятся без ошибок.
|