Steffen Daode Nurpmeso <sdao...@googlemail.com> added the comment:
On Sat, Apr 09, 2011 at 02:18:01PM +0000, STINNER Victor wrote:
> I noticied a strange behaviour:
So forget all this girlie s...!
Here is a real man's patch!!
You'll notice mysterious function calls with a Py prefix -
they're necessary in this environment, but anyway sorry for that.
(L'ascenseur est là , à gauche.
And i'll hope to come to lesson 2 soon...)
P.S.: this is very simple minded in respect to multibyte
characters; our terminal library does something like this
(and the complete picture is even more complicated):
jnext: uni = s_textcodec_decode_single(_sterm_io_codec, cbuf, cbuf_len,
&bytes_consumed);
cbuf += bytes_consumed;
cbuf_len -= bytes_consumed;
if (s_PREDICT_FALSE(uni < 0)) {
if (uni == -s_ERROR_INPROGRESS) {
seq_cpl = s_FAL0;
goto jleave;
}
/*if (uni == -s_ERROR_ILSEQ || uni == -s_ERROR_INVAL) {*/
cbuf_len = 0;
uni = sterm_KEY_UNKNOWN;
goto jemit;
/*}*/
}
----------
Added file: http://bugs.python.org/file21593/11650.termios.diff
_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue11650>
_______________________________________
diff --git a/Parser/myreadline.c b/Parser/myreadline.c
--- a/Parser/myreadline.c
+++ b/Parser/myreadline.c
@@ -10,6 +10,9 @@
*/
#include "Python.h"
+#ifdef Py_PYPORT_H
+# include "signal.h"
+#endif
#ifdef MS_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
@@ -29,117 +32,187 @@
int (*PyOS_InputHook)(void) = NULL;
-/* This function restarts a fgets() after an EINTR error occurred
+/* This function restarts a fgetc() after an EINTR error occurred
except if PyOS_InterruptOccurred() returns true. */
+static int
+my_fgets(char **store, FILE *fp)
+{
+ int estat;
+ char *buf, *cursor;
+ size_t buf_len;
-static int
-my_fgets(char *buf, int len, FILE *fp)
-{
- char *p;
+ buf = (char*)PyMem_MALLOC(2*80);
+ estat = 1;
+ if (buf == NULL)
+ goto jreturn;
+
+ cursor = buf;
+ buf_len = 2*80 - 2;
+jrestart_input:
+ estat = 0;
+
+ if (PyOS_InputHook != NULL)
+ (void)(PyOS_InputHook)();
+
+ /* Fetch bytes until error or newline */
+ errno = 0;
while (1) {
- if (PyOS_InputHook != NULL)
- (void)(PyOS_InputHook)();
- errno = 0;
- p = fgets(buf, len, fp);
- if (p != NULL)
- return 0; /* No error */
+ int c = fgetc(fp);
+#ifdef Py_PYPORT_H
+ if (!isprint(c))
+ switch (c) {
+ case '':
+ c = EOF;
+ /* FALLTHROUGH */
+ default:
+ break;
+ case '':
+ estat = SIGINT;
+ goto j_sigit;
+ case '':
+ estat = SIGTSTP;
+ goto j_sigit;
+ case '':
+ estat = SIGQUIT;
+ /* FALLTHROUGH */
+j_sigit: kill(getpid(), estat);
+ errno = EINTR;
+ goto jcheck_fail;
+ }
+#endif
+ if (c == EOF)
+ goto jcheck_fail;
+ *(cursor++) = (char)c;
+ if (c == '\n')
+ break;
+
+ if ((size_t)(cursor-buf) >= buf_len) {
+ buf_len += 2+32;
+ cursor = buf = (char*)PyMem_REALLOC(buf, buf_len);
+ if (buf == NULL) {
+ estat = 1;
+ goto jreturn;
+ }
+ buf_len -= 2+32;
+ cursor += buf_len;
+ buf_len += 32;
+ }
+ }
+
+ *cursor = '\0';
+ *store = buf;
+jreturn:
+ return estat;
+
+jcheck_fail:
#ifdef MS_WINDOWS
- /* In the case of a Ctrl+C or some other external event
- interrupting the operation:
- Win2k/NT: ERROR_OPERATION_ABORTED is the most recent Win32
- error code (and feof() returns TRUE).
- Win9x: Ctrl+C seems to have no effect on fgets() returning
- early - the signal handler is called, but the fgets()
- only returns "normally" (ie, when Enter hit or feof())
+ /* In the case of a Ctrl+C or some other external event
+ interrupting the operation:
+ Win2k/NT: ERROR_OPERATION_ABORTED is the most recent Win32
+ error code (and feof() returns TRUE).
+ Win9x: Ctrl+C seems to have no effect on fgets() returning
+ early - the signal handler is called, but the fgets()
+ only returns "normally" (ie, when Enter hit or feof())
+ */
+ if (GetLastError()==ERROR_OPERATION_ABORTED) {
+ /* Signals come asynchronously, so we sleep a brief
+ moment before checking if the handler has been
+ triggered (we cant just return 1 before the
+ signal handler has been called, as the later
+ signal may be treated as a separate interrupt).
*/
- if (GetLastError()==ERROR_OPERATION_ABORTED) {
- /* Signals come asynchronously, so we sleep a brief
- moment before checking if the handler has been
- triggered (we cant just return 1 before the
- signal handler has been called, as the later
- signal may be treated as a separate interrupt).
- */
- Sleep(1);
- if (PyOS_InterruptOccurred()) {
- return 1; /* Interrupt */
- }
- /* Either the sleep wasn't long enough (need a
- short loop retrying?) or not interrupted at all
- (in which case we should revisit the whole thing!)
- Logging some warning would be nice. assert is not
- viable as under the debugger, the various dialogs
- mean the condition is not true.
- */
+ Sleep(1);
+ if (PyOS_InterruptOccurred()) {
+ estat = 1;
+ goto jfail;
}
+ /* Either the sleep wasn't long enough (need a
+ short loop retrying?) or not interrupted at all
+ (in which case we should revisit the whole thing!)
+ Logging some warning would be nice. assert is not
+ viable as under the debugger, the various dialogs
+ mean the condition is not true.
+ */
+ }
#endif /* MS_WINDOWS */
- if (feof(fp)) {
- return -1; /* EOF */
+
+#ifndef Py_PYPORT_H
+ if (feof(fp)) {
+ estat = -1; /* EOF */
+ goto jfail;
+ }
+#endif
+#ifdef EINTR
+ if (errno == EINTR) {
+# ifdef WITH_THREAD
+ PyEval_RestoreThread(_PyOS_ReadlineTState);
+# endif
+ estat = PyErr_CheckSignals();
+# ifdef WITH_THREAD
+ PyEval_SaveThread();
+# endif
+ if (estat < 0) {
+ estat = 1;
+ goto jfail;
}
-#ifdef EINTR
- if (errno == EINTR) {
- int s;
-#ifdef WITH_THREAD
- PyEval_RestoreThread(_PyOS_ReadlineTState);
+ /* EINTR is restarted */
+ goto jrestart_input;
+ }
#endif
- s = PyErr_CheckSignals();
-#ifdef WITH_THREAD
- PyEval_SaveThread();
-#endif
- if (s < 0)
- return 1;
- /* try again */
- continue;
- }
-#endif
- if (PyOS_InterruptOccurred()) {
- return 1; /* Interrupt */
- }
- return -2; /* Error */
+
+ if (PyOS_InterruptOccurred()) {
+ estat = 1; /* Interrupt */
+ goto jfail;
}
- /* NOTREACHED */
+ estat = -2; /* Error */
+ /* FALLTHROUGH */
+
+jfail:
+ PyMem_Free(buf);
+ goto jreturn;
}
-
-/* Readline implementation using fgets() */
-
+/* Readline implementation using my_fgets() */
char *
PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, char *prompt)
{
- size_t n;
- char *p;
- n = 100;
- if ((p = (char *)PyMem_MALLOC(n)) == NULL)
- return NULL;
+ auto char *result = NULL;
+#ifdef Py_PYPORT_H
+ auto struct termios told, tnew;
+ int infd = fileno(sys_stdin);
+
+ while (tcgetattr(infd, &told) != 0)
+ ;
+ memcpy(&tnew, &told, sizeof(told));
+ tnew.c_lflag &= ~(ECHOCTL | ICANON);
+ tnew.c_cc[VMIN] = 1;
+ while (tcsetattr(infd, TCSAFLUSH, &tnew) != 0)
+ ;
+#endif
+
fflush(sys_stdout);
if (prompt)
fprintf(stderr, "%s", prompt);
fflush(stderr);
- switch (my_fgets(p, (int)n, sys_stdin)) {
+
+ switch (my_fgets(&result, sys_stdin)) {
case 0: /* Normal case */
+ case 1: /* Interrupt */
break;
- case 1: /* Interrupt */
- PyMem_FREE(p);
- return NULL;
case -1: /* EOF */
case -2: /* Error */
default: /* Shouldn't happen */
- *p = '\0';
+ result = (char*)PyMem_MALLOC(sizeof(void*));
+ if (result != NULL)
+ *result = '\0';
break;
}
- n = strlen(p);
- while (n > 0 && p[n-1] != '\n') {
- size_t incr = n+2;
- p = (char *)PyMem_REALLOC(p, n + incr);
- if (p == NULL)
- return NULL;
- if (incr > INT_MAX) {
- PyErr_SetString(PyExc_OverflowError, "input line too long");
- }
- if (my_fgets(p+n, (int)incr, sys_stdin) != 0)
- break;
- n += strlen(p+n);
- }
- return (char *)PyMem_REALLOC(p, n+1);
+
+#ifdef Py_PYPORT_H
+ while (tcsetattr(infd, TCSANOW, &told) != 0)
+ ;
+#endif
+ return result;
}
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com