bug 413735 - consistent readline usage
authorAndrei Saprykin <andrei@runitsoft.com>
Tue, 13 Jan 2009 16:35:47 +0100
changeset 23723 56128cae91c99e875dc8b918c1425c31bbda02ba
parent 23722 d0a0f0694cedcf5a01cebe37b15d1d781000149f
child 23724 de45be48741570475d22aec7d15d1f65316745a9
push id4690
push userrsayre@mozilla.com
push dateThu, 15 Jan 2009 07:42:55 +0000
treeherdermozilla-central@ddfa483fea2a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs413735
milestone1.9.2a1pre
bug 413735 - consistent readline usage
js/src/editline/editline.c
js/src/js.cpp
--- a/js/src/editline/editline.c
+++ b/js/src/editline/editline.c
@@ -155,17 +155,17 @@ int		rl_meta_chars = 0;
 **  Declarations.
 */
 STATIC CHAR	*editinput();
 #if	defined(USE_TERMCAP)
 #include <stdlib.h>
 #include <curses.h>
 #include <term.h>
 #endif	/* defined(USE_TERMCAP) */
-
+
 /*
 **  TTY input/output functions.
 */
 
 STATIC void
 TTYflush()
 {
     if (ScreenCount) {
@@ -296,17 +296,17 @@ TTYinfo()
     }
 #endif	/* defined(TIOCGWINSZ) */
 
     if (TTYwidth <= 0 || TTYrows <= 0) {
 	TTYwidth = SCREEN_WIDTH;
 	TTYrows = SCREEN_ROWS;
     }
 }
-
+
 
 STATIC void
 reposition()
 {
     int		i;
     CHAR	*p;
 
     TTYput('\r');
@@ -510,17 +510,17 @@ redisplay()
 }
 
 STATIC STATUS
 toggle_meta_mode()
 {
     rl_meta_chars = ! rl_meta_chars;
     return redisplay();
 }
-
+
 
 STATIC CHAR *
 next_hist()
 {
     return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
 }
 
 STATIC CHAR *
@@ -961,16 +961,19 @@ editinput()
 	    case CSdispatch:
 	    case CSstay:
 		break;
 	    }
 	    break;
 	case CSstay:
 	    break;
 	}
+    if (strlen(Line))
+        return Line;
+    free(Line);
     return NULL;
 }
 
 STATIC void
 hist_add(p)
     CHAR	*p;
 {
     int		i;
@@ -1047,17 +1050,17 @@ add_history(p)
 	return;
 
 #if	defined(UNIQUE_HISTORY)
     if (H.Size && strcmp(p, H.Lines[H.Size - 1]) == 0)
         return;
 #endif	/* defined(UNIQUE_HISTORY) */
     hist_add((CHAR *)p);
 }
