aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Gudmundsson <[email protected]>2013-05-15 15:16:50 +0200
committerDan Gudmundsson <[email protected]>2013-06-03 12:58:45 +0200
commit0057676c3ebfd603658631088c977219ba2b0cc6 (patch)
tree879f3125ed8b569e25eefc02c3b5c5a201d824a3
parent892fb14882ef356c90eda8aa02ca43c3db8b53da (diff)
downloadotp-0057676c3ebfd603658631088c977219ba2b0cc6.tar.gz
otp-0057676c3ebfd603658631088c977219ba2b0cc6.tar.bz2
otp-0057676c3ebfd603658631088c977219ba2b0cc6.zip
kernel: Handle unicode in os:cmd
Allow unicode strings in os:cmd and try to convert the result bytes to unicode list. Also test it.
-rw-r--r--lib/kernel/src/os.erl37
-rw-r--r--lib/kernel/test/os_SUITE.erl26
-rw-r--r--lib/kernel/test/os_SUITE_data/my_echo.c28
3 files changed, 69 insertions, 22 deletions
diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl
index 86f2f94f1f..c92bb463c1 100644
--- a/lib/kernel/src/os.erl
+++ b/lib/kernel/src/os.erl
@@ -183,20 +183,25 @@ extensions() ->
Command :: atom() | io_lib:chars().
cmd(Cmd) ->
validate(Cmd),
- case type() of
- {unix, _} ->
- unix_cmd(Cmd);
- {win32, Wtype} ->
- Command0 = case {os:getenv("COMSPEC"),Wtype} of
- {false,windows} -> lists:concat(["command.com /c", Cmd]);
- {false,_} -> lists:concat(["cmd /c", Cmd]);
- {Cspec,_} -> lists:concat([Cspec," /c",Cmd])
- end,
- %% open_port/2 awaits string() in Command, but io_lib:chars() can be
- %% deep lists according to io_lib module description.
- Command = lists:flatten(Command0),
- Port = open_port({spawn, Command}, [stream, in, eof, hide]),
- get_data(Port, [])
+ Bytes = case type() of
+ {unix, _} ->
+ unix_cmd(Cmd);
+ {win32, Wtype} ->
+ Command0 = case {os:getenv("COMSPEC"),Wtype} of
+ {false,windows} -> lists:concat(["command.com /c", Cmd]);
+ {false,_} -> lists:concat(["cmd /c", Cmd]);
+ {Cspec,_} -> lists:concat([Cspec," /c",Cmd])
+ end,
+ %% open_port/2 awaits string() in Command, but io_lib:chars() can be
+ %% deep lists according to io_lib module description.
+ Command = lists:flatten(Command0),
+ Port = open_port({spawn, Command}, [stream, in, eof, hide]),
+ get_data(Port, [])
+ end,
+ String = unicode:characters_to_list(list_to_binary(Bytes)),
+ if %% Convert to unicode list if possible otherwise return bytes
+ is_list(String) -> String;
+ true -> Bytes
end.
unix_cmd(Cmd) ->
@@ -337,7 +342,7 @@ mk_cmd(Cmd) when is_atom(Cmd) -> % backward comp.
mk_cmd(Cmd) ->
%% We insert a new line after the command, in case the command
%% contains a comment character.
- io_lib:format("(~ts\n) </dev/null; echo \"\^D\"\n", [Cmd]).
+ [$(, unicode:characters_to_binary(Cmd), "\n) </dev/null; echo \"\^D\"\n"].
validate(Atom) when is_atom(Atom) ->
@@ -345,7 +350,7 @@ validate(Atom) when is_atom(Atom) ->
validate(List) when is_list(List) ->
validate1(List).
-validate1([C|Rest]) when is_integer(C), 0 =< C, C < 256 ->
+validate1([C|Rest]) when is_integer(C) ->
validate1(Rest);
validate1([List|Rest]) when is_list(List) ->
validate1(List),
diff --git a/lib/kernel/test/os_SUITE.erl b/lib/kernel/test/os_SUITE.erl
index 73ed704ae3..9b474c4cdf 100644
--- a/lib/kernel/test/os_SUITE.erl
+++ b/lib/kernel/test/os_SUITE.erl
@@ -20,7 +20,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
--export([space_in_cwd/1, quoting/1, space_in_name/1, bad_command/1,
+-export([space_in_cwd/1, quoting/1, cmd_unicode/1, space_in_name/1, bad_command/1,
find_executable/1, unix_comment_in_command/1, deep_list_command/1, evil/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -28,9 +28,8 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [space_in_cwd, quoting, space_in_name, bad_command,
- find_executable, unix_comment_in_command, deep_list_command,
- evil].
+ [space_in_cwd, quoting, cmd_unicode, space_in_name, bad_command,
+ find_executable, unix_comment_in_command, deep_list_command, evil].
groups() ->
[].
@@ -95,6 +94,21 @@ quoting(Config) when is_list(Config) ->
?line [] = receive_all(),
ok.
+
+cmd_unicode(doc) -> "Test that unicode arguments work.";
+cmd_unicode(suite) -> [];
+cmd_unicode(Config) when is_list(Config) ->
+ ?line DataDir = ?config(data_dir, Config),
+ ?line Echo = filename:join(DataDir, "my_echo"),
+
+ ?line comp("one", os:cmd(Echo ++ " one")),
+ ?line comp("one::two", os:cmd(Echo ++ " one two")),
+ ?line comp("åäö::ϼΩ", os:cmd(Echo ++ " åäö " ++ [1020, 937])),
+ ?t:sleep(5),
+ ?line [] = receive_all(),
+ ok.
+
+
space_in_name(doc) ->
"Test that program with a space in its name can be executed.";
space_in_name(suite) -> [];
@@ -302,8 +316,8 @@ comp(Expected, Got) ->
Expected ->
ok;
Other ->
- ok = io:format("Expected: ~s\n", [Expected]),
- ok = io:format("Got: ~s\n", [Other]),
+ ok = io:format("Expected: ~ts\n", [Expected]),
+ ok = io:format("Got: ~ts\n", [Other]),
test_server:fail()
end.
diff --git a/lib/kernel/test/os_SUITE_data/my_echo.c b/lib/kernel/test/os_SUITE_data/my_echo.c
index 2127511dd1..712c828bb5 100644
--- a/lib/kernel/test/os_SUITE_data/my_echo.c
+++ b/lib/kernel/test/os_SUITE_data/my_echo.c
@@ -1,3 +1,30 @@
+#ifdef __WIN32__
+#include <windows.h>
+
+int wmain(int argc, wchar_t **argv)
+{
+ char* sep = "";
+ int len;
+
+ /*
+ * Echo all arguments separated with '::', so that we can check that
+ * quotes are interpreted correctly.
+ */
+
+ while (argc-- > 1) {
+ char *utf8;
+ len = WideCharToMultiByte(CP_UTF8, 0, argv[1], -1, NULL, 0, NULL, NULL);
+ utf8 = malloc(len*sizeof(char));
+ WideCharToMultiByte(CP_UTF8, 0, argv++[1], -1, utf8, len, NULL, NULL);
+ printf("%s%s", sep, utf8);
+ free(utf8);
+ sep = "::";
+ }
+ putchar('\n');
+ return 0;
+}
+#else
+
#include <stdio.h>
int
@@ -17,3 +44,4 @@ main(int argc, char** argv)
putchar('\n');
return 0;
}
+#endif