xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/python/py-gdb-readline.c (revision 8b657b0747480f8989760d71343d6dd33f8d4cf9)
1 /* Readline support for Python.
2 
3    Copyright (C) 2012-2023 Free Software Foundation, Inc.
4 
5    This file is part of GDB.
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19 
20 #include "defs.h"
21 #include "python-internal.h"
22 #include "top.h"
23 #include "cli/cli-utils.h"
24 
25 /* Readline function suitable for PyOS_ReadlineFunctionPointer, which
26    is used for Python's interactive parser and raw_input.  In both
27    cases, sys_stdin and sys_stdout are always stdin and stdout
28    respectively, as far as I can tell; they are ignored and
29    command_line_input is used instead.  */
30 
31 static char *
32 gdbpy_readline_wrapper (FILE *sys_stdin, FILE *sys_stdout,
33 #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 4
34 			const char *prompt)
35 #else
36 			char *prompt)
37 #endif
38 {
39   int n;
40   const char *p = NULL;
41   std::string buffer;
42   char *q;
43 
44   try
45     {
46       p = command_line_input (buffer, prompt, "python");
47     }
48   /* Handle errors by raising Python exceptions.  */
49   catch (const gdb_exception &except)
50     {
51       /* Detect user interrupt (Ctrl-C).  */
52       if (except.reason == RETURN_QUIT)
53 	return NULL;
54 
55       /* The thread state is nulled during gdbpy_readline_wrapper,
56 	 with the original value saved in the following undocumented
57 	 variable (see Python's Parser/myreadline.c and
58 	 Modules/readline.c).  */
59       PyEval_RestoreThread (_PyOS_ReadlineTState);
60       gdbpy_convert_exception (except);
61       PyEval_SaveThread ();
62       return NULL;
63     }
64 
65   /* Detect EOF (Ctrl-D).  */
66   if (p == NULL)
67     {
68       q = (char *) PyMem_RawMalloc (1);
69       if (q != NULL)
70 	q[0] = '\0';
71       return q;
72     }
73 
74   n = strlen (p);
75 
76   /* Copy the line to Python and return.  */
77   q = (char *) PyMem_RawMalloc (n + 2);
78   if (q != NULL)
79     {
80       strcpy (q, p);
81       q[n] = '\n';
82       q[n + 1] = '\0';
83     }
84   return q;
85 }
86 
87 /* Initialize Python readline support.  */
88 
89 void
90 gdbpy_initialize_gdb_readline (void)
91 {
92   /* Python's readline module conflicts with GDB's use of readline
93      since readline is not reentrant.  Ideally, a reentrant wrapper to
94      GDB's readline should be implemented to replace Python's readline
95      and prevent conflicts.  For now, this file implements a
96      sys.meta_path finder that simply fails to import the readline
97      module.  */
98   if (PyRun_SimpleString ("\
99 import sys\n\
100 \n\
101 class GdbRemoveReadlineFinder:\n\
102   def find_module(self, fullname, path=None):\n\
103     if fullname == 'readline' and path is None:\n\
104       return self\n\
105     return None\n\
106 \n\
107   def load_module(self, fullname):\n\
108     raise ImportError('readline module disabled under GDB')\n\
109 \n\
110 sys.meta_path.append(GdbRemoveReadlineFinder())\n\
111 ") == 0)
112     PyOS_ReadlineFunctionPointer = gdbpy_readline_wrapper;
113 }
114 
115