Commit b9c5232c authored by erik.corry@gmail.com's avatar erik.corry@gmail.com

Add os.chdir and os.setenv to d8. Move system() to os.system().

Protect os.chdir, os.setenv, os.system against string conversion
failures.  Add comment about the issue to include/v8.h.
Review URL: http://codereview.chromium.org/57005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1644 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent d3ee29a7
...@@ -883,7 +883,10 @@ class V8EXPORT String : public Primitive { ...@@ -883,7 +883,10 @@ class V8EXPORT String : public Primitive {
/** /**
* Converts an object to a utf8-encoded character array. Useful if * Converts an object to a utf8-encoded character array. Useful if
* you want to print the object. * you want to print the object. If conversion to a string fails
* (eg. due to an exception in the toString() method of the object)
* then the length() method returns 0 and the * operator returns
* NULL.
*/ */
class V8EXPORT Utf8Value { class V8EXPORT Utf8Value {
public: public:
...@@ -903,6 +906,9 @@ class V8EXPORT String : public Primitive { ...@@ -903,6 +906,9 @@ class V8EXPORT String : public Primitive {
/** /**
* Converts an object to an ascii string. * Converts an object to an ascii string.
* Useful if you want to print the object. * Useful if you want to print the object.
* If conversion to a string fails (eg. due to an exception in the toString()
* method of the object) then the length() method returns 0 and the * operator
* returns NULL.
*/ */
class V8EXPORT AsciiValue { class V8EXPORT AsciiValue {
public: public:
...@@ -921,6 +927,9 @@ class V8EXPORT String : public Primitive { ...@@ -921,6 +927,9 @@ class V8EXPORT String : public Primitive {
/** /**
* Converts an object to a two-byte string. * Converts an object to a two-byte string.
* If conversion to a string fails (eg. due to an exception in the toString()
* method of the object) then the length() method returns 0 and the * operator
* returns NULL.
*/ */
class V8EXPORT Value { class V8EXPORT Value {
public: public:
......
...@@ -184,9 +184,18 @@ class OpenFDCloser { ...@@ -184,9 +184,18 @@ class OpenFDCloser {
// scope. // scope.
class ExecArgs { class ExecArgs {
public: public:
ExecArgs(Handle<Value> arg0, Handle<Array> command_args) { ExecArgs() {
exec_args_[0] = NULL;
}
bool Init(Handle<Value> arg0, Handle<Array> command_args) {
String::Utf8Value prog(arg0); String::Utf8Value prog(arg0);
int len = prog.length() + 1; if (*prog == NULL) {
const char* message =
"os.system(): String conversion of program name failed";
ThrowException(String::New(message));
return false;
}
int len = prog.length() + 3;
char* c_arg = new char[len]; char* c_arg = new char[len];
snprintf(c_arg, len, "%s", *prog); snprintf(c_arg, len, "%s", *prog);
exec_args_[0] = c_arg; exec_args_[0] = c_arg;
...@@ -194,12 +203,20 @@ class ExecArgs { ...@@ -194,12 +203,20 @@ class ExecArgs {
for (unsigned j = 0; j < command_args->Length(); i++, j++) { for (unsigned j = 0; j < command_args->Length(); i++, j++) {
Handle<Value> arg(command_args->Get(Integer::New(j))); Handle<Value> arg(command_args->Get(Integer::New(j)));
String::Utf8Value utf8_arg(arg); String::Utf8Value utf8_arg(arg);
if (*utf8_arg == NULL) {
exec_args_[i] = NULL; // Consistent state for destructor.
const char* message =
"os.system(): String conversion of argument failed.";
ThrowException(String::New(message));
return false;
}
int len = utf8_arg.length() + 1; int len = utf8_arg.length() + 1;
char* c_arg = new char[len]; char* c_arg = new char[len];
snprintf(c_arg, len, "%s", *utf8_arg); snprintf(c_arg, len, "%s", *utf8_arg);
exec_args_[i] = c_arg; exec_args_[i] = c_arg;
} }
exec_args_[i] = NULL; exec_args_[i] = NULL;
return true;
} }
~ExecArgs() { ~ExecArgs() {
for (unsigned i = 0; i < kMaxArgs; i++) { for (unsigned i = 0; i < kMaxArgs; i++) {
...@@ -454,7 +471,10 @@ Handle<Value> Shell::System(const Arguments& args) { ...@@ -454,7 +471,10 @@ Handle<Value> Shell::System(const Arguments& args) {
struct timeval start_time; struct timeval start_time;
gettimeofday(&start_time, NULL); gettimeofday(&start_time, NULL);
ExecArgs exec_args(args[0], command_args); ExecArgs exec_args;
if (!exec_args.Init(args[0], command_args)) {
return v8::Undefined();
}
int exec_error_fds[2]; int exec_error_fds[2];
int stdout_fds[2]; int stdout_fds[2];
...@@ -501,4 +521,21 @@ Handle<Value> Shell::System(const Arguments& args) { ...@@ -501,4 +521,21 @@ Handle<Value> Shell::System(const Arguments& args) {
} }
Handle<Value> Shell::ChangeDirectory(const Arguments& args) {
if (args.Length() != 1) {
const char* message = "chdir() takes one argument";
return ThrowException(String::New(message));
}
String::Utf8Value directory(args[0]);
if (*directory == NULL) {
const char* message = "os.chdir(): String conversion of argument failed.";
return ThrowException(String::New(message));
}
if (chdir(*directory) != 0) {
return ThrowException(String::New(strerror(errno)));
}
return v8::Undefined();
}
} // namespace v8 } // namespace v8
...@@ -42,4 +42,11 @@ Handle<Value> Shell::System(const Arguments& args) { ...@@ -42,4 +42,11 @@ Handle<Value> Shell::System(const Arguments& args) {
} }
Handle<Value> Shell::ChangeDirectory(const Arguments& args) {
Handle<String> error_message =
String::New("chdir() is not yet supported on your OS");
return ThrowException(error_message);
}
} // namespace v8 } // namespace v8
...@@ -163,6 +163,28 @@ Handle<Value> Shell::Print(const Arguments& args) { ...@@ -163,6 +163,28 @@ Handle<Value> Shell::Print(const Arguments& args) {
} }
Handle<Value> Shell::SetEnvironment(const Arguments& args) {
if (args.Length() != 2) {
const char* message = "setenv() takes two arguments";
return ThrowException(String::New(message));
}
String::Utf8Value var(args[0]);
String::Utf8Value value(args[1]);
if (*var == NULL) {
const char* message =
"os.setenv(): String conversion of variable name failed.";
return ThrowException(String::New(message));
}
if (*value == NULL) {
const char* message =
"os.setenv(): String conversion of variable contents failed.";
return ThrowException(String::New(message));
}
setenv(*var, *value, 1);
return v8::Undefined();
}
Handle<Value> Shell::Load(const Arguments& args) { Handle<Value> Shell::Load(const Arguments& args) {
for (int i = 0; i < args.Length(); i++) { for (int i = 0; i < args.Length(); i++) {
HandleScope handle_scope; HandleScope handle_scope;
...@@ -342,7 +364,12 @@ void Shell::Initialize() { ...@@ -342,7 +364,12 @@ void Shell::Initialize() {
global_template->Set(String::New("load"), FunctionTemplate::New(Load)); global_template->Set(String::New("load"), FunctionTemplate::New(Load));
global_template->Set(String::New("quit"), FunctionTemplate::New(Quit)); global_template->Set(String::New("quit"), FunctionTemplate::New(Quit));
global_template->Set(String::New("version"), FunctionTemplate::New(Version)); global_template->Set(String::New("version"), FunctionTemplate::New(Version));
global_template->Set(String::New("system"), FunctionTemplate::New(System));
Handle<ObjectTemplate> os_templ = ObjectTemplate::New();
os_templ->Set(String::New("system"), FunctionTemplate::New(System));
os_templ->Set(String::New("chdir"), FunctionTemplate::New(ChangeDirectory));
os_templ->Set(String::New("setenv"), FunctionTemplate::New(SetEnvironment));
global_template->Set(String::New("os"), os_templ);
utility_context_ = Context::New(NULL, global_template); utility_context_ = Context::New(NULL, global_template);
utility_context_->SetSecurityToken(Undefined()); utility_context_->SetSecurityToken(Undefined());
......
...@@ -130,9 +130,12 @@ class Shell: public i::AllStatic { ...@@ -130,9 +130,12 @@ class Shell: public i::AllStatic {
static Handle<Value> Quit(const Arguments& args); static Handle<Value> Quit(const Arguments& args);
static Handle<Value> Version(const Arguments& args); static Handle<Value> Version(const Arguments& args);
static Handle<Value> Load(const Arguments& args); static Handle<Value> Load(const Arguments& args);
// system("program_name", ["arg1", "arg2", ...], timeout1, timeout2) will run // The OS object on the global object contains methods for performing
// the command, passing the arguments to the program. The standard output of // operating system calls:
// the program will be picked up and returned as a multiline string. If //
// os.system("program_name", ["arg1", "arg2", ...], timeout1, timeout2) will
// run the command, passing the arguments to the program. The standard output
// of the program will be picked up and returned as a multiline string. If
// timeout1 is present then it should be a number. -1 indicates no timeout // timeout1 is present then it should be a number. -1 indicates no timeout
// and a positive number is used as a timeout in milliseconds that limits the // and a positive number is used as a timeout in milliseconds that limits the
// time spent waiting between receiving output characters from the program. // time spent waiting between receiving output characters from the program.
...@@ -140,7 +143,16 @@ class Shell: public i::AllStatic { ...@@ -140,7 +143,16 @@ class Shell: public i::AllStatic {
// milliseconds on the total running time of the program. Exceptions are // milliseconds on the total running time of the program. Exceptions are
// thrown on timeouts or other errors or if the exit status of the program // thrown on timeouts or other errors or if the exit status of the program
// indicates an error. // indicates an error.
//
// os.chdir(dir) changes directory to the given directory. Throws an
// exception/ on error.
//
// os.setenv(variable, value) sets an environment variable. Repeated calls to
// this method leak memory due to the API of setenv in the standard C library.
static Handle<Value> OSObject(const Arguments& args);
static Handle<Value> System(const Arguments& args); static Handle<Value> System(const Arguments& args);
static Handle<Value> ChangeDirectory(const Arguments& args);
static Handle<Value> SetEnvironment(const Arguments& args);
static Handle<Context> utility_context() { return utility_context_; } static Handle<Context> utility_context() { return utility_context_; }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment