32-way branching in intmap.scm, not 16-way
[bpt/guile.git] / libguile / rdelim.c
CommitLineData
a2c36371
LC
1/* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2006,
2 * 2011 Free Software Foundation, Inc.
3 *
73be1d9e 4 * This library is free software; you can redistribute it and/or
53befeb7
NJ
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 3 of
7 * the License, or (at your option) any later version.
6d36532c 8 *
53befeb7
NJ
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
6d36532c 13 *
73be1d9e
MV
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
53befeb7
NJ
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
73be1d9e 18 */
6d36532c 19
dbb605f5 20#ifdef HAVE_CONFIG_H
f3447317
RB
21# include <config.h>
22#endif
23
6d36532c
GH
24#include "libguile/_scm.h"
25
26#include <stdio.h>
27
28#ifdef HAVE_STRING_H
29#include <string.h>
30#endif
31
32#include "libguile/chars.h"
33#include "libguile/modules.h"
34#include "libguile/ports.h"
35#include "libguile/rdelim.h"
36#include "libguile/root.h"
37#include "libguile/strings.h"
38#include "libguile/strports.h"
39#include "libguile/validate.h"
40
41SCM_DEFINE (scm_read_delimited_x, "%read-delimited!", 3, 3, 0,
42 (SCM delims, SCM str, SCM gobble, SCM port, SCM start, SCM end),
43 "Read characters from @var{port} into @var{str} until one of the\n"
5352393c
MG
44 "characters in the @var{delims} string is encountered. If\n"
45 "@var{gobble} is true, discard the delimiter character;\n"
46 "otherwise, leave it in the input stream for the next read. If\n"
47 "@var{port} is not specified, use the value of\n"
48 "@code{(current-input-port)}. If @var{start} or @var{end} are\n"
49 "specified, store data only into the substring of @var{str}\n"
50 "bounded by @var{start} and @var{end} (which default to the\n"
51 "beginning and end of the string, respectively).\n"
52 "\n"
53 " Return a pair consisting of the delimiter that terminated the\n"
54 "string and the number of characters read. If reading stopped\n"
55 "at the end of file, the delimiter returned is the\n"
56 "@var{eof-object}; if the string was filled without encountering\n"
57 "a delimiter, this value is @code{#f}.")
6d36532c
GH
58#define FUNC_NAME s_scm_read_delimited_x
59{
1be6b49c 60 size_t j;
1be6b49c
ML
61 size_t cstart;
62 size_t cend;
889975e5 63 scm_t_wchar c;
1be6b49c 64 size_t num_delims;
6d36532c 65
3eb1e2aa 66 SCM_VALIDATE_STRING (1, delims);
cc95e00a 67 num_delims = scm_i_string_length (delims);
3eb1e2aa
MV
68
69 SCM_VALIDATE_STRING (2, str);
cc95e00a 70 scm_i_get_substring_spec (scm_i_string_length (str),
3eb1e2aa
MV
71 start, &cstart, end, &cend);
72
6d36532c 73 if (SCM_UNBNDP (port))
9de87eea 74 port = scm_current_input_port ();
6d36532c 75 else
3eb1e2aa 76 SCM_VALIDATE_OPINPORT (4, port);
6d36532c
GH
77
78 for (j = cstart; j < cend; j++)
79 {
1be6b49c 80 size_t k;
6d36532c 81
be632904 82 c = scm_getc_unlocked (port);
6d36532c
GH
83 for (k = 0; k < num_delims; k++)
84 {
889975e5 85 if (scm_i_string_ref (delims, k) == c)
6d36532c 86 {
7888309b 87 if (scm_is_false (gobble))
c932ce0b 88 scm_ungetc_unlocked (c, port);
6d36532c
GH
89
90 return scm_cons (SCM_MAKE_CHAR (c),
3eb1e2aa 91 scm_from_size_t (j - cstart));
6d36532c
GH
92 }
93 }
94 if (c == EOF)
95 return scm_cons (SCM_EOF_VAL,
3eb1e2aa 96 scm_from_size_t (j - cstart));
6d36532c 97
cc95e00a 98 scm_c_string_set_x (str, j, SCM_MAKE_CHAR (c));
6d36532c 99 }
3eb1e2aa 100 return scm_cons (SCM_BOOL_F, scm_from_size_t (j - cstart));
6d36532c
GH
101}
102#undef FUNC_NAME
103
6d36532c
GH
104
105/*
106 * %read-line
107 * truncates any terminating newline from its input, and returns
108 * a cons of the string read and its terminating character. Doing
109 * so makes it easy to implement the hairy `read-line' options
110 * efficiently in Scheme.
111 */
112
113SCM_DEFINE (scm_read_line, "%read-line", 0, 1, 0,
114 (SCM port),
115 "Read a newline-terminated line from @var{port}, allocating storage as\n"
116 "necessary. The newline terminator (if any) is removed from the string,\n"
117 "and a pair consisting of the line and its delimiter is returned. The\n"
118 "delimiter may be either a newline or the @var{eof-object}; if\n"
119 "@code{%read-line} is called at the end of file, it returns the pair\n"
120 "@code{(#<eof> . #<eof>)}.")
121#define FUNC_NAME s_scm_read_line
122{
a2c36371
LC
123/* Threshold under which the only allocation performed is that of the
124 resulting string and pair. */
e578faea 125#define LINE_BUFFER_SIZE 256
a2c36371
LC
126
127 SCM line, strings, result;
128 scm_t_wchar buf[LINE_BUFFER_SIZE], delim;
129 size_t index;
6d36532c
GH
130
131 if (SCM_UNBNDP (port))
9de87eea 132 port = scm_current_input_port ();
6d36532c 133
a2c36371 134 SCM_VALIDATE_OPINPORT (1,port);
6d36532c 135
a2c36371
LC
136 index = 0;
137 delim = 0;
e578faea 138 strings = SCM_BOOL_F;
6d36532c 139
a2c36371 140 do
6d36532c 141 {
a7ea4411 142 if (SCM_UNLIKELY (index >= LINE_BUFFER_SIZE))
6d36532c 143 {
a2c36371
LC
144 /* The line is getting longer than BUF so store its current
145 contents in STRINGS. */
146 strings = scm_cons (scm_from_utf32_stringn (buf, index),
147 scm_is_false (strings) ? SCM_EOL : strings);
148 index = 0;
6d36532c
GH
149 }
150 else
151 {
be632904 152 buf[index] = scm_getc_unlocked (port);
a2c36371
LC
153 switch (buf[index])
154 {
155 case EOF:
156 case '\n':
157 delim = buf[index];
158 break;
159
160 default:
161 index++;
162 }
4c9419ac 163 }
6d36532c 164 }
a2c36371
LC
165 while (delim == 0);
166
e578faea
LC
167 if (SCM_LIKELY (scm_is_false (strings)))
168 /* The fast path. */
a2c36371
LC
169 line = scm_from_utf32_stringn (buf, index);
170 else
171 {
172 /* Aggregate the intermediary results. */
173 strings = scm_cons (scm_from_utf32_stringn (buf, index), strings);
174 line = scm_string_concatenate (scm_reverse (strings));
175 }
6d36532c 176
a2c36371
LC
177 if (delim == EOF && scm_i_string_length (line) == 0)
178 result = scm_cons (SCM_EOF_VAL, SCM_EOF_VAL);
179 else
180 result = scm_cons (line,
181 delim == EOF ? SCM_EOF_VAL : SCM_MAKE_CHAR (delim));
6d36532c 182
a2c36371
LC
183 return result;
184#undef LINE_BUFFER_SIZE
6d36532c
GH
185}
186#undef FUNC_NAME
187
188SCM_DEFINE (scm_write_line, "write-line", 1, 1, 0,
189 (SCM obj, SCM port),
1e6808ea
MG
190 "Display @var{obj} and a newline character to @var{port}. If\n"
191 "@var{port} is not specified, @code{(current-output-port)} is\n"
192 "used. This function is equivalent to:\n"
193 "@lisp\n"
6d36532c
GH
194 "(display obj [port])\n"
195 "(newline [port])\n"
1e6808ea 196 "@end lisp")
6d36532c
GH
197#define FUNC_NAME s_scm_write_line
198{
199 scm_display (obj, port);
200 return scm_newline (port);
201}
202#undef FUNC_NAME
203
6280d429
MV
204SCM
205scm_init_rdelim_builtins (void)
6d36532c 206{
6d36532c 207#include "libguile/rdelim.x"
6d36532c 208
6280d429
MV
209 return SCM_UNSPECIFIED;
210}
211
212void
213scm_init_rdelim (void)
214{
9a441ddb
MV
215 scm_c_define_gsubr ("%init-rdelim-builtins", 0, 0, 0,
216 scm_init_rdelim_builtins);
6d36532c
GH
217}
218
219/*
220 Local Variables:
221 c-file-style: "gnu"
222 End:
223*/