1999-07-04 Gary Houston <ghouston@easynet.co.uk>
[bpt/guile.git] / libguile / strports.c
CommitLineData
754c9491 1/* Copyright (C) 1995,1996,1998,1999 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. */
0f2d19dd
JB
41\f
42
43#include <stdio.h>
44#include "_scm.h"
20e6290e
JB
45#include "unif.h"
46#include "eval.h"
cd07a097 47#include "read.h"
20e6290e
JB
48
49#include "strports.h"
0f2d19dd 50
95b88819
GH
51#ifdef HAVE_STRING_H
52#include <string.h>
53#endif
54
0f2d19dd
JB
55\f
56
57/* {Ports - string ports}
58 *
59 */
60
1cc91f1b 61
0f2d19dd 62static int
0f88a8f3 63prinstpt (SCM exp, SCM port, scm_print_state *pstate)
0f2d19dd
JB
64{
65 scm_prinport (exp, port, "string");
66 return !0;
67}
68
ee149d03
JB
69static int
70stfill_buffer (SCM port)
0f2d19dd 71{
ee149d03 72 SCM str = SCM_STREAM (port);
754c9491 73 scm_port *pt = SCM_PTAB_ENTRY (port);
ee149d03
JB
74
75 pt->read_buf = SCM_ROCHARS (str);
76 pt->read_buf_size = SCM_ROLENGTH (str);
77 pt->read_end = pt->read_buf + pt->read_buf_size;
78
79 if (pt->read_pos >= pt->read_end)
80 return EOF;
81 else
82 return scm_return_first (*(pt->read_pos++), port);
0f2d19dd
JB
83}
84
754c9491
JB
85static void
86st_grow_port (scm_port *pt, off_t add)
87{
88 off_t new_size = pt->write_buf_size + add;
89
90 scm_vector_set_length_x (pt->stream,
91 SCM_MAKINUM (new_size));
92 pt->read_buf_size = pt->write_buf_size = new_size;
93 /* reset buffer in case reallocation moved the string. */
94 {
95 off_t index = pt->write_pos - pt->write_buf;
96
97 pt->read_buf = pt->write_buf = SCM_CHARS (pt->stream);
98 pt->write_pos = pt->write_buf + index;
99 pt->read_end = pt->write_end = pt->write_buf + pt->write_buf_size;
100 }
101}
102
ee149d03
JB
103static void
104st_flush (SCM port)
0f2d19dd 105{
754c9491 106 scm_port *pt = SCM_PTAB_ENTRY (port);
ee149d03
JB
107
108 if (pt->write_pos == pt->write_end)
109 {
754c9491
JB
110 st_grow_port (pt, 1);
111 }
112 pt->read_pos = pt->write_pos;
113 pt->rw_active = 0;
114}
115
116static void
283a1a0e 117st_read_flush (SCM port, int offset)
754c9491
JB
118{
119 scm_port *pt = SCM_PTAB_ENTRY (port);
120
121 pt->write_pos = (unsigned char *) pt->read_pos;
122 pt->rw_active = 0;
123}
124
125static off_t
126st_seek (SCM port, off_t offset, int whence)
127{
128 scm_port *pt = SCM_PTAB_ENTRY (port);
129 off_t target;
130
131 switch (whence)
132 {
133 case SEEK_CUR:
134 if (SCM_CAR (port) & SCM_WRTNG)
135 target = pt->write_pos - pt->write_buf + offset;
136 else
137 target = pt->read_pos - pt->read_buf + offset;
138 break;
139 case SEEK_END:
140 target = pt->write_end - pt->write_buf + offset;
141 break;
142 default: /* SEEK_SET */
143 target = offset;
144 break;
145 }
146 if (target < 0)
147 scm_misc_error ("st_seek", "negative offset",
148 scm_cons (SCM_MAKINUM (target), EOF));
149 if (target > pt->read_buf_size)
150 {
151 st_grow_port (pt, target - pt->read_buf_size);
ee149d03 152 }
754c9491
JB
153 pt->read_pos = pt->write_pos = pt->read_buf + target;
154 return target;
155}
156
157static void
158st_ftruncate (SCM port, off_t length)
159{
160 scm_port *pt = SCM_PTAB_ENTRY (port);
161 off_t old_len = pt->write_end - pt->write_buf;
162
163 if (length != old_len)
164 st_grow_port (pt, length - old_len);
0f2d19dd
JB
165}
166
0f2d19dd
JB
167SCM
168scm_mkstrport (pos, str, modes, caller)
169 SCM pos;
170 SCM str;
171 long modes;
3eeba8d4 172 const char * caller;
0f2d19dd
JB
173{
174 SCM z;
754c9491
JB
175 scm_port *pt;
176 int str_len;
177
178 SCM_ASSERT (SCM_INUMP(pos) && SCM_INUM(pos) >= 0, pos, SCM_ARG1, caller);
179 SCM_ASSERT (SCM_NIMP(str) && SCM_ROSTRINGP(str), str, SCM_ARG1, caller);
180 str_len = SCM_ROLENGTH (str);
181 if (SCM_INUM (pos) > str_len)
182 scm_out_of_range (caller, pos);
183 if (!((modes & SCM_WRTNG) || (modes & SCM_RDNG)))
184 scm_misc_error ("scm_mkstrport", "port must read or write", SCM_EOL);
0f2d19dd
JB
185 SCM_NEWCELL (z);
186 SCM_DEFER_INTS;
187 pt = scm_add_to_port_table (z);
a6c64c3c 188 SCM_SETCAR (z, scm_tc16_strport | modes);
0f2d19dd 189 SCM_SETPTAB_ENTRY (z, pt);
754c9491 190 SCM_SETSTREAM (z, str);
ee149d03 191 pt->write_buf = pt->read_buf = SCM_ROCHARS (str);
754c9491
JB
192 pt->read_pos = pt->write_pos = pt->read_buf + SCM_INUM (pos);
193 pt->write_buf_size = pt->read_buf_size = str_len;
194 pt->write_end = pt->read_end = pt->read_buf + pt->read_buf_size;
195 pt->rw_random = (modes & SCM_RDNG) && (modes & SCM_WRTNG);
0f2d19dd 196 SCM_ALLOW_INTS;
754c9491
JB
197 if ((modes & SCM_WRTNG) && pt->write_pos == pt->write_end)
198 st_flush (z);
0f2d19dd
JB
199 return z;
200}
201
202SCM_PROC(s_call_with_output_string, "call-with-output-string", 1, 0, 0, scm_call_with_output_string);
1cc91f1b 203
0f2d19dd
JB
204SCM
205scm_call_with_output_string (proc)
206 SCM proc;
0f2d19dd
JB
207{
208 SCM p;
754c9491
JB
209
210 p = scm_mkstrport (SCM_INUM0,
211 scm_make_string (SCM_INUM0, SCM_UNDEFINED),
212 SCM_OPN | SCM_WRTNG,
213 s_call_with_output_string);
0f2d19dd
JB
214 scm_apply (proc, p, scm_listofnull);
215 {
216 SCM answer;
ee149d03 217
754c9491
JB
218 /* can't use pt->write_pos, in case port position was changed with
219 seek.
220
221 The port buffer protocol promises that you can always store at
222 least one character at write_pos. This means that the
223 underlying string always has one spare character at the end,
224 that the user didn't write. Make sure we don't include that in
225 the result. */
ee149d03 226 answer = scm_makfromstr (SCM_CHARS (SCM_STREAM (p)),
754c9491 227 SCM_LENGTH (SCM_STREAM (p)) - 1,
0f2d19dd 228 0);
0f2d19dd
JB
229 return answer;
230 }
231}
232
233
234
235/* Return a Scheme string obtained by printing a given object.
236 */
237
1cc91f1b 238
0f2d19dd
JB
239SCM
240scm_strprint_obj (obj)
241 SCM obj;
0f2d19dd
JB
242{
243 SCM str;
244 SCM port;
245
246 str = scm_makstr (64, 0);
247 port = scm_mkstrport (SCM_MAKINUM (0), str, SCM_OPN | SCM_WRTNG, "scm_strprint_obj");
87818069 248 scm_prin1 (obj, port, 1);
0f2d19dd 249 {
6c951427 250 scm_port *pt = SCM_PTAB_ENTRY (port);
0f2d19dd 251 SCM answer;
ee149d03
JB
252
253 answer = scm_makfromstr (SCM_CHARS (SCM_STREAM (port)),
254 pt->write_pos - pt->write_buf,
0f2d19dd 255 0);
0f2d19dd
JB
256 return answer;
257 }
258}
259
260
261
262
263SCM_PROC(s_call_with_input_string, "call-with-input-string", 2, 0, 0, scm_call_with_input_string);
1cc91f1b 264
0f2d19dd
JB
265SCM
266scm_call_with_input_string (str, proc)
267 SCM str;
268 SCM proc;
0f2d19dd
JB
269{
270 SCM p = scm_mkstrport(SCM_INUM0, str, SCM_OPN | SCM_RDNG, s_call_with_input_string);
271 return scm_apply (proc, p, scm_listofnull);
272}
273
1cc91f1b 274
cd07a097 275
a8aa30d8
MD
276/* Given a null-terminated string EXPR containing a Scheme expression
277 read it, and return it as an SCM value. */
278SCM
279scm_read_0str (expr)
280 char *expr;
281{
282 SCM port = scm_mkstrport (SCM_MAKINUM (0),
283 scm_makfrom0str (expr),
284 SCM_OPN | SCM_RDNG,
285 "scm_eval_0str");
286 SCM form;
287
288 /* Read expressions from that port; ignore the values. */
deca31e1 289 form = scm_read (port);
a8aa30d8
MD
290
291 scm_close_port (port);
292 return form;
293}
294
cd07a097 295/* Given a null-terminated string EXPR containing Scheme program text,
a8aa30d8
MD
296 evaluate it, and return the result of the last expression evaluated. */
297SCM
cd07a097
JB
298scm_eval_0str (expr)
299 char *expr;
300{
b377f53e
JB
301 return scm_eval_string (scm_makfrom0str (expr));
302}
303
304
305SCM_PROC (s_eval_string, "eval-string", 1, 0, 0, scm_eval_string);
306
307SCM
308scm_eval_string (string)
309 SCM string;
310{
311 SCM port = scm_mkstrport (SCM_MAKINUM (0), string, SCM_OPN | SCM_RDNG,
cd07a097
JB
312 "scm_eval_0str");
313 SCM form;
b377f53e 314 SCM ans = SCM_UNSPECIFIED;
cd07a097
JB
315
316 /* Read expressions from that port; ignore the values. */
0c32d76c 317 while (!SCM_EOF_OBJECT_P (form = scm_read (port)))
a8aa30d8 318 ans = scm_eval_x (form);
cd07a097 319
0d7368d7
JB
320 /* Don't close the port here; if we re-enter this function via a
321 continuation, then the next time we enter it, we'll get an error.
322 It's a string port anyway, so there's no advantage to closing it
323 early. */
324
a8aa30d8 325 return ans;
cd07a097
JB
326}
327
328
b377f53e 329
1cc91f1b
JB
330static int noop0 SCM_P ((SCM stream));
331
0f2d19dd
JB
332static int
333noop0 (stream)
1cc91f1b 334 SCM stream;
0f2d19dd
JB
335{
336 return 0;
337}
338
339
340scm_ptobfuns scm_stptob =
341{
342 scm_markstream,
343 noop0,
344 prinstpt,
345 0,
ee149d03 346 st_flush,
754c9491 347 st_read_flush,
ee149d03
JB
348 0,
349 stfill_buffer,
754c9491
JB
350 st_seek,
351 st_ftruncate,
ee149d03 352 0,
0f2d19dd
JB
353};
354
355
1cc91f1b 356
0f2d19dd
JB
357void
358scm_init_strports ()
0f2d19dd
JB
359{
360#include "strports.x"
361}
362