* convert.c: include <string.h> for convert_i.c.
[bpt/guile.git] / libguile / rdelim.c
CommitLineData
e81d98ec 1/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc.
6d36532c
GH
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
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
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.
40 * If you do not wish that, delete this exception notice.
41
42 * This is the C part of the module for delimited I/O. It's
43 * similar to (scsh rdelim) but somewhat incompatible. */
44
45#include "libguile/_scm.h"
46
47#include <stdio.h>
48
49#ifdef HAVE_STRING_H
50#include <string.h>
51#endif
52
53#include "libguile/chars.h"
54#include "libguile/modules.h"
55#include "libguile/ports.h"
56#include "libguile/rdelim.h"
57#include "libguile/root.h"
58#include "libguile/strings.h"
59#include "libguile/strports.h"
60#include "libguile/validate.h"
61
62SCM_DEFINE (scm_read_delimited_x, "%read-delimited!", 3, 3, 0,
63 (SCM delims, SCM str, SCM gobble, SCM port, SCM start, SCM end),
64 "Read characters from @var{port} into @var{str} until one of the\n"
5352393c
MG
65 "characters in the @var{delims} string is encountered. If\n"
66 "@var{gobble} is true, discard the delimiter character;\n"
67 "otherwise, leave it in the input stream for the next read. If\n"
68 "@var{port} is not specified, use the value of\n"
69 "@code{(current-input-port)}. If @var{start} or @var{end} are\n"
70 "specified, store data only into the substring of @var{str}\n"
71 "bounded by @var{start} and @var{end} (which default to the\n"
72 "beginning and end of the string, respectively).\n"
73 "\n"
74 " Return a pair consisting of the delimiter that terminated the\n"
75 "string and the number of characters read. If reading stopped\n"
76 "at the end of file, the delimiter returned is the\n"
77 "@var{eof-object}; if the string was filled without encountering\n"
78 "a delimiter, this value is @code{#f}.")
6d36532c
GH
79#define FUNC_NAME s_scm_read_delimited_x
80{
1be6b49c 81 size_t j;
6d36532c 82 char *buf;
1be6b49c
ML
83 size_t cstart;
84 size_t cend;
6d36532c
GH
85 int c;
86 char *cdelims;
1be6b49c 87 size_t num_delims;
6d36532c
GH
88
89 SCM_VALIDATE_STRING_COPY (1, delims, cdelims);
90 num_delims = SCM_STRING_LENGTH (delims);
91 SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, str, buf, 5, start, cstart,
92 6, end, cend);
93 if (SCM_UNBNDP (port))
94 port = scm_cur_inp;
95 else
96 SCM_VALIDATE_OPINPORT (4,port);
97
98 for (j = cstart; j < cend; j++)
99 {
1be6b49c 100 size_t k;
6d36532c
GH
101
102 c = scm_getc (port);
103 for (k = 0; k < num_delims; k++)
104 {
105 if (cdelims[k] == c)
106 {
107 if (SCM_FALSEP (gobble))
108 scm_ungetc (c, port);
109
110 return scm_cons (SCM_MAKE_CHAR (c),
111 scm_long2num (j - cstart));
112 }
113 }
114 if (c == EOF)
115 return scm_cons (SCM_EOF_VAL,
116 scm_long2num (j - cstart));
117
118 buf[j] = c;
119 }
120 return scm_cons (SCM_BOOL_F, scm_long2num (j - cstart));
121}
122#undef FUNC_NAME
123
124static unsigned char *
1be6b49c 125scm_do_read_line (SCM port, size_t *len_p)
6d36532c 126{
92c2555f 127 scm_t_port *pt = SCM_PTAB_ENTRY (port);
6d36532c
GH
128 unsigned char *end;
129
130 /* I thought reading lines was simple. Mercy me. */
131
132 /* The common case: the buffer contains a complete line.
133 This needs to be fast. */
134 if ((end = memchr (pt->read_pos, '\n', (pt->read_end - pt->read_pos)))
135 != 0)
136 {
1be6b49c 137 size_t buf_len = (end + 1) - pt->read_pos;
6d36532c 138 /* Allocate a buffer of the perfect size. */
4c9419ac 139 unsigned char *buf = scm_malloc (buf_len + 1);
6d36532c
GH
140
141 memcpy (buf, pt->read_pos, buf_len);
142 pt->read_pos += buf_len;
143
144 buf[buf_len] = '\0';
145
146 *len_p = buf_len;
147 return buf;
148 }
149
150 /* The buffer contains no newlines. */
151 {
152 /* When live, len is always the number of characters in the
153 current buffer that are part of the current line. */
1be6b49c
ML
154 size_t len = (pt->read_end - pt->read_pos);
155 size_t buf_size = (len < 50) ? 60 : len * 2;
6d36532c
GH
156 /* Invariant: buf always has buf_size + 1 characters allocated;
157 the `+ 1' is for the final '\0'. */
4c9419ac 158 unsigned char *buf = scm_malloc (buf_size + 1);
1be6b49c 159 size_t buf_len = 0;
6d36532c
GH
160
161 for (;;)
162 {
163 if (buf_len + len > buf_size)
164 {
1be6b49c 165 size_t new_size = (buf_len + len) * 2;
4c9419ac 166 buf = scm_realloc (buf, new_size + 1);
6d36532c
GH
167 buf_size = new_size;
168 }
169
170 /* Copy what we've got out of the port, into our buffer. */
171 memcpy (buf + buf_len, pt->read_pos, len);
172 buf_len += len;
173 pt->read_pos += len;
174
175 /* If we had seen a newline, we're done now. */
176 if (end)
177 break;
178
179 /* Get more characters. */
180 if (scm_fill_input (port) == EOF)
181 {
182 /* If we're missing a final newline in the file, return
183 what we did get, sans newline. */
184 if (buf_len > 0)
185 break;
186
187 free (buf);
188 return 0;
189 }
190
191 /* Search the buffer for newlines. */
192 if ((end = memchr (pt->read_pos, '\n',
193 (len = (pt->read_end - pt->read_pos))))
194 != 0)
195 len = (end - pt->read_pos) + 1;
196 }
197
198 /* I wonder how expensive this realloc is. */
4c9419ac 199 buf = scm_realloc (buf, buf_len + 1);
6d36532c
GH
200 buf[buf_len] = '\0';
201 *len_p = buf_len;
202 return buf;
203 }
4c9419ac 204}
6d36532c
GH
205
206
207/*
208 * %read-line
209 * truncates any terminating newline from its input, and returns
210 * a cons of the string read and its terminating character. Doing
211 * so makes it easy to implement the hairy `read-line' options
212 * efficiently in Scheme.
213 */
214
215SCM_DEFINE (scm_read_line, "%read-line", 0, 1, 0,
216 (SCM port),
217 "Read a newline-terminated line from @var{port}, allocating storage as\n"
218 "necessary. The newline terminator (if any) is removed from the string,\n"
219 "and a pair consisting of the line and its delimiter is returned. The\n"
220 "delimiter may be either a newline or the @var{eof-object}; if\n"
221 "@code{%read-line} is called at the end of file, it returns the pair\n"
222 "@code{(#<eof> . #<eof>)}.")
223#define FUNC_NAME s_scm_read_line
224{
92c2555f 225 scm_t_port *pt;
6d36532c 226 char *s;
1be6b49c 227 size_t slen;
6d36532c
GH
228 SCM line, term;
229
230 if (SCM_UNBNDP (port))
231 port = scm_cur_inp;
232 SCM_VALIDATE_OPINPORT (1,port);
233
234 pt = SCM_PTAB_ENTRY (port);
235 if (pt->rw_active == SCM_PORT_WRITE)
236 scm_ptobs[SCM_PTOBNUM (port)].flush (port);
237
238 s = (char *) scm_do_read_line (port, &slen);
239
240 if (s == NULL)
241 term = line = SCM_EOF_VAL;
242 else
243 {
244 if (s[slen-1] == '\n')
245 {
246 term = SCM_MAKE_CHAR ('\n');
247 s[slen-1] = '\0';
248 line = scm_take_str (s, slen-1);
6d36532c
GH
249 SCM_INCLINE (port);
250 }
251 else
252 {
253 /* Fix: we should check for eof on the port before assuming this. */
254 term = SCM_EOF_VAL;
255 line = scm_take_str (s, slen);
256 SCM_COL (port) += slen;
4c9419ac 257 }
6d36532c
GH
258 }
259
260 if (pt->rw_random)
261 pt->rw_active = SCM_PORT_READ;
262
263 return scm_cons (line, term);
264}
265#undef FUNC_NAME
266
267SCM_DEFINE (scm_write_line, "write-line", 1, 1, 0,
268 (SCM obj, SCM port),
1e6808ea
MG
269 "Display @var{obj} and a newline character to @var{port}. If\n"
270 "@var{port} is not specified, @code{(current-output-port)} is\n"
271 "used. This function is equivalent to:\n"
272 "@lisp\n"
6d36532c
GH
273 "(display obj [port])\n"
274 "(newline [port])\n"
1e6808ea 275 "@end lisp")
6d36532c
GH
276#define FUNC_NAME s_scm_write_line
277{
278 scm_display (obj, port);
279 return scm_newline (port);
280}
281#undef FUNC_NAME
282
6280d429
MV
283SCM
284scm_init_rdelim_builtins (void)
6d36532c 285{
6d36532c
GH
286#ifndef SCM_MAGIC_SNARFER
287#include "libguile/rdelim.x"
288#endif
289
6280d429
MV
290 return SCM_UNSPECIFIED;
291}
292
293void
294scm_init_rdelim (void)
295{
9a441ddb
MV
296 scm_c_define_gsubr ("%init-rdelim-builtins", 0, 0, 0,
297 scm_init_rdelim_builtins);
6d36532c
GH
298}
299
300/*
301 Local Variables:
302 c-file-style: "gnu"
303 End:
304*/