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