xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/guile/scm-string.c (revision 8b657b0747480f8989760d71343d6dd33f8d4cf9)
1 /* GDB/Scheme charset interface.
2 
3    Copyright (C) 2014-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 /* See README file in this directory for implementation notes, coding
21    conventions, et.al.  */
22 
23 #include "defs.h"
24 #include "charset.h"
25 #include "guile-internal.h"
26 #include "gdbsupport/buildargv.h"
27 
28 /* Convert STRING to an int.
29    STRING must be a valid integer.  */
30 
31 int
32 gdbscm_scm_string_to_int (SCM string)
33 {
34   char *s = scm_to_latin1_string (string);
35   int r = atoi (s);
36 
37   free (s);
38   return r;
39 }
40 
41 /* Convert a C (latin1) string to an SCM string.
42    "latin1" is chosen because Guile won't throw an exception.  */
43 
44 SCM
45 gdbscm_scm_from_c_string (const char *string)
46 {
47   return scm_from_latin1_string (string);
48 }
49 
50 /* Convert an SCM string to a C (latin1) string.
51    "latin1" is chosen because Guile won't throw an exception.
52    It is an error to call this if STRING is not a string.  */
53 
54 gdb::unique_xmalloc_ptr<char>
55 gdbscm_scm_to_c_string (SCM string)
56 {
57   return gdb::unique_xmalloc_ptr<char> (scm_to_latin1_string (string));
58 }
59 
60 /* Use printf to construct a Scheme string.  */
61 
62 SCM
63 gdbscm_scm_from_printf (const char *format, ...)
64 {
65   va_list args;
66   SCM result;
67 
68   va_start (args, format);
69   std::string string = string_vprintf (format, args);
70   va_end (args);
71   result = scm_from_latin1_string (string.c_str ());
72 
73   return result;
74 }
75 
76 /* Struct to pass data from gdbscm_scm_to_string to
77    gdbscm_call_scm_to_stringn.  */
78 
79 struct scm_to_stringn_data
80 {
81   SCM string;
82   size_t *lenp;
83   const char *charset;
84   scm_t_string_failed_conversion_handler conversion_kind;
85   char *result;
86 };
87 
88 /* Helper for gdbscm_scm_to_string to call scm_to_stringn
89    from within scm_c_catch.  */
90 
91 static SCM
92 gdbscm_call_scm_to_stringn (void *datap)
93 {
94   struct scm_to_stringn_data *data = (struct scm_to_stringn_data *) datap;
95 
96   data->result = scm_to_stringn (data->string, data->lenp, data->charset,
97 				 data->conversion_kind);
98   return SCM_BOOL_F;
99 }
100 
101 /* Convert an SCM string to a string in charset CHARSET.
102    This function is guaranteed to not throw an exception.
103 
104    If LENP is NULL then the returned string is NUL-terminated,
105    and an exception is thrown if the string contains embedded NULs.
106    Otherwise the string is not guaranteed to be NUL-terminated, but worse
107    there's no space to put a NUL if we wanted to (scm_to_stringn limitation).
108 
109    If STRICT is non-zero, and there's a conversion error, then a
110    <gdb:exception> object is stored in *EXCEPT_SCMP, and NULL is returned.
111    If STRICT is zero, then escape sequences are used for characters that
112    can't be converted, and EXCEPT_SCMP may be passed as NULL.
113 
114    It is an error to call this if STRING is not a string.  */
115 
116 gdb::unique_xmalloc_ptr<char>
117 gdbscm_scm_to_string (SCM string, size_t *lenp,
118 		      const char *charset, int strict, SCM *except_scmp)
119 {
120   struct scm_to_stringn_data data;
121   SCM scm_result;
122 
123   data.string = string;
124   data.lenp = lenp;
125   data.charset = charset;
126   data.conversion_kind = (strict
127 			  ? SCM_FAILED_CONVERSION_ERROR
128 			  : SCM_FAILED_CONVERSION_ESCAPE_SEQUENCE);
129   data.result = NULL;
130 
131   scm_result = gdbscm_call_guile (gdbscm_call_scm_to_stringn, &data, NULL);
132 
133   if (gdbscm_is_false (scm_result))
134     {
135       gdb_assert (data.result != NULL);
136       return gdb::unique_xmalloc_ptr<char> (data.result);
137     }
138   gdb_assert (gdbscm_is_exception (scm_result));
139   *except_scmp = scm_result;
140   return NULL;
141 }
142 
143 /* Struct to pass data from gdbscm_scm_from_string to
144    gdbscm_call_scm_from_stringn.  */
145 
146 struct scm_from_stringn_data
147 {
148   const char *string;
149   size_t len;
150   const char *charset;
151   scm_t_string_failed_conversion_handler conversion_kind;
152   SCM result;
153 };
154 
155 /* Helper for gdbscm_scm_from_string to call scm_from_stringn
156    from within scm_c_catch.  */
157 
158 static SCM
159 gdbscm_call_scm_from_stringn (void *datap)
160 {
161   struct scm_from_stringn_data *data = (struct scm_from_stringn_data *) datap;
162 
163   data->result = scm_from_stringn (data->string, data->len, data->charset,
164 				   data->conversion_kind);
165   return SCM_BOOL_F;
166 }
167 
168 /* Convert STRING to a Scheme string in charset CHARSET.
169    This function is guaranteed to not throw an exception.
170 
171    If STRICT is non-zero, and there's a conversion error, then a
172    <gdb:exception> object is returned.
173    If STRICT is zero, then question marks are used for characters that
174    can't be converted (limitation of underlying Guile conversion support).  */
175 
176 SCM
177 gdbscm_scm_from_string (const char *string, size_t len,
178 			const char *charset, int strict)
179 {
180   struct scm_from_stringn_data data;
181   SCM scm_result;
182 
183   data.string = string;
184   data.len = len;
185   data.charset = charset;
186   /* The use of SCM_FAILED_CONVERSION_QUESTION_MARK is specified by Guile.  */
187   data.conversion_kind = (strict
188 			  ? SCM_FAILED_CONVERSION_ERROR
189 			  : SCM_FAILED_CONVERSION_QUESTION_MARK);
190   data.result = SCM_UNDEFINED;
191 
192   scm_result = gdbscm_call_guile (gdbscm_call_scm_from_stringn, &data, NULL);
193 
194   if (gdbscm_is_false (scm_result))
195     {
196       gdb_assert (!SCM_UNBNDP (data.result));
197       return data.result;
198     }
199   gdb_assert (gdbscm_is_exception (scm_result));
200   return scm_result;
201 }
202 
203 /* Convert an SCM string to a host string.
204    This function is guaranteed to not throw an exception.
205 
206    If LENP is NULL then the returned string is NUL-terminated,
207    and if the string contains embedded NULs then NULL is returned with
208    an exception object stored in *EXCEPT_SCMP.
209    Otherwise the string is not guaranteed to be NUL-terminated, but worse
210    there's no space to put a NUL if we wanted to (scm_to_stringn limitation).
211 
212    Returns NULL if there is a conversion error, with the exception object
213    stored in *EXCEPT_SCMP.
214    It is an error to call this if STRING is not a string.  */
215 
216 gdb::unique_xmalloc_ptr<char>
217 gdbscm_scm_to_host_string (SCM string, size_t *lenp, SCM *except_scmp)
218 {
219   return gdbscm_scm_to_string (string, lenp, host_charset (), 1, except_scmp);
220 }
221 
222 /* Convert a host string to an SCM string.
223    This function is guaranteed to not throw an exception.
224    Returns a <gdb:exception> object if there's a conversion error.  */
225 
226 SCM
227 gdbscm_scm_from_host_string (const char *string, size_t len)
228 {
229   return gdbscm_scm_from_string (string, len, host_charset (), 1);
230 }
231 
232 /* (string->argv string) -> list
233    Return list of strings split up according to GDB's argv parsing rules.
234    This is useful when writing GDB commands in Scheme.  */
235 
236 static SCM
237 gdbscm_string_to_argv (SCM string_scm)
238 {
239   char *string;
240   SCM result = SCM_EOL;
241 
242   gdbscm_parse_function_args (FUNC_NAME, SCM_ARG1, NULL, "s",
243 			      string_scm, &string);
244 
245   if (string == NULL || *string == '\0')
246     {
247       xfree (string);
248       return SCM_EOL;
249     }
250 
251   gdb_argv c_argv (string);
252   for (char *arg : c_argv)
253     result = scm_cons (gdbscm_scm_from_c_string (arg), result);
254 
255   xfree (string);
256 
257   return scm_reverse_x (result, SCM_EOL);
258 }
259 
260 /* Initialize the Scheme charset interface to GDB.  */
261 
262 static const scheme_function string_functions[] =
263 {
264   { "string->argv", 1, 0, 0, as_a_scm_t_subr (gdbscm_string_to_argv),
265   "\
266 Convert a string to a list of strings split up according to\n\
267 gdb's argv parsing rules." },
268 
269   END_FUNCTIONS
270 };
271 
272 void
273 gdbscm_initialize_strings (void)
274 {
275   gdbscm_define_functions (string_functions, 1);
276 }
277