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