www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Mistake of opening of a file having a name in cp1251.

reply "MGW" <mgw yandex.ru> writes:
Greetings to all!

I work on Windows with cp1251 and I have a mistake in the program:

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

This mistake of a kind:

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

For correction of this mistake I had to change a file std\stdio.d,
having added in it function fromUtf8toAnsiW (). The piece of an 
source code
of a file std\stdio.d with changes is presented more low.

private FILE* fopen(in char[] name, in char[] mode = "r") 
 trusted // nothrow  nogc - mgw отключено из-за fromUtf8toAnsiW
{
     import std.internal.cstring : tempCString;

     version(Windows)
     {
		// 02.04.2015 8:31:19 repair for 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());
         return _wfopen(fromUtf8toAnsiW(name), 
mode.tempCStringW());
     }
     else version(Posix)
     {
         import core.sys.posix.stdio : fopen;
         return fopen(name.tempCString(), mode.tempCString());
     }
     else
     {
         return .fopen(name.tempCString(), mode.tempCString());
     }
}

With the given correction all works correctly.

Question.
Whether correctly such change from the point of view of 
programming canons on D ?
Apr 02 2015
next sibling parent reply "Danny" <danny.milo+a gmail.com> writes:
According to the documentation 
<https://msdn.microsoft.com/de-de/library/yeby3zcb.aspx>, _wfopen 
already takes a wide-character string, not an ANSI string.

So

          return _wfopen(name.tempCStringW(), mode.tempCStringW());

would be the correct way. All these weird ansi versions are 
Windows 98 era legacy, they aren't commonly used anymore.

Please also try whether your C runtime implements _wfopen 
correctly or otherwise your file name is somehow broken (maybe 
it's on a FAT filesystem etc). For that, please try opening it in 
a C program using _wfopen(_T("filenamehere"), "r");

For comparison, try to create a file with the same name on an 
NTFS filesystem and try opening it in a C program using 
_wfopen(_T("filenamehere"), "r");

Does that work?

Also, what version and flavour (DMD, GDC, LDC) of D do you use?
Apr 03 2015
parent "MGW" <mgw yandex.ru> writes:
The decision, which I have applied using function 
fromUtf8toAnsiW() already works correctly.

I use dmd 2.067.0
Apr 03 2015
prev sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 4/3/15 2:26 AM, MGW wrote:
 Greetings to all!

 I work on Windows with cp1251 and I have a mistake in the program:

 import std.stdio;
 int main (string [] args) {
      string nameFile = `«Ёлки с объектами №876».txt`;
      File f = File (nameFile, "w");
      f.writeln ("Greetings!");
      return 0;
 }
Please see if this will fix your problem, currently open PR: https://github.com/D-Programming-Language/phobos/pull/3138 Seems like the same issue -Steve
Apr 03 2015