*** empty log message ***
[bpt/guile.git] / libguile / strports.c
CommitLineData
b9ad392e 1/* Copyright (C) 1995,1996,1998,1999,2000,2001,2002, 2003 Free Software Foundation, Inc.
0f2d19dd 2 *
73be1d9e
MV
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
0f2d19dd 7 *
73be1d9e
MV
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
0f2d19dd 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
1bbd0b84 17
1bbd0b84 18
0f2d19dd
JB
19\f
20
c986274f
RB
21#if HAVE_CONFIG_H
22# include <config.h>
23#endif
24
a0599745 25#include "libguile/_scm.h"
681b9005
MD
26
27#include <stdio.h>
28#ifdef HAVE_UNISTD_H
29#include <unistd.h>
30#endif
31
a0599745
MD
32#include "libguile/unif.h"
33#include "libguile/eval.h"
34#include "libguile/ports.h"
35#include "libguile/read.h"
36#include "libguile/root.h"
37#include "libguile/strings.h"
07bcf91d 38#include "libguile/modules.h"
fe78b6c0 39#include "libguile/validate.h"
ca13a04a 40#include "libguile/deprecation.h"
20e6290e 41
a0599745 42#include "libguile/strports.h"
0f2d19dd 43
95b88819
GH
44#ifdef HAVE_STRING_H
45#include <string.h>
46#endif
47
0f2d19dd
JB
48\f
49
50/* {Ports - string ports}
51 *
52 */
53
3fe6190f
GH
54/* NOTES:
55 write_buf/write_end point to the ends of the allocated string.
56 read_buf/read_end in principle point to the part of the string which
57 has been written to, but this is only updated after a flush.
58 read_pos and write_pos in principle should be equal, but this is only true
61e452ba 59 when rw_active is SCM_PORT_NEITHER.
3fe6190f 60*/
1cc91f1b 61
92c2555f 62scm_t_bits scm_tc16_strport;
a98bddfd
DH
63
64
ee149d03
JB
65static int
66stfill_buffer (SCM port)
0f2d19dd 67{
92c2555f 68 scm_t_port *pt = SCM_PTAB_ENTRY (port);
ee149d03 69
ee149d03
JB
70 if (pt->read_pos >= pt->read_end)
71 return EOF;
72 else
41b0806d 73 return scm_return_first_int (*pt->read_pos, port);
0f2d19dd
JB
74}
75
3fe6190f
GH
76/* change the size of a port's string to new_size. this doesn't
77 change read_buf_size. */
754c9491 78static void
92c2555f 79st_resize_port (scm_t_port *pt, off_t new_size)
754c9491 80{
94115ae3 81 SCM old_stream = SCM_PACK (pt->stream);
be54b15d 82 SCM new_stream = scm_allocate_string (new_size);
c014a02e
ML
83 unsigned long int old_size = SCM_STRING_LENGTH (old_stream);
84 unsigned long int min_size = min (old_size, new_size);
85 unsigned long int i;
74a16888 86
3fe6190f
GH
87 off_t index = pt->write_pos - pt->write_buf;
88
89 pt->write_buf_size = new_size;
90
94115ae3
DH
91 for (i = 0; i != min_size; ++i)
92 SCM_STRING_CHARS (new_stream) [i] = SCM_STRING_CHARS (old_stream) [i];
754c9491 93
94115ae3 94 /* reset buffer. */
754c9491 95 {
729dbac3 96 pt->stream = SCM_UNPACK (new_stream);
94115ae3 97 pt->read_buf = pt->write_buf = SCM_STRING_UCHARS (new_stream);
3fe6190f
GH
98 pt->read_pos = pt->write_pos = pt->write_buf + index;
99 pt->write_end = pt->write_buf + pt->write_buf_size;
100 pt->read_end = pt->read_buf + pt->read_buf_size;
754c9491
JB
101 }
102}
103
3fe6190f
GH
104/* amount by which write_buf is expanded. */
105#define SCM_WRITE_BLOCK 80
106
107/* ensure that write_pos < write_end by enlarging the buffer when
108 necessary. update read_buf to account for written chars. */
ee149d03
JB
109static void
110st_flush (SCM port)
0f2d19dd 111{
92c2555f 112 scm_t_port *pt = SCM_PTAB_ENTRY (port);
ee149d03
JB
113
114 if (pt->write_pos == pt->write_end)
115 {
3fe6190f 116 st_resize_port (pt, pt->write_buf_size + SCM_WRITE_BLOCK);
754c9491
JB
117 }
118 pt->read_pos = pt->write_pos;
3fe6190f
GH
119 if (pt->read_pos > pt->read_end)
120 {
121 pt->read_end = (unsigned char *) pt->read_pos;
122 pt->read_buf_size = pt->read_end - pt->read_buf;
123 }
61e452ba 124 pt->rw_active = SCM_PORT_NEITHER;
754c9491
JB
125}
126
31703ab8 127static void
8aa011a1 128st_write (SCM port, const void *data, size_t size)
31703ab8 129{
92c2555f 130 scm_t_port *pt = SCM_PTAB_ENTRY (port);
31703ab8
GH
131 const char *input = (char *) data;
132
133 while (size > 0)
134 {
135 int space = pt->write_end - pt->write_pos;
136 int write_len = (size > space) ? space : size;
137
4b8ec619 138 memcpy ((char *) pt->write_pos, input, write_len);
31703ab8
GH
139 pt->write_pos += write_len;
140 size -= write_len;
141 input += write_len;
142 if (write_len == space)
143 st_flush (port);
144 }
145}
146
754c9491 147static void
affc96b5 148st_end_input (SCM port, int offset)
754c9491 149{
92c2555f 150 scm_t_port *pt = SCM_PTAB_ENTRY (port);
7dcb364d 151
cd19d608
GH
152 if (pt->read_pos - pt->read_buf < offset)
153 scm_misc_error ("st_end_input", "negative position", SCM_EOL);
154
a3c8b9fc 155 pt->write_pos = (unsigned char *) (pt->read_pos = pt->read_pos - offset);
61e452ba 156 pt->rw_active = SCM_PORT_NEITHER;
754c9491
JB
157}
158
159static off_t
160st_seek (SCM port, off_t offset, int whence)
161{
92c2555f 162 scm_t_port *pt = SCM_PTAB_ENTRY (port);
754c9491
JB
163 off_t target;
164
7dcb364d
GH
165 if (pt->rw_active == SCM_PORT_READ && offset == 0 && whence == SEEK_CUR)
166 /* special case to avoid disturbing the unread-char buffer. */
754c9491 167 {
7dcb364d
GH
168 if (pt->read_buf == pt->putback_buf)
169 {
170 target = pt->saved_read_pos - pt->saved_read_buf
171 - (pt->read_end - pt->read_pos);
172 }
173 else
174 {
175 target = pt->read_pos - pt->read_buf;
176 }
754c9491 177 }
7dcb364d
GH
178 else
179 /* all other cases. */
754c9491 180 {
7dcb364d
GH
181 if (pt->rw_active == SCM_PORT_WRITE)
182 st_flush (port);
183
184 if (pt->rw_active == SCM_PORT_READ)
185 scm_end_input (port);
186
187 switch (whence)
188 {
189 case SEEK_CUR:
190 target = pt->read_pos - pt->read_buf + offset;
191 break;
192 case SEEK_END:
193 target = pt->read_end - pt->read_buf + offset;
194 break;
195 default: /* SEEK_SET */
196 target = offset;
197 break;
198 }
199
200 if (target < 0)
201 scm_misc_error ("st_seek", "negative offset", SCM_EOL);
202
203 if (target >= pt->write_buf_size)
3fe6190f 204 {
206d3de3 205 if (!(SCM_CELL_WORD_0 (port) & SCM_WRTNG))
3fe6190f 206 {
7dcb364d
GH
207 if (target > pt->write_buf_size)
208 {
209 scm_misc_error ("st_seek",
210 "seek past end of read-only strport",
211 SCM_EOL);
212 }
213 }
214 else
215 {
216 st_resize_port (pt, target + (target == pt->write_buf_size
217 ? SCM_WRITE_BLOCK
218 : 0));
3fe6190f
GH
219 }
220 }
7dcb364d
GH
221 pt->read_pos = pt->write_pos = pt->read_buf + target;
222 if (pt->read_pos > pt->read_end)
3fe6190f 223 {
7dcb364d
GH
224 pt->read_end = (unsigned char *) pt->read_pos;
225 pt->read_buf_size = pt->read_end - pt->read_buf;
3fe6190f 226 }
ee149d03 227 }
754c9491
JB
228 return target;
229}
230
231static void
affc96b5 232st_truncate (SCM port, off_t length)
754c9491 233{
92c2555f 234 scm_t_port *pt = SCM_PTAB_ENTRY (port);
3fe6190f
GH
235
236 if (length > pt->write_buf_size)
237 st_resize_port (pt, length);
238
239 pt->read_buf_size = length;
240 pt->read_end = pt->read_buf + length;
241 if (pt->read_pos > pt->read_end)
242 pt->read_pos = pt->read_end;
754c9491 243
3fe6190f
GH
244 if (pt->write_pos > pt->read_end)
245 pt->write_pos = pt->read_end;
0f2d19dd
JB
246}
247
0f2d19dd 248SCM
1bbd0b84 249scm_mkstrport (SCM pos, SCM str, long modes, const char *caller)
0f2d19dd
JB
250{
251 SCM z;
92c2555f 252 scm_t_port *pt;
e11e83f3 253 size_t str_len, c_pos;
754c9491 254
ebea155a
MV
255 SCM_ASSERT (SCM_I_STRINGP (str), str, SCM_ARG1, caller);
256 str_len = SCM_I_STRING_LENGTH (str);
e11e83f3
MV
257 c_pos = scm_to_unsigned_integer (pos, 0, str_len);
258
754c9491
JB
259 if (!((modes & SCM_WRTNG) || (modes & SCM_RDNG)))
260 scm_misc_error ("scm_mkstrport", "port must read or write", SCM_EOL);
5f16b897 261
b9ad392e 262 scm_mutex_lock (&scm_i_port_table_mutex);
da220f27
HWN
263 z = scm_new_port_table_entry (scm_tc16_strport);
264 pt = SCM_PTAB_ENTRY(z);
74a16888 265 SCM_SETSTREAM (z, SCM_UNPACK (str));
da220f27 266 SCM_SET_CELL_TYPE(z, scm_tc16_strport|modes);
ebea155a 267 pt->write_buf = pt->read_buf = SCM_I_STRING_UCHARS (str);
e11e83f3 268 pt->read_pos = pt->write_pos = pt->read_buf + c_pos;
754c9491
JB
269 pt->write_buf_size = pt->read_buf_size = str_len;
270 pt->write_end = pt->read_end = pt->read_buf + pt->read_buf_size;
3fe6190f 271
0de97b83 272 pt->rw_random = 1;
3fe6190f 273
b9ad392e 274 scm_mutex_unlock (&scm_i_port_table_mutex);
3fe6190f
GH
275
276 /* ensure write_pos is writable. */
754c9491
JB
277 if ((modes & SCM_WRTNG) && pt->write_pos == pt->write_end)
278 st_flush (z);
0f2d19dd
JB
279 return z;
280}
281
3fe6190f
GH
282/* create a new string from a string port's buffer. */
283SCM scm_strport_to_string (SCM port)
284{
92c2555f 285 scm_t_port *pt = SCM_PTAB_ENTRY (port);
36284627 286 SCM str;
3fe6190f
GH
287
288 if (pt->rw_active == SCM_PORT_WRITE)
289 st_flush (port);
36284627
DH
290
291 str = scm_mem2string ((char *) pt->read_buf, pt->read_buf_size);
292 scm_remember_upto_here_1 (port);
293 return str;
3fe6190f
GH
294}
295
fe78b6c0
KN
296SCM_DEFINE (scm_object_to_string, "object->string", 1, 1, 0,
297 (SCM obj, SCM printer),
298 "Return a Scheme string obtained by printing @var{obj}.\n"
299 "Printing function can be specified by the optional second\n"
300 "argument @var{printer} (default: @code{write}).")
1f3908c4
KN
301#define FUNC_NAME s_scm_object_to_string
302{
fe78b6c0
KN
303 SCM str, port;
304
305 if (!SCM_UNBNDP (printer))
306 SCM_VALIDATE_PROC (2, printer);
1f3908c4 307
be54b15d 308 str = scm_allocate_string (0);
1a92274c 309 port = scm_mkstrport (SCM_INUM0, str, SCM_OPN | SCM_WRTNG, FUNC_NAME);
fe78b6c0
KN
310
311 if (SCM_UNBNDP (printer))
312 scm_write (obj, port);
313 else
fdc28395 314 scm_call_2 (printer, obj, port);
fe78b6c0 315
1f3908c4
KN
316 return scm_strport_to_string (port);
317}
318#undef FUNC_NAME
319
3b3b36dd 320SCM_DEFINE (scm_call_with_output_string, "call-with-output-string", 1, 0, 0,
1bbd0b84 321 (SCM proc),
b380b885
MD
322 "Calls the one-argument procedure @var{proc} with a newly created output\n"
323 "port. When the function returns, the string composed of the characters\n"
324 "written into the port is returned.")
1bbd0b84 325#define FUNC_NAME s_scm_call_with_output_string
0f2d19dd
JB
326{
327 SCM p;
754c9491
JB
328
329 p = scm_mkstrport (SCM_INUM0,
330 scm_make_string (SCM_INUM0, SCM_UNDEFINED),
331 SCM_OPN | SCM_WRTNG,
1bbd0b84 332 FUNC_NAME);
fdc28395 333 scm_call_1 (proc, p);
3fe6190f 334
184b85a3 335 return scm_get_output_string (p);
0f2d19dd 336}
1bbd0b84 337#undef FUNC_NAME
0f2d19dd 338
3b3b36dd 339SCM_DEFINE (scm_call_with_input_string, "call-with-input-string", 2, 0, 0,
1e6808ea
MG
340 (SCM string, SCM proc),
341 "Calls the one-argument procedure @var{proc} with a newly\n"
342 "created input port from which @var{string}'s contents may be\n"
343 "read. The value yielded by the @var{proc} is returned.")
1bbd0b84 344#define FUNC_NAME s_scm_call_with_input_string
0f2d19dd 345{
1e6808ea 346 SCM p = scm_mkstrport(SCM_INUM0, string, SCM_OPN | SCM_RDNG, FUNC_NAME);
fdc28395 347 return scm_call_1 (proc, p);
0f2d19dd 348}
1bbd0b84 349#undef FUNC_NAME
0f2d19dd 350
e87a03fc
MG
351SCM_DEFINE (scm_open_input_string, "open-input-string", 1, 0, 0,
352 (SCM str),
1e6808ea
MG
353 "Take a string and return an input port that delivers characters\n"
354 "from the string. The port can be closed by\n"
e87a03fc
MG
355 "@code{close-input-port}, though its storage will be reclaimed\n"
356 "by the garbage collector if it becomes inaccessible.")
357#define FUNC_NAME s_scm_open_input_string
358{
359 SCM p = scm_mkstrport(SCM_INUM0, str, SCM_OPN | SCM_RDNG, FUNC_NAME);
360 return p;
361}
362#undef FUNC_NAME
363
364SCM_DEFINE (scm_open_output_string, "open-output-string", 0, 0, 0,
365 (void),
1e6808ea 366 "Return an output port that will accumulate characters for\n"
e87a03fc
MG
367 "retrieval by @code{get-output-string}. The port can be closed\n"
368 "by the procedure @code{close-output-port}, though its storage\n"
369 "will be reclaimed by the garbage collector if it becomes\n"
370 "inaccessible.")
371#define FUNC_NAME s_scm_open_output_string
372{
373 SCM p;
374
375 p = scm_mkstrport (SCM_INUM0,
376 scm_make_string (SCM_INUM0, SCM_UNDEFINED),
377 SCM_OPN | SCM_WRTNG,
378 FUNC_NAME);
379 return p;
380}
381#undef FUNC_NAME
382
383SCM_DEFINE (scm_get_output_string, "get-output-string", 1, 0, 0,
384 (SCM port),
385 "Given an output port created by @code{open-output-string},\n"
1e6808ea 386 "return a string consisting of the characters that have been\n"
e87a03fc
MG
387 "output to the port so far.")
388#define FUNC_NAME s_scm_get_output_string
389{
390 SCM_VALIDATE_OPOUTSTRPORT (1, port);
391 return scm_strport_to_string (port);
392}
393#undef FUNC_NAME
1cc91f1b 394
cd07a097 395
a8aa30d8
MD
396/* Given a null-terminated string EXPR containing a Scheme expression
397 read it, and return it as an SCM value. */
398SCM
ca13a04a 399scm_c_read_string (const char *expr)
a8aa30d8 400{
3fe6190f 401 SCM port = scm_mkstrport (SCM_INUM0,
a8aa30d8
MD
402 scm_makfrom0str (expr),
403 SCM_OPN | SCM_RDNG,
ca13a04a 404 "scm_c_read_string");
a8aa30d8
MD
405 SCM form;
406
407 /* Read expressions from that port; ignore the values. */
deca31e1 408 form = scm_read (port);
a8aa30d8
MD
409
410 scm_close_port (port);
411 return form;
412}
413
cd07a097 414/* Given a null-terminated string EXPR containing Scheme program text,
a8aa30d8
MD
415 evaluate it, and return the result of the last expression evaluated. */
416SCM
ca13a04a 417scm_c_eval_string (const char *expr)
cd07a097 418{
b377f53e
JB
419 return scm_eval_string (scm_makfrom0str (expr));
420}
421
209b52fe
MV
422SCM
423scm_c_eval_string_in_module (const char *expr, SCM module)
424{
425 return scm_eval_string_in_module (scm_makfrom0str (expr), module);
426}
427
428
96e83482
MV
429static SCM
430inner_eval_string (void *data)
b377f53e 431{
96e83482 432 SCM port = (SCM)data;
cd07a097 433 SCM form;
b377f53e 434 SCM ans = SCM_UNSPECIFIED;
cd07a097
JB
435
436 /* Read expressions from that port; ignore the values. */
0c32d76c 437 while (!SCM_EOF_OBJECT_P (form = scm_read (port)))
96e83482 438 ans = scm_primitive_eval_x (form);
cd07a097 439
0d7368d7
JB
440 /* Don't close the port here; if we re-enter this function via a
441 continuation, then the next time we enter it, we'll get an error.
442 It's a string port anyway, so there's no advantage to closing it
443 early. */
444
a8aa30d8 445 return ans;
cd07a097 446}
96e83482 447
209b52fe
MV
448SCM_DEFINE (scm_eval_string_in_module, "eval-string", 1, 1, 0,
449 (SCM string, SCM module),
96e83482
MV
450 "Evaluate @var{string} as the text representation of a Scheme\n"
451 "form or forms, and return whatever value they produce.\n"
209b52fe
MV
452 "Evaluation takes place in the given module, or the current\n"
453 "module when no module is given.\n"
454 "While the code is evaluated, the given module is made the\n"
455 "current one. The current module is restored when this\n"
456 "procedure returns.")
457#define FUNC_NAME s_scm_eval_string_in_module
96e83482
MV
458{
459 SCM port = scm_mkstrport (SCM_INUM0, string, SCM_OPN | SCM_RDNG,
209b52fe
MV
460 FUNC_NAME);
461 if (SCM_UNBNDP (module))
462 module = scm_current_module ();
aeec5be1
MV
463 else
464 SCM_VALIDATE_MODULE (2, module);
209b52fe 465 return scm_c_call_with_current_module (module,
96e83482
MV
466 inner_eval_string, (void *)port);
467}
1bbd0b84 468#undef FUNC_NAME
cd07a097 469
209b52fe
MV
470SCM
471scm_eval_string (SCM string)
472{
473 return scm_eval_string_in_module (string, SCM_UNDEFINED);
474}
475
92c2555f 476static scm_t_bits
0b6881fa 477scm_make_stptob ()
0f2d19dd 478{
92c2555f 479 scm_t_bits tc = scm_make_port_type ("string", stfill_buffer, st_write);
a98bddfd 480
6c747373 481 scm_set_port_mark (tc, scm_markstream);
affc96b5
GH
482 scm_set_port_end_input (tc, st_end_input);
483 scm_set_port_flush (tc, st_flush);
6c747373 484 scm_set_port_seek (tc, st_seek);
affc96b5 485 scm_set_port_truncate (tc, st_truncate);
a98bddfd
DH
486
487 return tc;
0f2d19dd
JB
488}
489
0f2d19dd
JB
490void
491scm_init_strports ()
0f2d19dd 492{
a98bddfd
DH
493 scm_tc16_strport = scm_make_stptob ();
494
a0599745 495#include "libguile/strports.x"
0f2d19dd
JB
496}
497
89e00824
ML
498
499/*
500 Local Variables:
501 c-file-style: "gnu"
502 End:
503*/