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