Bug 944164 - Move a bunch of file-related stuff onto an os.file object, creating aliases from the old names, r=jorendorff

This commit is contained in:
Steve Fink
2015-05-13 15:16:26 -07:00
parent 0c81a173e9
commit 6d1314c800
4 changed files with 363 additions and 284 deletions

View File

@@ -11,6 +11,7 @@
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#ifdef XP_WIN #ifdef XP_WIN
#include <direct.h>
#include <process.h> #include <process.h>
#include <string.h> #include <string.h>
#else #else
@@ -18,13 +19,262 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
#include "jsapi.h"
// For JSFunctionSpecWithHelp // For JSFunctionSpecWithHelp
#include "jsfriendapi.h" #include "jsfriendapi.h"
#include "jsobj.h"
#ifdef XP_WIN
# include "jswin.h"
#endif
#include "jswrapper.h"
#include "js/Conversions.h" #include "js/Conversions.h"
#include "shell/jsshell.h"
#include "vm/TypedArrayObject.h"
#include "jsobjinlines.h"
#ifdef XP_WIN
# define PATH_MAX (MAX_PATH > _MAX_DIR ? MAX_PATH : _MAX_DIR)
# define getcwd _getcwd
#else
# include <libgen.h>
#endif
using namespace JS; using namespace JS;
namespace js {
namespace shell {
/*
* Resolve a (possibly) relative filename to an absolute path. If
* |scriptRelative| is true, then the result will be relative to the directory
* containing the currently-running script, or the current working directory if
* the currently-running script is "-e" (namely, you're using it from the
* command line.) Otherwise, it will be relative to the current working
* directory.
*/
JSString*
ResolvePath(JSContext* cx, HandleString filenameStr, PathResolutionMode resolveMode)
{
JSAutoByteString filename(cx, filenameStr);
if (!filename)
return nullptr;
const char* pathname = filename.ptr();
if (pathname[0] == '/')
return filenameStr;
#ifdef XP_WIN
// Various forms of absolute paths per http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
// "\..."
if (pathname[0] == '\\')
return filenameStr;
// "C:\..."
if (strlen(pathname) > 3 && isalpha(pathname[0]) && pathname[1] == ':' && pathname[2] == '\\')
return filenameStr;
// "\\..."
if (strlen(pathname) > 2 && pathname[1] == '\\' && pathname[2] == '\\')
return filenameStr;
#endif
/* Get the currently executing script's name. */
JS::AutoFilename scriptFilename;
if (!DescribeScriptedCaller(cx, &scriptFilename))
return nullptr;
if (!scriptFilename.get())
return nullptr;
if (strcmp(scriptFilename.get(), "-e") == 0 || strcmp(scriptFilename.get(), "typein") == 0)
resolveMode = RootRelative;
static char buffer[PATH_MAX+1];
if (resolveMode == ScriptRelative) {
#ifdef XP_WIN
// The docs say it can return EINVAL, but the compiler says it's void
_splitpath(scriptFilename.get(), nullptr, buffer, nullptr, nullptr);
#else
strncpy(buffer, scriptFilename.get(), PATH_MAX+1);
if (buffer[PATH_MAX] != '\0')
return nullptr;
// dirname(buffer) might return buffer, or it might return a
// statically-allocated string
memmove(buffer, dirname(buffer), strlen(buffer) + 1);
#endif
} else {
const char* cwd = getcwd(buffer, PATH_MAX);
if (!cwd)
return nullptr;
}
size_t len = strlen(buffer);
buffer[len] = '/';
strncpy(buffer + len + 1, pathname, sizeof(buffer) - (len+1));
if (buffer[PATH_MAX] != '\0')
return nullptr;
return JS_NewStringCopyZ(cx, buffer);
}
static JSObject*
FileAsTypedArray(JSContext* cx, const char* pathname)
{
FILE* file = fopen(pathname, "rb");
if (!file) {
JS_ReportError(cx, "can't open %s: %s", pathname, strerror(errno));
return nullptr;
}
AutoCloseInputFile autoClose(file);
RootedObject obj(cx);
if (fseek(file, 0, SEEK_END) != 0) {
JS_ReportError(cx, "can't seek end of %s", pathname);
} else {
size_t len = ftell(file);
if (fseek(file, 0, SEEK_SET) != 0) {
JS_ReportError(cx, "can't seek start of %s", pathname);
} else {
obj = JS_NewUint8Array(cx, len);
if (!obj)
return nullptr;
char* buf = (char*) obj->as<js::TypedArrayObject>().viewData();
size_t cc = fread(buf, 1, len, file);
if (cc != len) {
JS_ReportError(cx, "can't read %s: %s", pathname,
(ptrdiff_t(cc) < 0) ? strerror(errno) : "short read");
obj = nullptr;
}
}
}
return obj;
}
static bool
ReadFile(JSContext* cx, unsigned argc, jsval* vp, bool scriptRelative)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() < 1 || args.length() > 2) {
JS_ReportErrorNumber(cx, js::shell::my_GetErrorMessage, nullptr,
args.length() < 1 ? JSSMSG_NOT_ENOUGH_ARGS : JSSMSG_TOO_MANY_ARGS,
"snarf");
return false;
}
if (!args[0].isString() || (args.length() == 2 && !args[1].isString())) {
JS_ReportErrorNumber(cx, js::shell::my_GetErrorMessage, nullptr, JSSMSG_INVALID_ARGS, "snarf");
return false;
}
RootedString givenPath(cx, args[0].toString());
RootedString str(cx, js::shell::ResolvePath(cx, givenPath, scriptRelative ? ScriptRelative : RootRelative));
if (!str)
return false;
JSAutoByteString filename(cx, str);
if (!filename)
return false;
if (args.length() > 1) {
JSString* opt = JS::ToString(cx, args[1]);
if (!opt)
return false;
bool match;
if (!JS_StringEqualsAscii(cx, opt, "binary", &match))
return false;
if (match) {
JSObject* obj;
if (!(obj = FileAsTypedArray(cx, filename.ptr())))
return false;
args.rval().setObject(*obj);
return true;
}
}
if (!(str = FileAsString(cx, filename.ptr())))
return false;
args.rval().setString(str);
return true;
}
static bool
osfile_readFile(JSContext* cx, unsigned argc, jsval* vp)
{
return ReadFile(cx, argc, vp, false);
}
static bool
osfile_readRelativeToScript(JSContext* cx, unsigned argc, jsval* vp)
{
return ReadFile(cx, argc, vp, true);
}
static bool
Redirect(JSContext* cx, FILE* fp, HandleString relFilename)
{
RootedString filename(cx, ResolvePath(cx, relFilename, RootRelative));
if (!filename)
return false;
JSAutoByteString filenameABS(cx, filename);
if (!filenameABS)
return false;
if (freopen(filenameABS.ptr(), "wb", fp) == nullptr) {
JS_ReportError(cx, "cannot redirect to %s: %s", filenameABS.ptr(), strerror(errno));
return false;
}
return true;
}
static bool
osfile_redirect(JSContext* cx, unsigned argc, jsval* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() < 1 || args.length() > 2) {
JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, JSSMSG_INVALID_ARGS, "redirect");
return false;
}
if (args[0].isString()) {
RootedString stdoutPath(cx, args[0].toString());
if (!stdoutPath)
return false;
if (!Redirect(cx, stdout, stdoutPath))
return false;
}
if (args.length() > 1 && args[1].isString()) {
RootedString stderrPath(cx, args[1].toString());
if (!stderrPath)
return false;
if (!Redirect(cx, stderr, stderrPath))
return false;
}
args.rval().setUndefined();
return true;
}
static const JSFunctionSpecWithHelp osfile_functions[] = {
JS_FN_HELP("readFile", osfile_readFile, 1, 0,
"readFile(filename, [\"binary\"])",
" Read filename into returned string. Filename is relative to the current\n"
" working directory."),
JS_FN_HELP("readRelativeToScript", osfile_readRelativeToScript, 1, 0,
"readRelativeToScript(filename, [\"binary\"])",
" Read filename into returned string. Filename is relative to the directory\n"
" containing the current script."),
JS_FN_HELP("redirect", osfile_redirect, 2, 0,
"redirect(stdoutFilename[, stderrFilename])",
" Redirect stdout and/or stderr to the named file. Pass undefined to avoid\n"
" redirecting. Filenames are relative to the current working directory."),
JS_FS_HELP_END
};
static bool static bool
os_getenv(JSContext* cx, unsigned argc, Value* vp) os_getenv(JSContext* cx, unsigned argc, Value* vp)
{ {
@@ -292,14 +542,54 @@ static const JSFunctionSpecWithHelp os_functions[] = {
" The return value is an object containing a 'pid' field, if a process was waitable\n" " The return value is an object containing a 'pid' field, if a process was waitable\n"
" and an 'exitStatus' field if a pid exited."), " and an 'exitStatus' field if a pid exited."),
#endif #endif
JS_FS_HELP_END JS_FS_HELP_END
}; };
bool bool
js::DefineOS(JSContext* cx, HandleObject global) DefineOS(JSContext* cx, HandleObject global, bool fuzzingSafe)
{ {
RootedObject obj(cx, JS_NewPlainObject(cx)); RootedObject obj(cx, JS_NewPlainObject(cx));
return obj && if (!obj || !JS_DefineProperty(cx, global, "os", obj, 0))
JS_DefineFunctionsWithHelp(cx, obj, os_functions) && return false;
JS_DefineProperty(cx, global, "os", obj, 0);
if (!fuzzingSafe) {
if (!JS_DefineFunctionsWithHelp(cx, obj, os_functions))
return false;
}
RootedObject osfile(cx, JS_NewPlainObject(cx));
if (!osfile ||
!JS_DefineFunctionsWithHelp(cx, osfile, osfile_functions) ||
!JS_DefineProperty(cx, obj, "file", osfile, 0))
{
return false;
}
// For backwards compatibility, expose various os.file.* functions as
// direct methods on the global.
RootedValue val(cx);
struct {
const char* src;
const char* dst;
} osfile_exports[] = {
{ "readFile", "read" },
{ "readFile", "snarf" },
{ "readRelativeToScript", "readRelativeToScript" },
{ "redirect", "redirect" }
};
for (auto pair : osfile_exports) {
if (!JS_GetProperty(cx, osfile, pair.src, &val))
return false;
RootedObject function(cx, &val.toObject());
if (!JS_DefineProperty(cx, global, pair.dst, function, 0))
return false;
}
return true;
}
}
} }

