closes bpo-38156: Always handle interrupts in PyOS_StdioReadline. (GH-21569)


This consolidates the handling of my_fgets return values, so that interrupts are always handled, even if they come after EOF.

 I believe PyOS_StdioReadline is still buggy in that I/O errors will not result in a proper Python exception being set. However, that is a separate issue.
(cherry picked from commit a74eea238f5baba15797e2e8b570d153bc8690a7)

Co-authored-by: Benjamin Peterson <benjamin@python.org>
diff --git a/Parser/myreadline.c b/Parser/myreadline.c
index 2dd3623..a49c9d8 100644
--- a/Parser/myreadline.c
+++ b/Parser/myreadline.c
@@ -291,37 +291,16 @@
     }
 #endif
 
-    n = 100;
-    p = (char *)PyMem_RawMalloc(n);
-    if (p == NULL) {
-        PyEval_RestoreThread(tstate);
-        PyErr_NoMemory();
-        PyEval_SaveThread();
-        return NULL;
-    }
-
     fflush(sys_stdout);
     if (prompt) {
         fprintf(stderr, "%s", prompt);
     }
     fflush(stderr);
 
-    switch (my_fgets(tstate, p, (int)n, sys_stdin)) {
-    case 0: /* Normal case */
-        break;
-    case 1: /* Interrupt */
-        PyMem_RawFree(p);
-        return NULL;
-    case -1: /* EOF */
-    case -2: /* Error */
-    default: /* Shouldn't happen */
-        *p = '\0';
-        break;
-    }
-
-    n = strlen(p);
-    while (n > 0 && p[n-1] != '\n') {
-        size_t incr = n+2;
+    n = 0;
+    p = NULL;
+    do {
+        size_t incr = (n > 0) ? n + 2 : 100;
         if (incr > INT_MAX) {
             PyMem_RawFree(p);
             PyEval_RestoreThread(tstate);
@@ -329,7 +308,6 @@
             PyEval_SaveThread();
             return NULL;
         }
-
         pr = (char *)PyMem_RawRealloc(p, n + incr);
         if (pr == NULL) {
             PyMem_RawFree(p);
@@ -339,12 +317,18 @@
             return NULL;
         }
         p = pr;
-
-        if (my_fgets(tstate, p+n, (int)incr, sys_stdin) != 0) {
+        int err = my_fgets(tstate, p + n, incr, sys_stdin);
+        if (err == 1) {
+            // Interrupt
+            PyMem_RawFree(p);
+            return NULL;
+        } else if (err != 0) {
+            // EOF or error
+            p[n] = '\0';
             break;
         }
-        n += strlen(p+n);
-    }
+        n += strlen(p + n);
+    } while (p[n-1] != '\n');
 
     pr = (char *)PyMem_RawRealloc(p, n+1);
     if (pr == NULL) {