--- a/js/src/xpconnect/shell/xpcshell.cpp
+++ b/js/src/xpconnect/shell/xpcshell.cpp
@@ -97,24 +97,56 @@
/***************************************************************************/
#define EXITCODE_RUNTIME_ERROR 3
#define EXITCODE_FILE_NOT_FOUND 4
FILE *gOutFile = NULL;
FILE *gErrFile = NULL;
+FILE *gInFile = NULL;
int gExitCode = 0;
JSBool gQuitting = JS_FALSE;
static JSBool reportWarnings = JS_TRUE;
static JSBool compileOnly = JS_FALSE;
JSPrincipals *gJSPrincipals = nsnull;
+static JSBool
+GetLine(JSContext *cx, char *bufp, FILE *file, const char *prompt) {
+#ifdef EDITLINE
+ /*
+ * Use readline only if file is stdin, because there's no way to specify
+ * another handle. Are other filehandles interactive?
+ */
+ if (file == stdin) {
+ char *linep = readline(prompt);
+ if (!linep)
+ return JS_FALSE;
+ if (*linep)
+ add_history(linep);
+ strcpy(bufp, linep);
+ JS_free(cx, linep);
+ bufp += strlen(bufp);
+ *bufp++ = '\n';
+ *bufp = '\0';
+ } else
+#endif
+ {
+ char line[256];
+ fprintf(gOutFile, prompt);
+ fflush(gOutFile);
+ if (!fgets(line, sizeof line, file))
+ return JS_FALSE;
+ strcpy(bufp, line);
+ }
+ return JS_TRUE;
+}
+
static void
my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
{
int i, j, k, n;
char *prefix = NULL, *tmp;
const char *ctmp;
JSStackFrame * fp = nsnull;
nsCOMPtr<nsIXPConnect> xpc;
@@ -200,16 +232,58 @@ my_ErrorReporter(JSContext *cx, const ch
fputs("^\n", gErrFile);
out:
if (!JSREPORT_IS_WARNING(report->flags))
gExitCode = EXITCODE_RUNTIME_ERROR;
JS_free(cx, prefix);
}
static JSBool
+ReadLine(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ // While 4096 might be quite arbitrary, this is something to be fixed in
+ // bug 105707. It is also the same limit as in ProcessFile.
+ char buf[4096];
+ JSString *str;
+
+ /* If a prompt was specified, construct the string */
+ if (argc > 0) {
+ str = JS_ValueToString(cx, argv[0]);
+ if (!str)
+ return JS_FALSE;
+ argv[0] = STRING_TO_JSVAL(str);
+ } else {
+ str = JSVAL_TO_STRING(JS_GetEmptyStringValue(cx));
+ }
+
+ /* Get a line from the infile */
+ if (!GetLine(cx, buf, gInFile, JS_GetStringBytes(str)))
+ return JS_FALSE;
+
+ /* Strip newline character added by GetLine() */
+ unsigned int buflen = strlen(buf);
+ if (buflen == 0) {
+ if (feof(gInFile)) {
+ *rval = JSVAL_NULL;
+ return JS_TRUE;
+ }
+ } else if (buf[buflen - 1] == '\n') {
+ --buflen;
+ }
+
+ /* Turn buf into a JSString */
+ str = JS_NewStringCopyN(cx, buf, buflen);
+ if (!str)
+ return JS_FALSE;
+
+ *rval = STRING_TO_JSVAL(str);
+ return JS_TRUE;
+}
+
+static JSBool
Print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
uintN i, n;
JSString *str;
for (i = n = 0; i < argc; i++) {
str = JS_ValueToString(cx, argv[i]);
if (!str)
@@ -441,16 +515,17 @@ Clear(JSContext *cx, JSObject *obj, uint
JS_ReportError(cx, "'clear' requires an object");
return JS_FALSE;
}
return JS_TRUE;
}
static JSFunctionSpec glob_functions[] = {
{"print", Print, 0,0,0},
+ {"readline", ReadLine, 1,0,0},
{"load", Load, 1,0,0},
{"quit", Quit, 0,0,0},
{"version", Version, 1,0,0},
{"build", BuildDate, 0,0,0},
{"dumpXPC", DumpXPC, 1,0,0},
{"dump", Dump, 1,0,0},
{"gc", GC, 0,0,0},
{"clear", Clear, 1,0,0},
@@ -621,46 +696,16 @@ my_GetErrorMessage(void *userRef, const
#ifdef EDITLINE
extern "C" {
extern char *readline(const char *prompt);
extern void add_history(char *line);
}
#endif
-static JSBool
-GetLine(JSContext *cx, char *bufp, FILE *file, const char *prompt) {
-#ifdef EDITLINE
- /*
- * Use readline only if file is stdin, because there's no way to specify
- * another handle. Are other filehandles interactive?
- */
- if (file == stdin) {
- char *linep = readline(prompt);
- if (!linep)
- return JS_FALSE;
- if (*linep)
- add_history(linep);
- strcpy(bufp, linep);
- JS_free(cx, linep);
- bufp += strlen(bufp);
- *bufp++ = '\n';
- *bufp = '\0';
- } else
-#endif
- {
- char line[256];
- fprintf(gOutFile, prompt);
- fflush(gOutFile);
- if (!fgets(line, sizeof line, file))
- return JS_FALSE;
- strcpy(bufp, line);
- }
- return JS_TRUE;
-}
static void
ProcessFile(JSContext *cx, JSObject *obj, const char *filename, FILE *file,
JSBool forceTTY)
{
JSScript *script;
jsval result;
int lineno, startline;
@@ -1363,16 +1408,17 @@ main(int argc, char **argv, char **envp)
nsresult rv;
// unbuffer stdout so that output is in the correct order; note that stderr
// is unbuffered by default
setbuf(stdout, 0);
gErrFile = stderr;
gOutFile = stdout;
+ gInFile = stdin;
{
nsCOMPtr<nsIServiceManager> servMan;
rv = NS_InitXPCOM2(getter_AddRefs(servMan), nsnull, nsnull);
if (NS_FAILED(rv)) {
printf("NS_InitXPCOM failed!\n");
return 1;
}
{