*** 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
92205699 15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
73be1d9e 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 54/* NOTES:
cc95e00a
MV
55
56 We break the rules set forth by strings.h about accessing the
57 internals of strings here. We can do this since we can guarantee
58 that the string used as pt->stream is not in use by anyone else.
59 Thus, it's representation will not change asynchronously.
60
61 (Ports aren't thread-safe yet anyway...)
62
3fe6190f
GH
63 write_buf/write_end point to the ends of the allocated string.
64 read_buf/read_end in principle point to the part of the string which
65 has been written to, but this is only updated after a flush.
66 read_pos and write_pos in principle should be equal, but this is only true
61e452ba 67 when rw_active is SCM_PORT_NEITHER.
3fe6190f 68*/
1cc91f1b 69
92c2555f 70scm_t_bits scm_tc16_strport;
a98bddfd
DH
71
72
ee149d03
JB
73static int
74stfill_buffer (SCM port)
0f2d19dd 75{
92c2555f 76 scm_t_port *pt = SCM_PTAB_ENTRY (port);
ee149d03 77
ee149d03
JB
78 if (pt->read_pos >= pt->read_end)
79 return EOF;
80 else
41b0806d 81 return scm_return_first_int (*pt->read_pos, port);
0f2d19dd
JB
82}
83
3fe6190f
GH
84/* change the size of a port's string to new_size. this doesn't
85 change read_buf_size. */
754c9491 86static void
92c2555f 87st_resize_port (scm_t_port *pt, off_t new_size)
754c9491 88{
94115ae3 89 SCM old_stream = SCM_PACK (pt->stream);
cc95e00a
MV
90 const char *src = scm_i_string_chars (old_stream);
91 char *dst;
92 SCM new_stream = scm_i_make_string (new_size, &dst);
93 unsigned long int old_size = scm_i_string_length (old_stream);
c014a02e
ML
94 unsigned long int min_size = min (old_size, new_size);
95 unsigned long int i;
74a16888 96
3fe6190f
GH
97 off_t index = pt->write_pos - pt->write_buf;
98
99 pt->write_buf_size = new_size;
100
94115ae3 101 for (i = 0; i != min_size; ++i)
cc95e00a 102 dst[i] = src[i];
8824ac88
MV
103
104 scm_remember_upto_here_1 (old_stream);
754c9491 105
94115ae3 106 /* reset buffer. */
754c9491 107 {
729dbac3 108 pt->stream = SCM_UNPACK (new_stream);
5a6d139b 109 pt->read_buf = pt->write_buf = (unsigned char *)dst;
3fe6190f
GH
110 pt->read_pos = pt->write_pos = pt->write_buf + index;
111 pt->write_end = pt->write_buf + pt->write_buf_size;
112 pt->read_end = pt->read_buf + pt->read_buf_size;
754c9491
JB
113 }
114}
115
3fe6190f
GH
116/* amount by which write_buf is expanded. */
117#define SCM_WRITE_BLOCK 80
118
119/* ensure that write_pos < write_end by enlarging the buffer when
120 necessary. update read_buf to account for written chars. */
ee149d03
JB
121static void
122st_flush (SCM port)
0f2d19dd 123{
92c2555f 124 scm_t_port *pt = SCM_PTAB_ENTRY (port);
ee149d03
JB
125
126 if (pt->write_pos == pt->write_end)
127 {
3fe6190f 128 st_resize_port (pt, pt->write_buf_size + SCM_WRITE_BLOCK);
754c9491
JB
129 }
130 pt->read_pos = pt->write_pos;
3fe6190f
GH
131 if (pt->read_pos > pt->read_end)
132 {
133 pt->read_end = (unsigned char *) pt->read_pos;
134 pt->read_buf_size = pt->read_end - pt->read_buf;
135 }
61e452ba 136 pt->rw_active = SCM_PORT_NEITHER;
754c9491
JB
137}
138
31703ab8 139static void
8aa011a1 140st_write (SCM port, const void *data, size_t size)
31703ab8 141{
92c2555f 142 scm_t_port *pt = SCM_PTAB_ENTRY (port);
31703ab8
GH
143 const char *input = (char *) data;
144
145 while (size > 0)
146 {
147 int space = pt->write_end - pt->write_pos;
148 int write_len = (size > space) ? space : size;
149
4b8ec619 150 memcpy ((char *) pt->write_pos, input, write_len);
31703ab8
GH
151 pt->write_pos += write_len;
152 size -= write_len;
153 input += write_len;
154 if (write_len == space)
155 st_flush (port);
156 }
157}
158
754c9491 159static void
affc96b5 160st_end_input (SCM port, int offset)
754c9491 161{
92c2555f 162 scm_t_port *pt = SCM_PTAB_ENTRY (port);
7dcb364d 163
cd19d608
GH
164 if (pt->read_pos - pt->read_buf < offset)
165 scm_misc_error ("st_end_input", "negative position", SCM_EOL);
166
a3c8b9fc 167 pt->write_pos = (unsigned char *) (pt->read_pos = pt->read_pos - offset);
61e452ba 168 pt->rw_active = SCM_PORT_NEITHER;
754c9491
JB
169}
170
171static off_t
172st_seek (SCM port, off_t offset, int whence)
173{
92c2555f 174 scm_t_port *pt = SCM_PTAB_ENTRY (port);
754c9491
JB
175 off_t target;
176
7dcb364d
GH
177 if (pt->rw_active == SCM_PORT_READ && offset == 0 && whence == SEEK_CUR)
178 /* special case to avoid disturbing the unread-char buffer. */
754c9491 179 {
7dcb364d
GH
180 if (pt->read_buf == pt->putback_buf)
181 {
182 target = pt->saved_read_pos - pt->saved_read_buf
183 - (pt->read_end - pt->read_pos);
184 }
185 else
186 {
187 target = pt->read_pos - pt->read_buf;
188 }
754c9491 189 }
7dcb364d
GH
190 else
191 /* all other cases. */
754c9491 192 {
7dcb364d
GH
193 if (pt->rw_active == SCM_PORT_WRITE)
194 st_flush (port);
195
196 if (pt->rw_active == SCM_PORT_READ)
197 scm_end_input (port);
198
199 switch (whence)
200 {
201 case SEEK_CUR:
202 target = pt->read_pos - pt->read_buf + offset;
203 break;
204 case SEEK_END:
205 target = pt->read_end - pt->read_buf + offset;
206 break;
207 default: /* SEEK_SET */
208 target = offset;
209 break;
210 }
211
212 if (target < 0)
213 scm_misc_error ("st_seek", "negative offset", SCM_EOL);
214
215 if (target >= pt->write_buf_size)
3fe6190f 216 {
206d3de3 217 if (!(SCM_CELL_WORD_0 (port) & SCM_WRTNG))
3fe6190f 218 {
7dcb364d
GH
219 if (target > pt->write_buf_size)
220 {
221 scm_misc_error ("st_seek",
222 "seek past end of read-only strport",
223 SCM_EOL);
224 }
225 }
226 else
227 {
228 st_resize_port (pt, target + (target == pt->write_buf_size
229 ? SCM_WRITE_BLOCK
230 : 0));
3fe6190f
GH
231 }
232 }
7dcb364d
GH
233 pt->read_pos = pt->write_pos = pt->read_buf + target;
234 if (pt->read_pos > pt->read_end)
3fe6190f 235 {
7dcb364d
GH
236 pt->read_end = (unsigned char *) pt->read_pos;
237 pt->read_buf_size = pt->read_end - pt->read_buf;
3fe6190f 238 }
ee149d03 239 }
754c9491
JB
240 return target;
241}
242
243static void
affc96b5 244st_truncate (SCM port, off_t length)
754c9491 245{
92c2555f 246 scm_t_port *pt = SCM_PTAB_ENTRY (port);
3fe6190f
GH
247
248 if (length > pt->write_buf_size)
249 st_resize_port (pt, length);
250
251 pt->read_buf_size = length;
252 pt->read_end = pt->read_buf + length;
253 if (pt->read_pos > pt->read_end)
254 pt->read_pos = pt->read_end;
754c9491 255
3fe6190f
GH
256 if (pt->write_pos > pt->read_end)
257 pt->write_pos = pt->read_end;
0f2d19dd
JB
258}
259
0f2d19dd 260SCM
1bbd0b84 261scm_mkstrport (SCM pos, SCM str, long modes, const char *caller)
0f2d19dd
JB
262{
263 SCM z;
92c2555f 264 scm_t_port *pt;
e11e83f3 265 size_t str_len, c_pos;
754c9491 266
cc95e00a
MV
267 SCM_ASSERT (scm_is_string (str), str, SCM_ARG1, caller);
268
269 str_len = scm_i_string_length (str);
e11e83f3
MV
270 c_pos = scm_to_unsigned_integer (pos, 0, str_len);
271
754c9491
JB
272 if (!((modes & SCM_WRTNG) || (modes & SCM_RDNG)))
273 scm_misc_error ("scm_mkstrport", "port must read or write", SCM_EOL);
5f16b897 274
cc95e00a
MV
275 /* XXX
276
277 Make a new string to isolate us from changes to the original.
278 This is done so that we can rely on scm_i_string_chars to stay in
279 place even across SCM_TICKs.
280
281 Additionally, when we are going to write to the string, we make a
282 copy so that we can write to it without having to use
283 scm_i_string_writable_chars.
284 */
285
286 if (modes & SCM_WRTNG)
287 str = scm_c_substring_copy (str, 0, str_len);
288 else
289 str = scm_c_substring (str, 0, str_len);
290
9de87eea 291 scm_i_scm_pthread_mutex_lock (&scm_i_port_table_mutex);
da220f27
HWN
292 z = scm_new_port_table_entry (scm_tc16_strport);
293 pt = SCM_PTAB_ENTRY(z);
74a16888 294 SCM_SETSTREAM (z, SCM_UNPACK (str));
da220f27 295 SCM_SET_CELL_TYPE(z, scm_tc16_strport|modes);
cc95e00a 296 /* see above why we can use scm_i_string_chars here. */
5a6d139b 297 pt->write_buf = pt->read_buf = (unsigned char *) scm_i_string_chars (str);
e11e83f3 298 pt->read_pos = pt->write_pos = pt->read_buf + c_pos;
754c9491
JB
299 pt->write_buf_size = pt->read_buf_size = str_len;
300 pt->write_end = pt->read_end = pt->read_buf + pt->read_buf_size;
3fe6190f 301
0de97b83 302 pt->rw_random = 1;
3fe6190f 303
9de87eea 304 scm_i_pthread_mutex_unlock (&scm_i_port_table_mutex);
3fe6190f
GH
305
306 /* ensure write_pos is writable. */
754c9491
JB
307 if ((modes & SCM_WRTNG) && pt->write_pos == pt->write_end)
308 st_flush (z);
0f2d19dd
JB
309 return z;
310}
311
3fe6190f
GH
312/* create a new string from a string port's buffer. */
313SCM scm_strport_to_string (SCM port)
314{
92c2555f 315 scm_t_port *pt = SCM_PTAB_ENTRY (port);
36284627 316 SCM str;
cc95e00a
MV
317 char *dst;
318
3fe6190f
GH
319 if (pt->rw_active == SCM_PORT_WRITE)
320 st_flush (port);
36284627 321
cc95e00a
MV
322 str = scm_i_make_string (pt->read_buf_size, &dst);
323 memcpy (dst, (char *) pt->read_buf, pt->read_buf_size);
36284627
DH
324 scm_remember_upto_here_1 (port);
325 return str;
3fe6190f
GH
326}
327
fe78b6c0
KN
328SCM_DEFINE (scm_object_to_string, "object->string", 1, 1, 0,
329 (SCM obj, SCM printer),
330 "Return a Scheme string obtained by printing @var{obj}.\n"
331 "Printing function can be specified by the optional second\n"
332 "argument @var{printer} (default: @code{write}).")
1f3908c4
KN
333#define FUNC_NAME s_scm_object_to_string
334{
fe78b6c0
KN
335 SCM str, port;
336
337 if (!SCM_UNBNDP (printer))
338 SCM_VALIDATE_PROC (2, printer);
1f3908c4 339
cc95e00a 340 str = scm_c_make_string (0, SCM_UNDEFINED);
1a92274c 341 port = scm_mkstrport (SCM_INUM0, str, SCM_OPN | SCM_WRTNG, FUNC_NAME);
fe78b6c0
KN
342
343 if (SCM_UNBNDP (printer))
344 scm_write (obj, port);
345 else
fdc28395 346 scm_call_2 (printer, obj, port);
fe78b6c0 347
1f3908c4
KN
348 return scm_strport_to_string (port);
349}
350#undef FUNC_NAME
351
3b3b36dd 352SCM_DEFINE (scm_call_with_output_string, "call-with-output-string", 1, 0, 0,
1bbd0b84 353 (SCM proc),
b380b885
MD
354 "Calls the one-argument procedure @var{proc} with a newly created output\n"
355 "port. When the function returns, the string composed of the characters\n"
356 "written into the port is returned.")
1bbd0b84 357#define FUNC_NAME s_scm_call_with_output_string
0f2d19dd
JB
358{
359 SCM p;
754c9491
JB
360
361 p = scm_mkstrport (SCM_INUM0,
362 scm_make_string (SCM_INUM0, SCM_UNDEFINED),
363 SCM_OPN | SCM_WRTNG,
1bbd0b84 364 FUNC_NAME);
fdc28395 365 scm_call_1 (proc, p);
3fe6190f 366
184b85a3 367 return scm_get_output_string (p);
0f2d19dd 368}
1bbd0b84 369#undef FUNC_NAME
0f2d19dd 370
3b3b36dd 371SCM_DEFINE (scm_call_with_input_string, "call-with-input-string", 2, 0, 0,
1e6808ea
MG
372 (SCM string, SCM proc),
373 "Calls the one-argument procedure @var{proc} with a newly\n"
374 "created input port from which @var{string}'s contents may be\n"
375 "read. The value yielded by the @var{proc} is returned.")
1bbd0b84 376#define FUNC_NAME s_scm_call_with_input_string
0f2d19dd 377{
1e6808ea 378 SCM p = scm_mkstrport(SCM_INUM0, string, SCM_OPN | SCM_RDNG, FUNC_NAME);
fdc28395 379 return scm_call_1 (proc, p);
0f2d19dd 380}
1bbd0b84 381#undef FUNC_NAME
0f2d19dd 382
e87a03fc
MG
383SCM_DEFINE (scm_open_input_string, "open-input-string", 1, 0, 0,
384 (SCM str),
1e6808ea
MG
385 "Take a string and return an input port that delivers characters\n"
386 "from the string. The port can be closed by\n"
e87a03fc
MG
387 "@code{close-input-port}, though its storage will be reclaimed\n"
388 "by the garbage collector if it becomes inaccessible.")
389#define FUNC_NAME s_scm_open_input_string
390{
391 SCM p = scm_mkstrport(SCM_INUM0, str, SCM_OPN | SCM_RDNG, FUNC_NAME);
392 return p;
393}
394#undef FUNC_NAME
395
396SCM_DEFINE (scm_open_output_string, "open-output-string", 0, 0, 0,
397 (void),
1e6808ea 398 "Return an output port that will accumulate characters for\n"
e87a03fc
MG
399 "retrieval by @code{get-output-string}. The port can be closed\n"
400 "by the procedure @code{close-output-port}, though its storage\n"
401 "will be reclaimed by the garbage collector if it becomes\n"
402 "inaccessible.")
403#define FUNC_NAME s_scm_open_output_string
404{
405 SCM p;
406
407 p = scm_mkstrport (SCM_INUM0,
408 scm_make_string (SCM_INUM0, SCM_UNDEFINED),
409 SCM_OPN | SCM_WRTNG,
410 FUNC_NAME);
411 return p;
412}
413#undef FUNC_NAME
414
415SCM_DEFINE (scm_get_output_string, "get-output-string", 1, 0, 0,
416 (SCM port),
417 "Given an output port created by @code{open-output-string},\n"
1e6808ea 418 "return a string consisting of the characters that have been\n"
e87a03fc
MG
419 "output to the port so far.")
420#define FUNC_NAME s_scm_get_output_string
421{
422 SCM_VALIDATE_OPOUTSTRPORT (1, port);
423 return scm_strport_to_string (port);
424}
425#undef FUNC_NAME
1cc91f1b 426
cd07a097 427
a8aa30d8
MD
428/* Given a null-terminated string EXPR containing a Scheme expression
429 read it, and return it as an SCM value. */
430SCM
ca13a04a 431scm_c_read_string (const char *expr)
a8aa30d8 432{
3fe6190f 433 SCM port = scm_mkstrport (SCM_INUM0,
cc95e00a 434 scm_from_locale_string (expr),
a8aa30d8 435 SCM_OPN | SCM_RDNG,
ca13a04a 436 "scm_c_read_string");
a8aa30d8
MD
437 SCM form;
438
439 /* Read expressions from that port; ignore the values. */
deca31e1 440 form = scm_read (port);
a8aa30d8
MD
441
442 scm_close_port (port);
443 return form;
444}
445
cd07a097 446/* Given a null-terminated string EXPR containing Scheme program text,
a8aa30d8
MD
447 evaluate it, and return the result of the last expression evaluated. */
448SCM
ca13a04a 449scm_c_eval_string (const char *expr)
cd07a097 450{
cc95e00a 451 return scm_eval_string (scm_from_locale_string (expr));
b377f53e
JB
452}
453
209b52fe
MV
454SCM
455scm_c_eval_string_in_module (const char *expr, SCM module)
456{
cc95e00a 457 return scm_eval_string_in_module (scm_from_locale_string (expr), module);
209b52fe
MV
458}
459
460
96e83482
MV
461static SCM
462inner_eval_string (void *data)
b377f53e 463{
96e83482 464 SCM port = (SCM)data;
cd07a097 465 SCM form;
b377f53e 466 SCM ans = SCM_UNSPECIFIED;
cd07a097
JB
467
468 /* Read expressions from that port; ignore the values. */
0c32d76c 469 while (!SCM_EOF_OBJECT_P (form = scm_read (port)))
96e83482 470 ans = scm_primitive_eval_x (form);
cd07a097 471
0d7368d7
JB
472 /* Don't close the port here; if we re-enter this function via a
473 continuation, then the next time we enter it, we'll get an error.
474 It's a string port anyway, so there's no advantage to closing it
475 early. */
476
a8aa30d8 477 return ans;
cd07a097 478}
96e83482 479
209b52fe
MV
480SCM_DEFINE (scm_eval_string_in_module, "eval-string", 1, 1, 0,
481 (SCM string, SCM module),
96e83482
MV
482 "Evaluate @var{string} as the text representation of a Scheme\n"
483 "form or forms, and return whatever value they produce.\n"
209b52fe
MV
484 "Evaluation takes place in the given module, or the current\n"
485 "module when no module is given.\n"
486 "While the code is evaluated, the given module is made the\n"
487 "current one. The current module is restored when this\n"
488 "procedure returns.")
489#define FUNC_NAME s_scm_eval_string_in_module
96e83482
MV
490{
491 SCM port = scm_mkstrport (SCM_INUM0, string, SCM_OPN | SCM_RDNG,
209b52fe
MV
492 FUNC_NAME);
493 if (SCM_UNBNDP (module))
494 module = scm_current_module ();
aeec5be1
MV
495 else
496 SCM_VALIDATE_MODULE (2, module);
209b52fe 497 return scm_c_call_with_current_module (module,
96e83482
MV
498 inner_eval_string, (void *)port);
499}
1bbd0b84 500#undef FUNC_NAME
cd07a097 501
209b52fe
MV
502SCM
503scm_eval_string (SCM string)
504{
505 return scm_eval_string_in_module (string, SCM_UNDEFINED);
506}
507
92c2555f 508static scm_t_bits
0b6881fa 509scm_make_stptob ()
0f2d19dd 510{
92c2555f 511 scm_t_bits tc = scm_make_port_type ("string", stfill_buffer, st_write);
a98bddfd 512
6c747373 513 scm_set_port_mark (tc, scm_markstream);
affc96b5
GH
514 scm_set_port_end_input (tc, st_end_input);
515 scm_set_port_flush (tc, st_flush);
6c747373 516 scm_set_port_seek (tc, st_seek);
affc96b5 517 scm_set_port_truncate (tc, st_truncate);
a98bddfd
DH
518
519 return tc;
0f2d19dd
JB
520}
521
0f2d19dd
JB
522void
523scm_init_strports ()
0f2d19dd 524{
a98bddfd
DH
525 scm_tc16_strport = scm_make_stptob ();
526
a0599745 527#include "libguile/strports.x"
0f2d19dd
JB
528}
529
89e00824
ML
530
531/*
532 Local Variables:
533 c-file-style: "gnu"
534 End:
535*/