1 /* Copyright 1995,1996,1998-2003,2005-2006,2009-2014,2016-2019
2 Free Software Foundation, Inc.
3
4 This file is part of Guile.
5
6 Guile is free software: you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Guile is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with Guile. If not, see
18 <https://www.gnu.org/licenses/>. */
19
20
21
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <intprops.h>
31
32 #include "bytevectors.h"
33 #include "deprecation.h"
34 #include "eval.h"
35 #include "gsubr.h"
36 #include "keywords.h"
37 #include "modules.h"
38 #include "ports.h"
39 #include "procs.h"
40 #include "read.h"
41 #include "srfi-4.h"
42 #include "strings.h"
43 #include "symbols.h"
44 #include "syscalls.h"
45 #include "threads.h"
46 #include "variable.h"
47
48 #include "strports.h"
49
50
51
52
53 /* {Ports - string ports}
54 *
55 */
56
57 SCM_SYMBOL (sym_UTF_8, "UTF-8");
58
59 scm_t_port_type *scm_string_port_type;
60
61 struct string_port {
62 SCM bytevector;
63 size_t pos;
64 size_t len;
65 };
66
67 static size_t
string_port_read(SCM port,SCM dst,size_t start,size_t count)68 string_port_read (SCM port, SCM dst, size_t start, size_t count)
69 {
70 struct string_port *stream = (void *) SCM_STREAM (port);
71
72 if (stream->pos >= stream->len)
73 return 0;
74
75 if (count > stream->len - stream->pos)
76 count = stream->len - stream->pos;
77
78 memcpy (SCM_BYTEVECTOR_CONTENTS (dst) + start,
79 SCM_BYTEVECTOR_CONTENTS (stream->bytevector) + stream->pos,
80 count);
81
82 stream->pos += count;
83 return count;
84 }
85
86 #define MAX(A, B) ((A) >= (B) ? (A) : (B))
87
88 static size_t
string_port_write(SCM port,SCM src,size_t start,size_t count)89 string_port_write (SCM port, SCM src, size_t start, size_t count)
90 #define FUNC_NAME "string_port_write"
91 {
92 struct string_port *stream = (void *) SCM_STREAM (port);
93 size_t old_size = SCM_BYTEVECTOR_LENGTH (stream->bytevector);
94
95 if (count > old_size - stream->pos)
96 {
97 SCM new_bv;
98 size_t new_size;
99
100 if (INT_ADD_OVERFLOW (stream->pos, count))
101 scm_num_overflow (FUNC_NAME);
102
103 /* If (old_size * 2) overflows, it's harmless. */
104 new_size = MAX (old_size * 2, stream->pos + count);
105 new_bv = scm_c_make_bytevector (new_size);
106 memcpy (SCM_BYTEVECTOR_CONTENTS (new_bv),
107 SCM_BYTEVECTOR_CONTENTS (stream->bytevector),
108 stream->len);
109 stream->bytevector = new_bv;
110 }
111
112 memcpy (SCM_BYTEVECTOR_CONTENTS (stream->bytevector) + stream->pos,
113 SCM_BYTEVECTOR_CONTENTS (src) + start,
114 count);
115 stream->pos += count;
116 if (stream->pos > stream->len)
117 stream->len = stream->pos;
118
119 return count;
120 }
121 #undef FUNC_NAME
122
123 static scm_t_off
string_port_seek(SCM port,scm_t_off offset,int whence)124 string_port_seek (SCM port, scm_t_off offset, int whence)
125 #define FUNC_NAME "string_port_seek"
126 {
127 struct string_port *stream = (void *) SCM_STREAM (port);
128 size_t base;
129 scm_t_off target;
130
131 if (whence == SEEK_CUR)
132 base = stream->pos;
133 else if (whence == SEEK_SET)
134 base = 0;
135 else if (whence == SEEK_END)
136 base = stream->len;
137 else
138 scm_wrong_type_arg_msg (FUNC_NAME, 0, port, "invalid `seek' parameter");
139
140 if (base > SCM_T_OFF_MAX
141 || INT_ADD_OVERFLOW ((scm_t_off) base, offset))
142 scm_num_overflow (FUNC_NAME);
143 target = (scm_t_off) base + offset;
144
145 if (target >= 0 && target <= stream->len)
146 stream->pos = target;
147 else
148 scm_out_of_range (FUNC_NAME, scm_from_off_t (offset));
149
150 return target;
151 }
152 #undef FUNC_NAME
153
154 static void
string_port_truncate(SCM port,scm_t_off length)155 string_port_truncate (SCM port, scm_t_off length)
156 #define FUNC_NAME "string_port_truncate"
157 {
158 struct string_port *stream = (void *) SCM_STREAM (port);
159
160 if (0 <= length && stream->pos <= length && length <= stream->len)
161 stream->len = length;
162 else
163 scm_out_of_range (FUNC_NAME, scm_from_off_t (length));
164 }
165 #undef FUNC_NAME
166
167
168 /* The initial size in bytes of a string port's buffer. */
169 #define INITIAL_BUFFER_SIZE 128
170
171 /* Return a new string port with MODES. If STR is #f, a new backing
172 buffer is allocated; otherwise STR must be a string and a copy of it
173 serves as the buffer for the new port. */
174 SCM
scm_mkstrport(SCM pos,SCM str,long modes,const char * caller)175 scm_mkstrport (SCM pos, SCM str, long modes, const char *caller)
176 {
177 SCM buf;
178 size_t len, byte_pos;
179 struct string_port *stream;
180
181 if (!((modes & SCM_WRTNG) || (modes & SCM_RDNG)))
182 scm_misc_error ("scm_mkstrport", "port must read or write", SCM_EOL);
183
184 if (scm_is_false (str))
185 {
186 /* Allocate a new buffer to write to. */
187 buf = scm_c_make_bytevector (INITIAL_BUFFER_SIZE);
188 len = byte_pos = 0;
189 }
190 else
191 {
192 SCM_ASSERT (scm_is_string (str), str, SCM_ARG1, caller);
193
194 buf = scm_string_to_utf8 (str);
195 len = scm_c_bytevector_length (buf);
196
197 if (scm_is_eq (pos, SCM_INUM0))
198 byte_pos = 0;
199 else
200 /* Inefficient but simple way to convert the character position
201 POS into a byte position BYTE_POS. */
202 byte_pos = scm_c_string_utf8_length
203 (scm_substring (str, SCM_INUM0, pos));
204 }
205
206 stream = scm_gc_typed_calloc (struct string_port);
207 stream->bytevector = buf;
208 stream->pos = byte_pos;
209 stream->len = len;
210
211 return
212 scm_c_make_port_with_encoding (scm_string_port_type, modes, sym_UTF_8,
213 scm_i_default_port_conversion_strategy (),
214 (scm_t_bits) stream);
215 }
216
217 /* Create a new string from the buffer of PORT, a string port, converting from
218 PORT's encoding to the standard string representation. */
219 SCM
scm_strport_to_string(SCM port)220 scm_strport_to_string (SCM port)
221 {
222 signed char *ptr;
223 struct string_port *stream = (void *) SCM_STREAM (port);
224
225 scm_flush (port);
226
227 if (stream->len == 0)
228 return scm_nullstr;
229
230 ptr = SCM_BYTEVECTOR_CONTENTS (stream->bytevector);
231 return scm_from_port_stringn ((char *) ptr, stream->len, port);
232 }
233
234 SCM_DEFINE (scm_object_to_string, "object->string", 1, 1, 0,
235 (SCM obj, SCM printer),
236 "Return a Scheme string obtained by printing @var{obj}.\n"
237 "Printing function can be specified by the optional second\n"
238 "argument @var{printer} (default: @code{write}).")
239 #define FUNC_NAME s_scm_object_to_string
240 {
241 SCM port, result;
242
243 if (!SCM_UNBNDP (printer))
244 SCM_VALIDATE_PROC (2, printer);
245
246 port = scm_mkstrport (SCM_INUM0, SCM_BOOL_F, SCM_WRTNG, FUNC_NAME);
247
248 if (SCM_UNBNDP (printer))
249 scm_write (obj, port);
250 else
251 scm_call_2 (printer, obj, port);
252
253 result = scm_strport_to_string (port);
254
255 /* Explicitly close PORT so that the iconv CDs associated with it are
256 deallocated right away. This is important because CDs use a lot of
257 memory that's not visible to the GC, so not freeing them can lead
258 to almost large heap usage. See
259 <http://wingolog.org/archives/2011/02/25/ports-weaks-gc-and-dark-matter>
260 for details. */
261 scm_close_port (port);
262
263 return result;
264 }
265 #undef FUNC_NAME
266
267 SCM
scm_call_with_output_string(SCM proc)268 scm_call_with_output_string (SCM proc)
269 {
270 static SCM var = SCM_BOOL_F;
271
272 if (scm_is_false (var))
273 var = scm_c_private_lookup ("guile", "call-with-output-string");
274
275 return scm_call_1 (scm_variable_ref (var), proc);
276 }
277
278 SCM
scm_call_with_input_string(SCM string,SCM proc)279 scm_call_with_input_string (SCM string, SCM proc)
280 {
281 static SCM var = SCM_BOOL_F;
282
283 if (scm_is_false (var))
284 var = scm_c_private_lookup ("guile", "call-with-input-string");
285
286 return scm_call_2 (scm_variable_ref (var), string, proc);
287 }
288
289 SCM_DEFINE (scm_open_input_string, "open-input-string", 1, 0, 0,
290 (SCM str),
291 "Take a string and return an input port that delivers characters\n"
292 "from the string. The port can be closed by\n"
293 "@code{close-input-port}, though its storage will be reclaimed\n"
294 "by the garbage collector if it becomes inaccessible.")
295 #define FUNC_NAME s_scm_open_input_string
296 {
297 return scm_mkstrport (SCM_INUM0, str, SCM_RDNG, FUNC_NAME);
298 }
299 #undef FUNC_NAME
300
301 SCM_DEFINE (scm_open_output_string, "open-output-string", 0, 0, 0,
302 (void),
303 "Return an output port that will accumulate characters for\n"
304 "retrieval by @code{get-output-string}. The port can be closed\n"
305 "by the procedure @code{close-output-port}, though its storage\n"
306 "will be reclaimed by the garbage collector if it becomes\n"
307 "inaccessible.")
308 #define FUNC_NAME s_scm_open_output_string
309 {
310 return scm_mkstrport (SCM_INUM0, SCM_BOOL_F, SCM_WRTNG, FUNC_NAME);
311 }
312 #undef FUNC_NAME
313
314 SCM_DEFINE (scm_get_output_string, "get-output-string", 1, 0, 0,
315 (SCM port),
316 "Given an output port created by @code{open-output-string},\n"
317 "return a string consisting of the characters that have been\n"
318 "output to the port so far.")
319 #define FUNC_NAME s_scm_get_output_string
320 {
321 SCM_VALIDATE_OPOUTSTRPORT (1, port);
322 return scm_strport_to_string (port);
323 }
324 #undef FUNC_NAME
325
326
327 /* Given a null-terminated string EXPR containing a Scheme expression
328 read it, and return it as an SCM value. */
329 SCM
scm_c_read_string(const char * expr)330 scm_c_read_string (const char *expr)
331 {
332 SCM port, form;
333
334 port = scm_mkstrport (SCM_INUM0, scm_from_locale_string (expr),
335 SCM_RDNG, "scm_c_read_string");
336 form = scm_read (port);
337 scm_close_port (port);
338
339 return form;
340 }
341
342 /* Given a null-terminated string EXPR containing Scheme program text,
343 evaluate it, and return the result of the last expression evaluated. */
344 SCM
scm_c_eval_string(const char * expr)345 scm_c_eval_string (const char *expr)
346 {
347 return scm_eval_string (scm_from_locale_string (expr));
348 }
349
350 SCM
scm_c_eval_string_in_module(const char * expr,SCM module)351 scm_c_eval_string_in_module (const char *expr, SCM module)
352 {
353 return scm_eval_string_in_module (scm_from_locale_string (expr), module);
354 }
355
356
357 static SCM eval_string_var;
358 static SCM k_module;
359
360 static void
init_eval_string_var_and_k_module(void)361 init_eval_string_var_and_k_module (void)
362 {
363 eval_string_var = scm_c_public_variable ("ice-9 eval-string", "eval-string");
364 k_module = scm_from_utf8_keyword ("module");
365 }
366
367 SCM_DEFINE (scm_eval_string_in_module, "eval-string", 1, 1, 0,
368 (SCM string, SCM module),
369 "Evaluate @var{string} as the text representation of a Scheme\n"
370 "form or forms, and return whatever value they produce.\n"
371 "Evaluation takes place in the given module, or the current\n"
372 "module when no module is given.\n"
373 "While the code is evaluated, the given module is made the\n"
374 "current one. The current module is restored when this\n"
375 "procedure returns.")
376 #define FUNC_NAME s_scm_eval_string_in_module
377 {
378 static scm_i_pthread_once_t once = SCM_I_PTHREAD_ONCE_INIT;
379 scm_i_pthread_once (&once, init_eval_string_var_and_k_module);
380
381 if (SCM_UNBNDP (module))
382 module = scm_current_module ();
383 else
384 SCM_VALIDATE_MODULE (2, module);
385
386 return scm_call_3 (scm_variable_ref (eval_string_var),
387 string, k_module, module);
388 }
389 #undef FUNC_NAME
390
391 SCM
scm_eval_string(SCM string)392 scm_eval_string (SCM string)
393 {
394 return scm_eval_string_in_module (string, SCM_UNDEFINED);
395 }
396
397 static scm_t_port_type *
scm_make_string_port_type()398 scm_make_string_port_type ()
399 {
400 scm_t_port_type *ptob = scm_make_port_type ("string",
401 string_port_read,
402 string_port_write);
403 scm_set_port_seek (ptob, string_port_seek);
404 scm_set_port_truncate (ptob, string_port_truncate);
405
406 return ptob;
407 }
408
409 void
scm_init_strports()410 scm_init_strports ()
411 {
412 scm_string_port_type = scm_make_string_port_type ();
413
414 #include "strports.x"
415 }
416
417