-
+
 
 STATIC STATUS
 beg_line()
 {
     if (Point) {
 	Point = 0;
 	return CSmove;
     }
--- a/js/src/js.cpp
+++ b/js/src/js.cpp
@@ -137,45 +137,76 @@ RescheduleOperationCallback(JSContext *c
 
 #ifdef EDITLINE
 JS_BEGIN_EXTERN_C
 extern char     *readline(const char *prompt);
 extern void     add_history(char *line);
 JS_END_EXTERN_C
 #endif
 
-static JSBool
-GetLine(JSContext *cx, char *bufp, FILE *file, const char *prompt) {
+static char *
+GetLine(FILE *file, const char * prompt)
+{
+    size_t size;
+    char *buffer;
 #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);
+        /*
+         * We set it to zero to avoid complaining about inappropriate ioctl
+         * for device in the case of EOF. Looks like errno == 251 if line is
+         * finished with EOF and errno == 25 if there is nothing left
+         * to read.
+         */
+        if (errno == 251 || errno == 25)
+            errno = 0;
         if (!linep)
-            return JS_FALSE;
+            return NULL;
         if (linep[0] != '\0')
             add_history(linep);
-        strcpy(bufp, linep);
-        JS_free(cx, linep);
-        bufp += strlen(bufp);
-        *bufp++ = '\n';
-        *bufp = '\0';
-    } else
+        return linep;
+    }
 #endif
-    {
-        char line[256];
+    size_t len = 0;
+    if (*prompt != '\0') {
         fprintf(gOutFile, prompt);
         fflush(gOutFile);
-        if (!fgets(line, sizeof line, file))
-            return JS_FALSE;
-        strcpy(bufp, line);
     }
-    return JS_TRUE;
+    size = 80;
+    buffer = (char *) malloc(size);
+    if (!buffer)
+        return NULL;
+    char *current = buffer;
+    while (fgets(current, size - len, file)) {
+        len += strlen(current);
+        char *t = buffer + len - 1;
+        if (*t == '\n') {
+            /* Line was read. We remove '\n' and exit. */
+            *t = '\0';
+            return buffer;
+        }
+        if (len + 1 == size) {
+            size = size * 2;
+            char *tmp = (char *) realloc(buffer, size);
+            if (!tmp) {
+                free(buffer);
+                return NULL;
+            }
+            buffer = tmp;
+        }
+        current = buffer + len;
+    }
+    if (len && !ferror(file))
+        return buffer;
+    free(buffer);
+    return NULL;
 }
 
 /* Time-related portability helpers. */
 typedef int64 OperationTime;
 const OperationTime TIME_INFINITY = -1LL;
 
 static inline OperationTime
 TicksPerSecond()
@@ -291,18 +322,18 @@ SetContextOptions(JSContext *cx)
 
 static void
 Process(JSContext *cx, JSObject *obj, char *filename, JSBool forceTTY)
 {
     JSBool ok, hitEOF;
     JSScript *script;
     jsval result;
     JSString *str;
-    char buffer[4096];
-    char *bufp;
+    char *buffer;
+    size_t size;
     int lineno;
     int startline;
     FILE *file;
     uint32 oldopts;
 
     if (forceTTY || !filename || strcmp(filename, "-") == 0) {
         file = stdin;
     } else {
@@ -351,54 +382,90 @@ Process(JSContext *cx, JSObject *obj, ch
             fclose(file);
         return;
     }
 #endif /* WINCE */
 
     /* It's an interactive filehandle; drop into read-eval-print loop. */
     lineno = 1;
     hitEOF = JS_FALSE;
+    size_t len;
+    buffer = NULL;
     do {
-        bufp = buffer;
-        *bufp = '\0';
 
         /*
          * Accumulate lines until we get a 'compilable unit' - one that either
          * generates an error (before running out of source) or that compiles
          * cleanly.  This should be whenever we get a complete statement that
          * coincides with the end of a line.
          */
         startline = lineno;
         do {
-            if (!GetLine(cx, bufp, file, startline == lineno ? "js> " : "")) {
+            errno = 0;
+            char *line = GetLine(file, startline == lineno ? "js> " : "");
+            if (!line) {
+                if (errno) {
+                    JS_ReportError(cx, strerror(errno));
+                    free(buffer);
+                    return;
+                }
                 hitEOF = JS_TRUE;
                 break;
             }
-            bufp += strlen(bufp);
+            if (!buffer) {
+                buffer = line;
+                len = strlen(buffer);
+                size = len + 1;
+            } else {
+                /**
+                 * len + 1 is required to store '\n' in the end of line
+                 */
+                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);
+                        return;
+                    }
+                    buffer = newBuf;
+                }
+                char *current = buffer + len;
+                if (startline != lineno)
+                    *current++ = '\n';
+                strcpy(current, line);
+                len = newlen;
+                free(line);
+            }
             lineno++;
-        } while (!JS_BufferIsCompilableUnit(cx, obj, buffer, strlen(buffer)));
+        } while (!JS_BufferIsCompilableUnit(cx, obj, buffer, len));
 
         /* Clear any pending exception from previous failed compiles.  */
         JS_ClearPendingException(cx);
-        script = JS_CompileScript(cx, obj, buffer, strlen(buffer), "typein",
+        script = JS_CompileScript(cx, obj, buffer, len, "typein",
                                   startline);
         if (script) {
             if (!compileOnly) {
                 ok = JS_ExecuteScript(cx, obj, script, &result);
                 if (ok && !JSVAL_IS_VOID(result)) {
                     str = JS_ValueToString(cx, result);
                     if (str)
                         fprintf(gOutFile, "%s\n", JS_GetStringBytes(str));
                     else
                         ok = JS_FALSE;
                 }
             }
             JS_DestroyScript(cx, script);
         }
+        *buffer = '\0';
+        len = 0;
     } while (!hitEOF && !gQuitting);
+    free(buffer);
     fprintf(gOutFile, "\n");
     if (file != stdin)
         fclose(file);
     return;
 }
 
 static int
 usage(void)