| // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| #include "bin/dartutils.h" |
| #include "bin/io_buffer.h" |
| #include "bin/process.h" |
| #include "bin/socket.h" |
| |
| #include "include/dart_api.h" |
| |
| |
| namespace dart { |
| namespace bin { |
| |
| static const int kProcessIdNativeField = 0; |
| |
| int Process::global_exit_code_ = 0; |
| dart::Mutex Process::global_exit_code_mutex_; |
| |
| // Extract an array of C strings from a list of Dart strings. |
| static char** ExtractCStringList(Dart_Handle strings, |
| Dart_Handle status_handle, |
| const char* error_msg, |
| intptr_t* length) { |
| static const intptr_t kMaxArgumentListLength = 1024 * 1024; |
| ASSERT(Dart_IsList(strings)); |
| intptr_t len = 0; |
| Dart_Handle result = Dart_ListLength(strings, &len); |
| if (Dart_IsError(result)) { |
| Dart_PropagateError(result); |
| } |
| // Protect against user-defined list implementations that can have |
| // arbitrary length. |
| if (len < 0 || len > kMaxArgumentListLength) { |
| DartUtils::SetIntegerField(status_handle, "_errorCode", 0); |
| DartUtils::SetStringField( |
| status_handle, "_errorMessage", "Max argument list length exceeded"); |
| return NULL; |
| } |
| *length = len; |
| char** string_args = new char*[len]; |
| for (int i = 0; i < len; i++) { |
| Dart_Handle arg = Dart_ListGetAt(strings, i); |
| if (Dart_IsError(arg)) { |
| delete[] string_args; |
| Dart_PropagateError(arg); |
| } |
| if (!Dart_IsString(arg)) { |
| DartUtils::SetIntegerField(status_handle, "_errorCode", 0); |
| DartUtils::SetStringField( |
| status_handle, "_errorMessage", error_msg); |
| delete[] string_args; |
| return NULL; |
| } |
| string_args[i] = const_cast<char *>(DartUtils::GetStringValue(arg)); |
| } |
| return string_args; |
| } |
| |
| void FUNCTION_NAME(Process_Start)(Dart_NativeArguments args) { |
| Dart_EnterScope(); |
| Dart_Handle process = Dart_GetNativeArgument(args, 0); |
| intptr_t process_stdin; |
| intptr_t process_stdout; |
| intptr_t process_stderr; |
| intptr_t exit_event; |
| Dart_Handle status_handle = Dart_GetNativeArgument(args, 9); |
| Dart_Handle path_handle = Dart_GetNativeArgument(args, 1); |
| // The Dart code verifies that the path implements the String |
| // interface. However, only builtin Strings are handled by |
| // GetStringValue. |
| if (!Dart_IsString(path_handle)) { |
| DartUtils::SetIntegerField(status_handle, "_errorCode", 0); |
| DartUtils::SetStringField( |
| status_handle, "_errorMessage", "Path must be a builtin string"); |
| Dart_SetReturnValue(args, Dart_NewBoolean(false)); |
| Dart_ExitScope(); |
| return; |
| } |
| const char* path = DartUtils::GetStringValue(path_handle); |
| Dart_Handle arguments = Dart_GetNativeArgument(args, 2); |
| intptr_t args_length = 0; |
| char** string_args = |
| ExtractCStringList(arguments, |
| status_handle, |
| "Arguments must be builtin strings", |
| &args_length); |
| if (string_args == NULL) { |
| Dart_SetReturnValue(args, Dart_NewBoolean(false)); |
| Dart_ExitScope(); |
| return; |
| } |
| Dart_Handle working_directory_handle = Dart_GetNativeArgument(args, 3); |
| // Defaults to the current working directoy. |
| const char* working_directory = NULL; |
| if (Dart_IsString(working_directory_handle)) { |
| working_directory = DartUtils::GetStringValue(working_directory_handle); |
| } else if (!Dart_IsNull(working_directory_handle)) { |
| delete[] string_args; |
| DartUtils::SetIntegerField(status_handle, "_errorCode", 0); |
| DartUtils::SetStringField( |
| status_handle, "_errorMessage", |
| "WorkingDirectory must be a builtin string"); |
| Dart_SetReturnValue(args, Dart_NewBoolean(false)); |
| Dart_ExitScope(); |
| return; |
| } |
| Dart_Handle environment = Dart_GetNativeArgument(args, 4); |
| intptr_t environment_length = 0; |
| char** string_environment = NULL; |
| if (!Dart_IsNull(environment)) { |
| string_environment = |
| ExtractCStringList(environment, |
| status_handle, |
| "Environment values must be builtin strings", |
| &environment_length); |
| if (string_environment == NULL) { |
| delete[] string_args; |
| Dart_SetReturnValue(args, Dart_NewBoolean(false)); |
| Dart_ExitScope(); |
| return; |
| } |
| } |
| Dart_Handle stdin_handle = Dart_GetNativeArgument(args, 5); |
| Dart_Handle stdout_handle = Dart_GetNativeArgument(args, 6); |
| Dart_Handle stderr_handle = Dart_GetNativeArgument(args, 7); |
| Dart_Handle exit_handle = Dart_GetNativeArgument(args, 8); |
| intptr_t pid = -1; |
| char* os_error_message = NULL; |
| |
| int error_code = Process::Start(path, |
| string_args, |
| args_length, |
| working_directory, |
| string_environment, |
| environment_length, |
| &process_stdout, |
| &process_stdin, |
| &process_stderr, |
| &pid, |
| &exit_event, |
| &os_error_message); |
| if (error_code == 0) { |
| Socket::SetSocketIdNativeField(stdin_handle, process_stdin); |
| Socket::SetSocketIdNativeField(stdout_handle, process_stdout); |
| Socket::SetSocketIdNativeField(stderr_handle, process_stderr); |
| Socket::SetSocketIdNativeField(exit_handle, exit_event); |
| Process::SetProcessIdNativeField(process, pid); |
| } else { |
| DartUtils::SetIntegerField( |
| status_handle, "_errorCode", error_code); |
| DartUtils::SetStringField( |
| status_handle, "_errorMessage", os_error_message); |
| } |
| delete[] string_args; |
| delete[] string_environment; |
| free(os_error_message); |
| Dart_SetReturnValue(args, Dart_NewBoolean(error_code == 0)); |
| Dart_ExitScope(); |
| } |
| |
| |
| void FUNCTION_NAME(Process_Kill)(Dart_NativeArguments args) { |
| Dart_EnterScope(); |
| Dart_Handle process = Dart_GetNativeArgument(args, 1); |
| intptr_t pid = -1; |
| Process::GetProcessIdNativeField(process, &pid); |
| int signal = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2)); |
| bool success = Process::Kill(pid, signal); |
| Dart_SetReturnValue(args, Dart_NewBoolean(success)); |
| Dart_ExitScope(); |
| } |
| |
| |
| void FUNCTION_NAME(Process_Exit)(Dart_NativeArguments args) { |
| Dart_EnterScope(); |
| int64_t status = 0; |
| // Ignore result if passing invalid argument and just exit 0. |
| DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 0), &status); |
| Dart_ExitScope(); |
| exit(static_cast<int>(status)); |
| } |
| |
| |
| void FUNCTION_NAME(Process_SetExitCode)(Dart_NativeArguments args) { |
| Dart_EnterScope(); |
| int64_t status = 0; |
| // Ignore result if passing invalid argument and just set exit code to 0. |
| DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 0), &status); |
| Process::SetGlobalExitCode(status); |
| Dart_ExitScope(); |
| } |
| |
| |
| void FUNCTION_NAME(Process_Sleep)(Dart_NativeArguments args) { |
| Dart_EnterScope(); |
| int64_t milliseconds = 0; |
| // Ignore result if passing invalid argument and just set exit code to 0. |
| DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 0), &milliseconds); |
| TimerUtils::Sleep(milliseconds); |
| Dart_ExitScope(); |
| } |
| |
| |
| void FUNCTION_NAME(Process_Pid)(Dart_NativeArguments args) { |
| Dart_EnterScope(); |
| // Ignore result if passing invalid argument and just set exit code to 0. |
| intptr_t pid = -1; |
| Dart_Handle process = Dart_GetNativeArgument(args, 0); |
| if (Dart_IsNull(process)) { |
| pid = Process::CurrentProcessId(); |
| } else { |
| Process::GetProcessIdNativeField(process, &pid); |
| } |
| Dart_SetReturnValue(args, Dart_NewInteger(pid)); |
| Dart_ExitScope(); |
| } |
| |
| |
| Dart_Handle Process::GetProcessIdNativeField(Dart_Handle process, |
| intptr_t* pid) { |
| return Dart_GetNativeInstanceField(process, kProcessIdNativeField, pid); |
| } |
| |
| |
| Dart_Handle Process::SetProcessIdNativeField(Dart_Handle process, |
| intptr_t pid) { |
| return Dart_SetNativeInstanceField(process, kProcessIdNativeField, pid); |
| } |
| |
| |
| void FUNCTION_NAME(SystemEncodingToString)(Dart_NativeArguments args) { |
| Dart_EnterScope(); |
| Dart_Handle bytes = Dart_GetNativeArgument(args, 0); |
| intptr_t bytes_length = 0; |
| Dart_Handle result = Dart_ListLength(bytes, &bytes_length); |
| if (Dart_IsError(result)) Dart_PropagateError(result); |
| uint8_t* buffer = new uint8_t[bytes_length + 1]; |
| result = Dart_ListGetAsBytes(bytes, 0, buffer, bytes_length); |
| buffer[bytes_length] = '\0'; |
| if (Dart_IsError(result)) { |
| delete[] buffer; |
| Dart_PropagateError(result); |
| } |
| char* str = |
| StringUtils::ConsoleStringToUtf8(reinterpret_cast<char*>(buffer)); |
| Dart_SetReturnValue(args, DartUtils::NewString(str)); |
| if (str != reinterpret_cast<char*>(buffer)) free(str); |
| Dart_ExitScope(); |
| } |
| |
| |
| void FUNCTION_NAME(StringToSystemEncoding)(Dart_NativeArguments args) { |
| Dart_EnterScope(); |
| Dart_Handle str = Dart_GetNativeArgument(args, 0); |
| const char* utf8 = DartUtils::GetStringValue(str); |
| const char* system_string = StringUtils::Utf8ToConsoleString(utf8); |
| int external_length = strlen(system_string); |
| uint8_t* buffer = NULL; |
| Dart_Handle external_array = IOBuffer::Allocate(external_length, &buffer); |
| memmove(buffer, system_string, external_length); |
| if (utf8 != system_string) free(const_cast<char*>(system_string)); |
| Dart_SetReturnValue(args, external_array); |
| Dart_ExitScope(); |
| } |
| |
| } // namespace bin |
| } // namespace dart |