--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -399,88 +399,30 @@ SkipUTF8BOM(FILE* file)
ungetc(ch3, file);
if (ch2 != EOF)
ungetc(ch2, file);
if (ch1 != EOF)
ungetc(ch1, file);
}
static void
-Process(JSContext *cx, JSObject *obj_, const char *filename, bool forceTTY)
+ReadEvalPrintLoop(JSContext *cx, JSObject *obj, FILE *file, bool compileOnly)
{
bool ok, hitEOF;
RootedScript script(cx);
RootedValue result(cx);
RootedString str(cx);
char *buffer;
size_t size;
jschar *uc_buffer;
size_t uc_len;
int lineno;
int startline;
- FILE *file;
uint32_t oldopts;
- RootedObject obj(cx, obj_);
-
- if (forceTTY || !filename || strcmp(filename, "-") == 0) {
- file = stdin;
- } else {
- file = fopen(filename, "r");
- if (!file) {
- JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
- JSSMSG_CANT_OPEN, filename, strerror(errno));
- gExitCode = EXITCODE_FILE_NOT_FOUND;
- return;
- }
- }
-
- SetContextOptions(cx);
-
- if (!forceTTY && !isatty(fileno(file)))
- {
- SkipUTF8BOM(file);
-
- /*
- * It's not interactive - just execute it. Support the UNIX #! shell
- * hack, and gobble the first line if it starts with '#'.
- */
- int ch = fgetc(file);
- if (ch == '#') {
- while((ch = fgetc(file)) != EOF) {
- if (ch == '\n' || ch == '\r')
- break;
- }
- }
- ungetc(ch, file);
-
- int64_t t1 = PRMJ_Now();
- oldopts = JS_GetOptions(cx);
- gGotError = false;
- JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL);
- CompileOptions options(cx);
- options.setUTF8(true)
- .setFileAndLine(filename, 1);
- script = JS::Compile(cx, obj, options, file);
- JS_SetOptions(cx, oldopts);
- JS_ASSERT_IF(!script, gGotError);
- if (script && !compileOnly) {
- if (!JS_ExecuteScript(cx, obj, script, NULL)) {
- if (!gQuitting && !gTimedOut)
- gExitCode = EXITCODE_RUNTIME_ERROR;
- }
- int64_t t2 = PRMJ_Now() - t1;
- if (printTiming)
- printf("runtime = %.3f ms\n", double(t2) / PRMJ_USEC_PER_MSEC);
- }
-
- goto cleanup;
- }
-
- /* It's an interactive filehandle; drop into read-eval-print loop. */
lineno = 1;
hitEOF = false;
buffer = NULL;
size = 0; /* assign here to avoid warnings */
do {
/*
* Accumulate lines until we get a 'compilable unit' - one that either
* generates an error (before running out of source) or that compiles
@@ -494,17 +436,17 @@ Process(JSContext *cx, JSObject *obj_, c
gTimedOut = false;
errno = 0;
char *line = GetLine(file, startline == lineno ? "js> " : "");
if (!line) {
if (errno) {
JS_ReportError(cx, strerror(errno));
free(buffer);
- goto cleanup;
+ return;
}
hitEOF = true;
break;
}
if (!buffer) {
buffer = line;
len = strlen(buffer);
size = len + 1;
@@ -515,17 +457,17 @@ Process(JSContext *cx, JSObject *obj_, c
size_t newlen = strlen(line) + (len ? len + 1 : 0);
if (newlen + 1 > size) {
size = newlen + 1 > size * 2 ? newlen + 1 : size * 2;
char *newBuf = (char *) realloc(buffer, size);
if (!newBuf) {
free(buffer);
free(line);
JS_ReportOutOfMemory(cx);
- goto cleanup;
+ return;
}
buffer = newBuf;
}
char *current = buffer + len;
if (startline != lineno)
*current++ = '\n';
strcpy(current, line);
len = newlen;
@@ -580,20 +522,92 @@ Process(JSContext *cx, JSObject *obj_, c
}
}
*buffer = '\0';
free(uc_buffer);
} while (!hitEOF && !gQuitting);
free(buffer);
fprintf(gOutFile, "\n");
-cleanup:
- if (file != stdin)
- fclose(file);
- return;
+}
+
+class AutoCloseInputFile
+{
+ private:
+ FILE *f_;
+ public:
+ explicit AutoCloseInputFile(FILE *f) : f_(f) {}
+ ~AutoCloseInputFile() {
+ if (f_ && f_ != stdin)
+ fclose(f_);
+ }
+};
+
+static void
+Process(JSContext *cx, JSObject *obj_, const char *filename, bool forceTTY)
+{
+ RootedObject obj(cx, obj_);
+
+ FILE *file;
+ if (forceTTY || !filename || strcmp(filename, "-") == 0) {
+ file = stdin;
+ } else {
+ file = fopen(filename, "r");
+ if (!file) {
+ JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL,
+ JSSMSG_CANT_OPEN, filename, strerror(errno));
+ gExitCode = EXITCODE_FILE_NOT_FOUND;
+ return;
+ }
+ }
+ AutoCloseInputFile autoClose(file);
+
+ SetContextOptions(cx);
+
+ if (!forceTTY && !isatty(fileno(file))) {
+ SkipUTF8BOM(file);
+
+ /*
+ * It's not interactive - just execute it. Support the UNIX #! shell
+ * hack, and gobble the first line if it starts with '#'.
+ */
+ int ch = fgetc(file);
+ if (ch == '#') {
+ while ((ch = fgetc(file)) != EOF) {
+ if (ch == '\n' || ch == '\r')
+ break;
+ }
+ }
+ ungetc(ch, file);
+
+ int64_t t1 = PRMJ_Now();
+ uint32_t oldopts = JS_GetOptions(cx);
+ gGotError = false;
+ JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL);
+ CompileOptions options(cx);
+ options.setUTF8(true)
+ .setFileAndLine(filename, 1);
+
+ RootedScript script(cx);
+ script = JS::Compile(cx, obj, options, file);
+ JS_SetOptions(cx, oldopts);
+ JS_ASSERT_IF(!script, gGotError);
+ if (script && !compileOnly) {
+ if (!JS_ExecuteScript(cx, obj, script, NULL)) {
+ if (!gQuitting && !gTimedOut)
+ gExitCode = EXITCODE_RUNTIME_ERROR;
+ }
+ int64_t t2 = PRMJ_Now() - t1;
+ if (printTiming)
+ printf("runtime = %.3f ms\n", double(t2) / PRMJ_USEC_PER_MSEC);
+ }
+ } else {
+ // It's an interactive filehandle; drop into read-eval-print loop.
+ ReadEvalPrintLoop(cx, obj, file, compileOnly);
+ }
}
/*
* JSContext option name to flag map. The option names are in alphabetical
* order for better reporting.
*/
static const struct JSOption {
const char *name;