* eval.c (RETURN): Wrap in do{}while(0) in order to make it
[bpt/guile.git] / libguile / strings.c
1 /* Copyright (C) 1995,1996,1998,2000,2001 Free Software Foundation, Inc.
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
43 \f
44
45 #include <string.h>
46
47 #include "libguile/_scm.h"
48 #include "libguile/chars.h"
49 #include "libguile/root.h"
50 #include "libguile/strings.h"
51 #include "libguile/deprecation.h"
52 #include "libguile/validate.h"
53
54 \f
55
56 /* {Strings}
57 */
58
59 SCM_DEFINE (scm_string_p, "string?", 1, 0, 0,
60 (SCM obj),
61 "Return @code{#t} iff @var{obj} is a string, else returns\n"
62 "@code{#f}.")
63 #define FUNC_NAME s_scm_string_p
64 {
65 return SCM_BOOL (SCM_STRINGP (obj));
66 }
67 #undef FUNC_NAME
68
69
70 SCM_REGISTER_PROC (s_scm_list_to_string, "list->string", 1, 0, 0, scm_string);
71
72 SCM_DEFINE (scm_string, "string", 0, 0, 1,
73 (SCM chrs),
74 "@deffnx primitive list->string chrs\n"
75 "Return a newly allocated string composed of the arguments,\n"
76 "@var{chrs}.")
77 #define FUNC_NAME s_scm_string
78 {
79 SCM result;
80
81 {
82 long i = scm_ilength (chrs);
83
84 SCM_ASSERT (i >= 0, chrs, SCM_ARG1, FUNC_NAME);
85 result = scm_allocate_string (i);
86 }
87
88 {
89 unsigned char *data = SCM_STRING_UCHARS (result);
90
91 while (!SCM_NULLP (chrs))
92 {
93 SCM elt = SCM_CAR (chrs);
94
95 SCM_VALIDATE_CHAR (SCM_ARGn, elt);
96 *data++ = SCM_CHAR (elt);
97 chrs = SCM_CDR (chrs);
98 }
99 }
100 return result;
101 }
102 #undef FUNC_NAME
103
104
105 /* converts C scm_array of strings to SCM scm_list of strings. */
106 /* If argc < 0, a null terminated scm_array is assumed. */
107 SCM
108 scm_makfromstrs (int argc, char **argv)
109 {
110 int i = argc;
111 SCM lst = SCM_EOL;
112 if (0 > i)
113 for (i = 0; argv[i]; i++);
114 while (i--)
115 lst = scm_cons (scm_mem2string (argv[i], strlen (argv[i])), lst);
116 return lst;
117 }
118
119
120 /* This function must only be applied to memory obtained via malloc,
121 since the GC is going to apply `free' to it when the string is
122 dropped.
123
124 Also, s[len] must be `\0', since we promise that strings are
125 null-terminated. Perhaps we could handle non-null-terminated
126 strings by claiming they're shared substrings of a string we just
127 made up. */
128 SCM
129 scm_take_str (char *s, size_t len)
130 #define FUNC_NAME "scm_take_str"
131 {
132 SCM answer;
133
134 SCM_ASSERT_RANGE (2, scm_ulong2num (len), len <= SCM_STRING_MAX_LENGTH);
135
136 SCM_NEWCELL (answer);
137 SCM_SET_STRING_CHARS (answer, s);
138 SCM_SET_STRING_LENGTH (answer, len);
139 scm_done_malloc (len + 1);
140
141 return answer;
142 }
143 #undef FUNC_NAME
144
145
146 /* `s' must be a malloc'd string. See scm_take_str. */
147 SCM
148 scm_take0str (char *s)
149 {
150 return scm_take_str (s, strlen (s));
151 }
152
153
154 SCM
155 scm_mem2string (const char *src, size_t len)
156 {
157 SCM s = scm_allocate_string (len);
158 char *dst = SCM_STRING_CHARS (s);
159
160 while (len--)
161 *dst++ = *src++;
162 return s;
163 }
164
165
166 SCM
167 scm_str2string (const char *src)
168 {
169 return scm_mem2string (src, strlen (src));
170 }
171
172
173 SCM
174 scm_makfrom0str (const char *src)
175 {
176 if (!src) return SCM_BOOL_F;
177 return scm_mem2string (src, strlen (src));
178 }
179
180
181 SCM
182 scm_makfrom0str_opt (const char *src)
183 {
184 return scm_makfrom0str (src);
185 }
186
187
188 SCM
189 scm_allocate_string (size_t len)
190 #define FUNC_NAME "scm_allocate_string"
191 {
192 char *mem;
193 SCM s;
194
195 SCM_ASSERT_RANGE (1, scm_long2num (len), len <= SCM_STRING_MAX_LENGTH);
196
197 mem = (char *) scm_must_malloc (len + 1, FUNC_NAME);
198 mem[len] = 0;
199
200 SCM_NEWCELL (s);
201 SCM_SET_STRING_CHARS (s, mem);
202 SCM_SET_STRING_LENGTH (s, len);
203
204 return s;
205 }
206 #undef FUNC_NAME
207
208
209 SCM_DEFINE (scm_make_string, "make-string", 1, 1, 0,
210 (SCM k, SCM chr),
211 "Return a newly allocated string of\n"
212 "length @var{k}. If @var{chr} is given, then all elements of\n"
213 "the string are initialized to @var{chr}, otherwise the contents\n"
214 "of the @var{string} are unspecified.")
215 #define FUNC_NAME s_scm_make_string
216 {
217 if (SCM_INUMP (k))
218 {
219 long int i = SCM_INUM (k);
220 SCM res;
221
222 SCM_ASSERT_RANGE (1, k, i >= 0);
223
224 res = scm_allocate_string (i);
225 if (!SCM_UNBNDP (chr))
226 {
227 unsigned char *dst;
228
229 SCM_VALIDATE_CHAR (2, chr);
230
231 dst = SCM_STRING_UCHARS (res);
232 memset (dst, SCM_CHAR (chr), i);
233 }
234
235 return res;
236 }
237 else if (SCM_BIGP (k))
238 SCM_OUT_OF_RANGE (1, k);
239 else
240 SCM_WRONG_TYPE_ARG (1, k);
241 }
242 #undef FUNC_NAME
243
244
245 SCM_DEFINE (scm_string_length, "string-length", 1, 0, 0,
246 (SCM string),
247 "Return the number of characters in @var{string}.")
248 #define FUNC_NAME s_scm_string_length
249 {
250 SCM_VALIDATE_STRING (1, string);
251 return SCM_MAKINUM (SCM_STRING_LENGTH (string));
252 }
253 #undef FUNC_NAME
254
255 SCM_DEFINE (scm_string_ref, "string-ref", 2, 0, 0,
256 (SCM str, SCM k),
257 "Return character @var{k} of @var{str} using zero-origin\n"
258 "indexing. @var{k} must be a valid index of @var{str}.")
259 #define FUNC_NAME s_scm_string_ref
260 {
261 long idx;
262
263 SCM_VALIDATE_STRING (1, str);
264 SCM_VALIDATE_INUM_COPY (2, k, idx);
265 SCM_ASSERT_RANGE (2, k, idx >= 0 && idx < SCM_STRING_LENGTH (str));
266 return SCM_MAKE_CHAR (SCM_STRING_UCHARS (str)[idx]);
267 }
268 #undef FUNC_NAME
269
270
271 SCM_DEFINE (scm_string_set_x, "string-set!", 3, 0, 0,
272 (SCM str, SCM k, SCM chr),
273 "Store @var{chr} in element @var{k} of @var{str} and return\n"
274 "an unspecified value. @var{k} must be a valid index of\n"
275 "@var{str}.")
276 #define FUNC_NAME s_scm_string_set_x
277 {
278 SCM_VALIDATE_STRING (1, str);
279 SCM_VALIDATE_INUM_RANGE (2,k,0,SCM_STRING_LENGTH(str));
280 SCM_VALIDATE_CHAR (3,chr);
281 SCM_STRING_UCHARS (str)[SCM_INUM (k)] = SCM_CHAR (chr);
282 return SCM_UNSPECIFIED;
283 }
284 #undef FUNC_NAME
285
286
287 SCM_DEFINE (scm_substring, "substring", 2, 1, 0,
288 (SCM str, SCM start, SCM end),
289 "Return a newly allocated string formed from the characters\n"
290 "of @var{str} beginning with index @var{start} (inclusive) and\n"
291 "ending with index @var{end} (exclusive).\n"
292 "@var{str} must be a string, @var{start} and @var{end} must be\n"
293 "exact integers satisfying:\n\n"
294 "0 <= @var{start} <= @var{end} <= (string-length @var{str}).")
295 #define FUNC_NAME s_scm_substring
296 {
297 long int from;
298 long int to;
299 SCM substr;
300
301 SCM_VALIDATE_STRING (1, str);
302 SCM_VALIDATE_INUM (2, start);
303 SCM_VALIDATE_INUM_DEF (3, end, SCM_STRING_LENGTH (str));
304
305 from = SCM_INUM (start);
306 SCM_ASSERT_RANGE (2, start, 0 <= from && from <= SCM_STRING_LENGTH (str));
307 to = SCM_INUM (end);
308 SCM_ASSERT_RANGE (3, end, from <= to && to <= SCM_STRING_LENGTH (str));
309
310 substr = scm_mem2string (&SCM_STRING_CHARS (str)[from], to - from);
311 scm_remember_upto_here_1 (str);
312 return substr;
313 }
314 #undef FUNC_NAME
315
316
317 SCM_DEFINE (scm_string_append, "string-append", 0, 0, 1,
318 (SCM args),
319 "Return a newly allocated string whose characters form the\n"
320 "concatenation of the given strings, @var{args}.")
321 #define FUNC_NAME s_scm_string_append
322 {
323 SCM res;
324 size_t i = 0;
325 register SCM l, s;
326 register unsigned char *data;
327
328 SCM_VALIDATE_REST_ARGUMENT (args);
329 for (l = args; !SCM_NULLP (l); l = SCM_CDR (l)) {
330 s = SCM_CAR (l);
331 SCM_VALIDATE_STRING (SCM_ARGn,s);
332 i += SCM_STRING_LENGTH (s);
333 }
334 res = scm_allocate_string (i);
335 data = SCM_STRING_UCHARS (res);
336 for (l = args; !SCM_NULLP (l);l = SCM_CDR (l)) {
337 s = SCM_CAR (l);
338 for (i = 0;i<SCM_STRING_LENGTH (s);i++) *data++ = SCM_STRING_UCHARS (s)[i];
339 }
340 return res;
341 }
342 #undef FUNC_NAME
343
344
345 void
346 scm_init_strings ()
347 {
348 scm_nullstr = scm_allocate_string (0);
349
350 #ifndef SCM_MAGIC_SNARFER
351 #include "libguile/strings.x"
352 #endif
353 }
354
355
356 /*
357 Local Variables:
358 c-file-style: "gnu"
359 End:
360 */