myreadline.c 2.9 KB
Newer Older
Guido van Rossum's avatar
Guido van Rossum committed
1

2 3 4 5
/* Readline interface for tokenizer.c and [raw_]input() in bltinmodule.c.
   By default, or when stdin is not a tty device, we have a super
   simple my_readline function using fgets.
   Optionally, we can use the GNU readline library.
Guido van Rossum's avatar
Guido van Rossum committed
6 7 8 9 10 11
   my_readline() has a different return value from GNU readline():
   - NULL if an interrupt occurred or if an error occurred
   - a malloc'ed empty string if EOF was read
   - a malloc'ed string ending in \n normally
*/

12
#include "Python.h"
Guido van Rossum's avatar
Guido van Rossum committed
13

Thomas Wouters's avatar
Thomas Wouters committed
14
int (*PyOS_InputHook)(void) = NULL;
15

16 17 18 19
#ifdef RISCOS
int Py_RISCOSWimpFlag;
#endif

20 21 22 23
/* This function restarts a fgets() after an EINTR error occurred
   except if PyOS_InterruptOccurred() returns true. */

static int
Thomas Wouters's avatar
Thomas Wouters committed
24
my_fgets(char *buf, int len, FILE *fp)
25 26 27
{
	char *p;
	for (;;) {
28 29
		if (PyOS_InputHook != NULL)
			(void)(PyOS_InputHook)();
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
		errno = 0;
		p = fgets(buf, len, fp);
		if (p != NULL)
			return 0; /* No error */
		if (feof(fp)) {
			return -1; /* EOF */
		}
#ifdef EINTR
		if (errno == EINTR) {
			if (PyOS_InterruptOccurred()) {
				return 1; /* Interrupt */
			}
			continue;
		}
#endif
		if (PyOS_InterruptOccurred()) {
			return 1; /* Interrupt */
		}
		return -2; /* Error */
	}
	/* NOTREACHED */
}


/* Readline implementation using fgets() */

char *
Thomas Wouters's avatar
Thomas Wouters committed
57
PyOS_StdioReadline(char *prompt)
58
{
59
	size_t n;
60
	char *p;
Guido van Rossum's avatar
Guido van Rossum committed
61
	n = 100;
62
	if ((p = PyMem_MALLOC(n)) == NULL)
Guido van Rossum's avatar
Guido van Rossum committed
63
		return NULL;
64
	fflush(stdout);
65
#ifndef RISCOS
Guido van Rossum's avatar
Guido van Rossum committed
66 67
	if (prompt)
		fprintf(stderr, "%s", prompt);
68 69 70 71 72 73 74 75
#else
	if (prompt) {
		if(Py_RISCOSWimpFlag)
			fprintf(stderr, "\x0cr%s\x0c", prompt);
		else
			fprintf(stderr, "%s", prompt);
	}
#endif
76
	fflush(stderr);
77
	switch (my_fgets(p, (int)n, stdin)) {
78 79 80
	case 0: /* Normal case */
		break;
	case 1: /* Interrupt */
81
		PyMem_FREE(p);
Guido van Rossum's avatar
Guido van Rossum committed
82
		return NULL;
83 84 85 86 87
	case -1: /* EOF */
	case -2: /* Error */
	default: /* Shouldn't happen */
		*p = '\0';
		break;
Guido van Rossum's avatar
Guido van Rossum committed
88
	}
89 90 91 92 93 94 95
#ifdef MPW
	/* Hack for MPW C where the prompt comes right back in the input */
	/* XXX (Actually this would be rather nice on most systems...) */
	n = strlen(prompt);
	if (strncmp(p, prompt, n) == 0)
		memmove(p, p + n, strlen(p) - n + 1);
#endif
Guido van Rossum's avatar
Guido van Rossum committed
96 97
	n = strlen(p);
	while (n > 0 && p[n-1] != '\n') {
98
		size_t incr = n+2;
99
		p = PyMem_REALLOC(p, n + incr);
Guido van Rossum's avatar
Guido van Rossum committed
100 101
		if (p == NULL)
			return NULL;
102 103 104 105
		if (incr > INT_MAX) {
			PyErr_SetString(PyExc_OverflowError, "input line too long");
		}
		if (my_fgets(p+n, (int)incr, stdin) != 0)
Guido van Rossum's avatar
Guido van Rossum committed
106 107 108
			break;
		n += strlen(p+n);
	}
109
	return PyMem_REALLOC(p, n+1);
110 111 112 113
}


/* By initializing this function pointer, systems embedding Python can
114 115 116
   override the readline function.

   Note: Python expects in return a buffer allocated with PyMem_Malloc. */
117

118
char *(*PyOS_ReadlineFunctionPointer)(char *);
119 120 121 122 123


/* Interface used by tokenizer.c and bltinmodule.c */

char *
Thomas Wouters's avatar
Thomas Wouters committed
124
PyOS_Readline(char *prompt)
125
{
126
	char *rv;
127 128 129
	if (PyOS_ReadlineFunctionPointer == NULL) {
			PyOS_ReadlineFunctionPointer = PyOS_StdioReadline;
	}
130
	Py_BEGIN_ALLOW_THREADS
131
	rv = (*PyOS_ReadlineFunctionPointer)(prompt);
132
	Py_END_ALLOW_THREADS
133
	return rv;
Guido van Rossum's avatar
Guido van Rossum committed
134
}