View File

@@ -12,11 +12,21 @@
#include "jsapi.h" #include "jsapi.h"
namespace js { namespace js {
namespace shell {
/* Define an os object on the given global object. */ /* Define an os object on the given global object. */
bool bool
DefineOS(JSContext* cx, JS::HandleObject global); DefineOS(JSContext* cx, JS::HandleObject global, bool fuzzingSafe);
enum PathResolutionMode {
RootRelative,
ScriptRelative
};
JSString*
ResolvePath(JSContext* cx, JS::HandleString filenameStr, PathResolutionMode resolveMode);
}
} }
#endif /* shell_OSObject_h */ #endif /* shell_OSObject_h */

View File

@@ -86,14 +86,9 @@
#include "vm/Interpreter-inl.h" #include "vm/Interpreter-inl.h"
#include "vm/Stack-inl.h" #include "vm/Stack-inl.h"
#ifdef XP_WIN
# define PATH_MAX (MAX_PATH > _MAX_DIR ? MAX_PATH : _MAX_DIR)
#else
# include <libgen.h>
#endif
using namespace js; using namespace js;
using namespace js::cli; using namespace js::cli;
using namespace js::shell;
using mozilla::ArrayLength; using mozilla::ArrayLength;
using mozilla::MakeUnique; using mozilla::MakeUnique;
@@ -110,11 +105,6 @@ enum JSShellExitCode {
EXITCODE_TIMEOUT = 6 EXITCODE_TIMEOUT = 6
}; };
enum PathResolutionMode {
RootRelative,
ScriptRelative
};
static size_t gStackChunkSize = 8192; static size_t gStackChunkSize = 8192;
/* /*
@@ -195,14 +185,6 @@ static bool dumpEntrainedVariables = false;
static bool OOM_printAllocationCount = false; static bool OOM_printAllocationCount = false;
#endif #endif
enum JSShellErrNum {
#define MSG_DEF(name, count, exception, format) \
name,
#include "jsshell.msg"
#undef MSG_DEF
JSShellErr_Limit
};
static JSContext* static JSContext*
NewContext(JSRuntime* rt); NewContext(JSRuntime* rt);
@@ -213,12 +195,6 @@ static JSObject*
NewGlobalObject(JSContext* cx, JS::CompartmentOptions& options, NewGlobalObject(JSContext* cx, JS::CompartmentOptions& options,
JSPrincipals* principals); JSPrincipals* principals);
static const JSErrorFormatString*
my_GetErrorMessage(void* userRef, const unsigned errorNumber);
static void
my_ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report);
/* /*
* A toy principals type for the shell. * A toy principals type for the shell.
* *
@@ -565,18 +541,6 @@ ReadEvalPrintLoop(JSContext* cx, FILE* in, FILE* out, bool compileOnly)
fprintf(out, "\n"); fprintf(out, "\n");
} }
class AutoCloseInputFile
{
private:
FILE* f_;
public:
explicit AutoCloseInputFile(FILE* f) : f_(f) {}
~AutoCloseInputFile() {
if (f_ && f_ != stdin)
fclose(f_);
}
};
static void static void
Process(JSContext* cx, const char* filename, bool forceTTY) Process(JSContext* cx, const char* filename, bool forceTTY)
{ {
@@ -631,77 +595,6 @@ Version(JSContext* cx, unsigned argc, jsval* vp)
return true; return true;
} }
/*
* Resolve a (possibly) relative filename to an absolute path. If
* |scriptRelative| is true, then the result will be relative to the directory
* containing the currently-running script, or the current working directory if
* the currently-running script is "-e" (namely, you're using it from the
* command line.) Otherwise, it will be relative to the current working
* directory.
*/
static JSString*
ResolvePath(JSContext* cx, HandleString filenameStr, PathResolutionMode resolveMode)
{
JSAutoByteString filename(cx, filenameStr);
if (!filename)
return nullptr;
const char* pathname = filename.ptr();
if (pathname[0] == '/')
return filenameStr;
#ifdef XP_WIN
// Various forms of absolute paths per http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
// "\..."
if (pathname[0] == '\\')
return filenameStr;
// "C:\..."
if (strlen(pathname) > 3 && isalpha(pathname[0]) && pathname[1] == ':' && pathname[2] == '\\')
return filenameStr;
// "\\..."
if (strlen(pathname) > 2 && pathname[1] == '\\' && pathname[2] == '\\')
return filenameStr;
#endif
/* Get the currently executing script's name. */
JS::AutoFilename scriptFilename;
if (!DescribeScriptedCaller(cx, &scriptFilename))
return nullptr;
if (!scriptFilename.get())
return nullptr;
if (strcmp(scriptFilename.get(), "-e") == 0 || strcmp(scriptFilename.get(), "typein") == 0)
resolveMode = RootRelative;
static char buffer[PATH_MAX+1];
if (resolveMode == ScriptRelative) {
#ifdef XP_WIN
// The docs say it can return EINVAL, but the compiler says it's void
_splitpath(scriptFilename.get(), nullptr, buffer, nullptr, nullptr);
#else
strncpy(buffer, scriptFilename.get(), PATH_MAX+1);
if (buffer[PATH_MAX] != '\0')
return nullptr;
// dirname(buffer) might return buffer, or it might return a
// statically-allocated string
memmove(buffer, dirname(buffer), strlen(buffer) + 1);
#endif
} else {
const char* cwd = getcwd(buffer, PATH_MAX);
if (!cwd)
return nullptr;
}
size_t len = strlen(buffer);
buffer[len] = '/';
strncpy(buffer + len + 1, pathname, sizeof(buffer) - (len+1));
if (buffer[PATH_MAX] != '\0')
return nullptr;
return JS_NewStringCopyZ(cx, buffer);
}
static bool static bool
CreateMappedArrayBuffer(JSContext* cx, unsigned argc, Value* vp) CreateMappedArrayBuffer(JSContext* cx, unsigned argc, Value* vp)
{ {
@@ -1366,8 +1259,8 @@ Evaluate(JSContext* cx, unsigned argc, jsval* vp)
return JS_WrapValue(cx, args.rval()); return JS_WrapValue(cx, args.rval());
} }
static JSString* JSString*
FileAsString(JSContext* cx, const char* pathname) js::shell::FileAsString(JSContext* cx, const char* pathname)
{ {
FILE* file; FILE* file;
RootedString str(cx); RootedString str(cx);
@@ -1412,39 +1305,6 @@ FileAsString(JSContext* cx, const char* pathname)
return str; return str;
} }
static JSObject*
FileAsTypedArray(JSContext* cx, const char* pathname)
{
FILE* file = fopen(pathname, "rb");
if (!file) {
JS_ReportError(cx, "can't open %s: %s", pathname, strerror(errno));
return nullptr;
}
AutoCloseInputFile autoClose(file);
RootedObject obj(cx);
if (fseek(file, 0, SEEK_END) != 0) {
JS_ReportError(cx, "can't seek end of %s", pathname);
} else {
size_t len = ftell(file);
if (fseek(file, 0, SEEK_SET) != 0) {
JS_ReportError(cx, "can't seek start of %s", pathname);
} else {
obj = JS_NewUint8Array(cx, len);
if (!obj)
return nullptr;
char* buf = (char*) obj->as<TypedArrayObject>().viewData();
size_t cc = fread(buf, 1, len, file);
if (cc != len) {
JS_ReportError(cx, "can't read %s: %s", pathname,
(ptrdiff_t(cc) < 0) ? strerror(errno) : "short read");
obj = nullptr;
}
}
}
return obj;
}
/* /*
* Function to run scripts and return compilation + execution time. Semantics * Function to run scripts and return compilation + execution time. Semantics
* are closely modelled after the equivalent function in WebKit, as this is used * are closely modelled after the equivalent function in WebKit, as this is used
@@ -3592,112 +3452,6 @@ struct FreeOnReturn
} }
}; };
static bool
ReadFile(JSContext* cx, unsigned argc, jsval* vp, bool scriptRelative)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() < 1 || args.length() > 2) {
JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr,
args.length() < 1 ? JSSMSG_NOT_ENOUGH_ARGS : JSSMSG_TOO_MANY_ARGS,
"snarf");
return false;
}
if (!args[0].isString() || (args.length() == 2 && !args[1].isString())) {
JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, JSSMSG_INVALID_ARGS, "snarf");
return false;
}
RootedString givenPath(cx, args[0].toString());
RootedString str(cx, ResolvePath(cx, givenPath, scriptRelative ? ScriptRelative : RootRelative));
if (!str)
return false;
JSAutoByteString filename(cx, str);
if (!filename)
return false;
if (args.length() > 1) {
JSString* opt = JS::ToString(cx, args[1]);
if (!opt)
return false;
bool match;
if (!JS_StringEqualsAscii(cx, opt, "binary", &match))
return false;
if (match) {
JSObject* obj;
if (!(obj = FileAsTypedArray(cx, filename.ptr())))
return false;
args.rval().setObject(*obj);
return true;
}
}
if (!(str = FileAsString(cx, filename.ptr())))
return false;
args.rval().setString(str);
return true;
}
static bool
Snarf(JSContext* cx, unsigned argc, jsval* vp)
{
return ReadFile(cx, argc, vp, false);
}
static bool
ReadRelativeToScript(JSContext* cx, unsigned argc, jsval* vp)
{
return ReadFile(cx, argc, vp, true);
}
static bool
redirect(JSContext* cx, FILE* fp, HandleString relFilename)
{
RootedString filename(cx, ResolvePath(cx, relFilename, RootRelative));
if (!filename)
return false;
JSAutoByteString filenameABS(cx, filename);
if (!filenameABS)
return false;
if (freopen(filenameABS.ptr(), "wb", fp) == nullptr) {
JS_ReportError(cx, "cannot redirect to %s: %s", filenameABS.ptr(), strerror(errno));
return false;
}
return true;
}
static bool
RedirectOutput(JSContext* cx, unsigned argc, jsval* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() < 1 || args.length() > 2) {
JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, JSSMSG_INVALID_ARGS, "redirect");
return false;
}
if (args[0].isString()) {
RootedString stdoutPath(cx, args[0].toString());
if (!stdoutPath)
return false;
if (!redirect(cx, stdout, stdoutPath))
return false;
}
if (args.length() > 1 && args[1].isString()) {
RootedString stderrPath(cx, args[1].toString());
if (!stderrPath)
return false;
if (!redirect(cx, stderr, stderrPath))
return false;
}
args.rval().setUndefined();
return true;
}
static int sArgc; static int sArgc;
static char** sArgv; static char** sArgv;
@@ -4512,6 +4266,7 @@ ReflectTrackedOptimizations(JSContext* cx, unsigned argc, Value* vp)
return true; return true;
} }
namespace js {
namespace shell { namespace shell {
class ShellAutoEntryMonitor : JS::dbg::AutoEntryMonitor { class ShellAutoEntryMonitor : JS::dbg::AutoEntryMonitor {
@@ -4583,6 +4338,7 @@ class ShellAutoEntryMonitor : JS::dbg::AutoEntryMonitor {
}; };
} // namespace shell } // namespace shell
} // namespace js
static bool static bool
EntryPoints(JSContext* cx, unsigned argc, Value* vp) EntryPoints(JSContext* cx, unsigned argc, Value* vp)
@@ -4605,7 +4361,7 @@ EntryPoints(JSContext* cx, unsigned argc, Value* vp)
if (!JS_GetProperty(cx, opts, "function", &fun)) if (!JS_GetProperty(cx, opts, "function", &fun))
return false; return false;
if (!fun.isUndefined()) { if (!fun.isUndefined()) {
shell::ShellAutoEntryMonitor sarep(cx); js::shell::ShellAutoEntryMonitor sarep(cx);
if (!Call(cx, UndefinedHandleValue, fun, JS::HandleValueArray::empty(), &dummy)) if (!Call(cx, UndefinedHandleValue, fun, JS::HandleValueArray::empty(), &dummy))
return false; return false;
return sarep.buildResult(cx, args.rval()); return sarep.buildResult(cx, args.rval());
@@ -4635,7 +4391,7 @@ EntryPoints(JSContext* cx, unsigned argc, Value* vp)
if (!JS_GetProperty(cx, opts, "value", &valuev)) if (!JS_GetProperty(cx, opts, "value", &valuev))
return false; return false;
shell::ShellAutoEntryMonitor sarep(cx); js::shell::ShellAutoEntryMonitor sarep(cx);
if (!valuev.isUndefined()) { if (!valuev.isUndefined()) {
if (!JS_SetPropertyById(cx, object, id, valuev)) if (!JS_SetPropertyById(cx, object, id, valuev))
@@ -4656,7 +4412,7 @@ EntryPoints(JSContext* cx, unsigned argc, Value* vp)
if (!JS_GetProperty(cx, opts, "ToString", &v)) if (!JS_GetProperty(cx, opts, "ToString", &v))
return false; return false;
if (!v.isUndefined()) { if (!v.isUndefined()) {
shell::ShellAutoEntryMonitor sarep(cx); js::shell::ShellAutoEntryMonitor sarep(cx);
if (!JS::ToString(cx, v)) if (!JS::ToString(cx, v))
return false; return false;
return sarep.buildResult(cx, args.rval()); return sarep.buildResult(cx, args.rval());
@@ -4671,7 +4427,7 @@ EntryPoints(JSContext* cx, unsigned argc, Value* vp)
if (!JS_GetProperty(cx, opts, "ToNumber", &v)) if (!JS_GetProperty(cx, opts, "ToNumber", &v))
return false; return false;
if (!v.isUndefined()) { if (!v.isUndefined()) {
shell::ShellAutoEntryMonitor sarep(cx); js::shell::ShellAutoEntryMonitor sarep(cx);
if (!JS::ToNumber(cx, v, &dummy)) if (!JS::ToNumber(cx, v, &dummy))
return false; return false;
return sarep.buildResult(cx, args.rval()); return sarep.buildResult(cx, args.rval());
@@ -4699,7 +4455,7 @@ EntryPoints(JSContext* cx, unsigned argc, Value* vp)
options.setIntroductionType("entryPoint eval") options.setIntroductionType("entryPoint eval")
.setFileAndLine("entryPoint eval", 1); .setFileAndLine("entryPoint eval", 1);
shell::ShellAutoEntryMonitor sarep(cx); js::shell::ShellAutoEntryMonitor sarep(cx);
if (!JS::Evaluate(cx, options, chars, length, &dummy)) if (!JS::Evaluate(cx, options, chars, length, &dummy))
return false; return false;
return sarep.buildResult(cx, args.rval()); return sarep.buildResult(cx, args.rval());
@@ -4905,20 +4661,6 @@ static const JSFunctionSpecWithHelp shell_functions[] = {
"sleep(dt)", "sleep(dt)",
" Sleep for dt seconds."), " Sleep for dt seconds."),
JS_FN_HELP("snarf", Snarf, 1, 0,
"snarf(filename, [\"binary\"])",
" Read filename into returned string. Filename is relative to the current\n"
" working directory."),
JS_FN_HELP("read", Snarf, 1, 0,
"read(filename, [\"binary\"])",
" Synonym for snarf."),
JS_FN_HELP("readRelativeToScript", ReadRelativeToScript, 1, 0,
"readRelativeToScript(filename, [\"binary\"])",
" Read filename into returned string. Filename is relative to the directory\n"
" containing the current script."),
JS_FN_HELP("compile", Compile, 1, 0, JS_FN_HELP("compile", Compile, 1, 0,
"compile(code)", "compile(code)",
" Compiles a string to bytecode, potentially throwing."), " Compiles a string to bytecode, potentially throwing."),
@@ -5111,11 +4853,6 @@ static const JSFunctionSpecWithHelp fuzzing_unsafe_functions[] = {
"pc2line(fun[, pc])", "pc2line(fun[, pc])",
" Map PC to line number."), " Map PC to line number."),
JS_FN_HELP("redirect", RedirectOutput, 2, 0,
"redirect(stdoutFilename[, stderrFilename])",
" Redirect stdout and/or stderr to the named file. Pass undefined to avoid\n"
" redirecting. Filenames are relative to the current working directory."),
JS_FN_HELP("nestedShell", NestedShell, 0, 0, JS_FN_HELP("nestedShell", NestedShell, 0, 0,
"nestedShell(shellArgs...)", "nestedShell(shellArgs...)",
" Execute the given code in a new JS shell process, passing this nested shell\n" " Execute the given code in a new JS shell process, passing this nested shell\n"
@@ -5294,8 +5031,8 @@ static const JSErrorFormatString jsShell_ErrorFormatString[JSShellErr_Limit] = {
#undef MSG_DEF #undef MSG_DEF
}; };
static const JSErrorFormatString* const JSErrorFormatString*
my_GetErrorMessage(void* userRef, const unsigned errorNumber) js::shell::my_GetErrorMessage(void* userRef, const unsigned errorNumber)
{ {
if (errorNumber == 0 || errorNumber >= JSShellErr_Limit) if (errorNumber == 0 || errorNumber >= JSShellErr_Limit)
return nullptr; return nullptr;
@@ -5303,8 +5040,8 @@ my_GetErrorMessage(void* userRef, const unsigned errorNumber)
return &jsShell_ErrorFormatString[errorNumber]; return &jsShell_ErrorFormatString[errorNumber];
} }
static void void
my_ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report) js::shell::my_ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report)
{ {
gGotError = PrintError(cx, gErrFile, message, report, reportWarnings); gGotError = PrintError(cx, gErrFile, message, report, reportWarnings);
if (report->exnType != JSEXN_NONE && !JSREPORT_IS_WARNING(report->flags)) { if (report->exnType != JSEXN_NONE && !JSREPORT_IS_WARNING(report->flags)) {
@@ -5889,12 +5626,13 @@ NewGlobalObject(JSContext* cx, JS::CompartmentOptions& options,
if (!fuzzingSafe) { if (!fuzzingSafe) {
if (!JS_DefineFunctionsWithHelp(cx, glob, fuzzing_unsafe_functions)) if (!JS_DefineFunctionsWithHelp(cx, glob, fuzzing_unsafe_functions))
return nullptr; return nullptr;
if (!js::DefineOS(cx, glob))
return nullptr;
if (!DefineConsole(cx, glob)) if (!DefineConsole(cx, glob))
return nullptr; return nullptr;
} }
if (!DefineOS(cx, glob, fuzzingSafe))
return nullptr;
RootedObject performanceObj(cx, JS_NewObject(cx, nullptr)); RootedObject performanceObj(cx, JS_NewObject(cx, nullptr));
if (!performanceObj) if (!performanceObj)
return nullptr; return nullptr;

41
js/src/shell/jsshell.h Normal file
View File

@@ -0,0 +1,41 @@
#ifndef jsshell_js_h
#define jsshell_js_h
#include "jsapi.h"
namespace js {
namespace shell {
enum JSShellErrNum {
#define MSG_DEF(name, count, exception, format) \
name,
#include "jsshell.msg"
#undef MSG_DEF
JSShellErr_Limit
};
const JSErrorFormatString*
my_GetErrorMessage(void* userRef, const unsigned errorNumber);
static void
my_ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report);
JSString*
FileAsString(JSContext* cx, const char* pathname);
class AutoCloseInputFile
{
private:
FILE* f_;
public:
explicit AutoCloseInputFile(FILE* f) : f_(f) {}
~AutoCloseInputFile() {
if (f_ && f_ != stdin)
fclose(f_);
}
};
} /* namespace shell */
} /* namespace js */
#endif