<div dir="ltr">Hello everyone,<div><br></div><div>I have found the documentation or implementation file:read/2 to be misleading when working with unicode devices in binary mode. I will use file:read_line/1 in the examples below but the issue applies to file:read/2, file:pread/1 and etc.</div>

<div><br></div><div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div>$ echo "héllo" > foo</div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div>$ erl</div>

<div><div>1> {ok, F} = file:open("foo", [binary, unicode]).</div><div>{ok,<0.34.0>}</div><div>2> {ok, Bin} = file:read_line(F).</div><div>{ok,<<"héllo\n">>}</div></div><div>3> <<Bin/binary, 0>>.</div>

<div><<104,233,108,108,111,10, 0>><br></div></blockquote></div><div><div><div><br></div><div>Not the result is not the one desired because I expected a binary containing <<"héllo\n"/utf8>>, or more explicitly, I expected it to contain the bytes <<195, 169>> instead of <<233>>. In other words, I got latin1 as result. With char lists, we would get "héllo\n" but the function will fail for any codepoint > 255.</div>

<div><br></div><div>Note this behaviour also happens if I use file:read_line/1 on any other IO device set to unicode (like standard_io).</div><div><br></div><div>The trouble I have with the function is that it is aimed to byte-oriented but it only really works for latin1 files. If you have a unicode file, the behaviour seems to be broken for binaries, and it only works for a limited range of codepoints when using char lists.</div>

<div><br></div><div>It is interesting to notice those functions use the old {get_line, Prompt} messages which, <a href="http://www.erlang.org/doc/apps/stdlib/io_protocol.html">according to the I/O protocol guide</a>, should not exist beyond R15B (section 1.3). The same section above suggests to translate {get_line, Prompt} to {get_line, latin1, Prompt} which seems to be the root cause of the issues above: those functions were never meant to work with unicode devices.</div>

<div><br></div><div>Unless I am terribly wrong, I can think of some ways to fix those functions:</div><div><br></div><div>1. Keep its dual aspect of returning bytes and/or characters but fix the bug when working with unicode. This means the {get_line, Prompt} should rather translate to {get_line, EncodingOfTheIODevice, Prompt}</div>

<div><br></div><div>2. Make them crash if the encoding of the device is not latin1. This means we translate {get_line, Prompt} to {get_line, latin1, Prompt} only if the encoding of the device is latin1.</div><div><br></div>

<div>3. Make it always work at the byte level, regardless of the encoding of the IO device. This would require assigning new meaning to the {get_line, Prompt} message, so I believe it is not going to happen (although it would be a useful feature in my opinion).</div>

<div><br></div><div>Given that the original IO messages were never meant to work with unicode, maybe 2) is the best way to go here. Both 1) and 2) would require a small amendment to the current I/O protocol advice but I would argue it is necessary to fix the current limitations/bugs when working with unicode.</div>

<div><br></div><div><span style="font-size:13px"><div><span style="font-family:arial,sans-serif;font-size:13px;border-collapse:collapse"><b>José Valim</b></span></div><div><span style="font-family:arial,sans-serif;font-size:13px;border-collapse:collapse"><div>

<span style="font-family:verdana,sans-serif;font-size:x-small"><a href="http://www.plataformatec.com.br/" style="color:rgb(42,93,176)" target="_blank">www.plataformatec.com.br</a></span></div><div><span style="font-family:verdana,sans-serif;font-size:x-small">Skype: jv.ptec</span></div>

<div><span style="font-family:verdana,sans-serif;font-size:x-small">Founder and Lead Developer</span></div></span></div></span></div></div>
</div></div>