1 /* Guile-R6RS-Libs --- Implementation of R6RS standard libraries.
2 Copyright (C) 2007 Ludovic Courtès <ludovic.courtes@laas.fr>
4 Guile-R6RS-Libs is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 Guile-R6RS-Libs is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with Guile-R6RS-Libs; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
28 /* Assuming 32-bit longs. */
29 # define ULONG_MAX 4294967295UL
38 # define EXPECT __builtin_expect
40 # define EXPECT(_expr, _value) (_expr)
43 #define EXPECT_TRUE(_expr) EXPECT ((_expr), 1)
44 #define EXPECT_FALSE(_expr) EXPECT ((_expr), 0)
46 /* Convenience macros. These are used by the various templates (macros) that
47 are parameterized by integer signedness. */
48 #define INT8_T_signed scm_t_int8
49 #define INT8_T_unsigned scm_t_uint8
50 #define INT16_T_signed scm_t_int16
51 #define INT16_T_unsigned scm_t_uint16
52 #define is_signed_int8(_x) (((_x) >= -128L) && ((_x) <= 127L))
53 #define is_unsigned_int8(_x) ((_x) <= 255UL)
54 #define is_signed_int16(_x) (((_x) >= -32768L) && ((_x) <= 32767L))
55 #define is_unsigned_int16(_x) ((_x) <= 65535UL)
57 #define INT_TYPE(_size, _sign) INT ## _size ## _T_ ## _sign
58 #define INT_SWAP(_size) bswap_ ## _size
59 #define INT_VALID_P(_size, _sign) is_ ## _sign ## _int ## _size
62 #define INTEGER_ACCESSOR_PROLOGUE(_len, _sign) \
63 unsigned c_len, c_index; \
66 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv); \
67 c_index = scm_to_uint (index); \
69 c_len = SCM_R6RS_BYTEVECTOR_LENGTH (bv); \
70 c_bv = (_sign char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv); \
72 if (EXPECT_FALSE (c_index + ((_len) >> 3UL) - 1 >= c_len)) \
73 scm_out_of_range (FUNC_NAME, index);
75 /* Template for fixed-size integer access (only 8, 16 or 32-bit). */
76 #define INTEGER_REF(_len, _sign) \
79 INTEGER_ACCESSOR_PROLOGUE (_len, _sign); \
80 SCM_VALIDATE_SYMBOL (3, endianness); \
83 INT_TYPE (_len, _sign) c_result; \
85 c_result = * (INT_TYPE (_len, _sign) *) &c_bv[c_index]; \
86 if (!scm_is_eq (endianness, native_endianness)) \
87 c_result = INT_SWAP (_len) (c_result); \
89 result = SCM_I_MAKINUM (c_result); \
94 /* Template for fixed-size integer access using the native endianness. */
95 #define INTEGER_NATIVE_REF(_len, _sign) \
98 INTEGER_ACCESSOR_PROLOGUE (_len, _sign); \
101 INT_TYPE (_len, _sign) c_result; \
103 c_result = * (INT_TYPE (_len, _sign) *) &c_bv[c_index]; \
104 result = SCM_I_MAKINUM (c_result); \
109 /* Template for fixed-size integer modification (only 8, 16 or 32-bit). */
110 #define INTEGER_SET(_len, _sign) \
111 INTEGER_ACCESSOR_PROLOGUE (_len, _sign); \
112 SCM_VALIDATE_SYMBOL (3, endianness); \
115 _sign long c_value; \
116 INT_TYPE (_len, _sign) c_value_short; \
118 if (EXPECT_FALSE (!SCM_I_INUMP (value))) \
119 scm_wrong_type_arg (FUNC_NAME, 3, value); \
121 c_value = SCM_I_INUM (value); \
122 if (EXPECT_FALSE (!INT_VALID_P (_len, _sign) (c_value))) \
123 scm_out_of_range (FUNC_NAME, value); \
125 c_value_short = (INT_TYPE (_len, _sign)) c_value; \
126 if (!scm_is_eq (endianness, native_endianness)) \
127 c_value_short = INT_SWAP (_len) (c_value_short); \
129 * (INT_TYPE (_len, _sign) *) &c_bv[c_index] = c_value_short; \
132 return SCM_UNSPECIFIED;
134 /* Template for fixed-size integer modification using the native
136 #define INTEGER_NATIVE_SET(_len, _sign) \
137 INTEGER_ACCESSOR_PROLOGUE (_len, _sign); \
140 _sign long c_value; \
141 INT_TYPE (_len, _sign) c_value_short; \
143 if (EXPECT_FALSE (!SCM_I_INUMP (value))) \
144 scm_wrong_type_arg (FUNC_NAME, 3, value); \
146 c_value = SCM_I_INUM (value); \
147 if (EXPECT_FALSE (!INT_VALID_P (_len, _sign) (c_value))) \
148 scm_out_of_range (FUNC_NAME, value); \
150 c_value_short = (INT_TYPE (_len, _sign)) c_value; \
152 * (INT_TYPE (_len, _sign) *) &c_bv[c_index] = c_value_short; \
155 return SCM_UNSPECIFIED;
159 /* Bytevector type. */
161 SCM_SMOB (scm_tc16_r6rs_bytevector
, "r6rs-bytevector", 0);
163 #define SCM_VALIDATE_R6RS_BYTEVECTOR(_pos, _obj) \
164 SCM_VALIDATE_SMOB ((_pos), (_obj), r6rs_bytevector);
168 make_bytevector (unsigned len
, signed char *contents
)
170 SCM_RETURN_NEWSMOB2 (scm_tc16_r6rs_bytevector
, len
, contents
);
173 #define SCM_R6RS_BYTEVECTOR_LENGTH(_bv) \
174 ((unsigned) SCM_SMOB_DATA (_bv))
175 #define SCM_R6RS_BYTEVECTOR_CONTENTS(_bv) \
176 ((signed char *) SCM_SMOB_DATA_2 (_bv))
178 #define SCM_GC_BYTEVECTOR "r6rs-bytevector"
180 SCM_SMOB_FREE (scm_tc16_r6rs_bytevector
, free_bytevector
, bv
)
185 c_len
= SCM_R6RS_BYTEVECTOR_LENGTH (bv
);
186 c_bv
= SCM_R6RS_BYTEVECTOR_CONTENTS (bv
);
188 scm_gc_free (c_bv
, c_len
, SCM_GC_BYTEVECTOR
);
195 /* General operations. */
197 SCM_SYMBOL (scm_sym_big
, "big");
198 SCM_SYMBOL (scm_sym_little
, "little");
200 /* Host endianness (a symbol). */
201 static SCM native_endianness
= SCM_UNSPECIFIED
;
205 # define bswap_24(_x) \
206 ((((_x) & 0xff0000) >> 16) | \
207 (((_x) & 0x00ff00)) | \
208 (((_x) & 0x0000ff) << 16))
212 SCM_DEFINE (scm_r6rs_native_endianness
, "native-endianness", 0, 0, 0,
214 "Return a symbol denoting the machine's native endianness.")
215 #define FUNC_NAME s_scm_r6rs_native_endianness
217 return native_endianness
;
221 SCM_DEFINE (scm_r6rs_bytevector_p
, "bytevector?", 1, 0, 0,
223 "Return true if @var{obj} is a bytevector.")
224 #define FUNC_NAME s_scm_r6rs_bytevector_p
226 return (scm_from_bool (SCM_SMOB_PREDICATE (scm_tc16_r6rs_bytevector
,
231 SCM_DEFINE (scm_r6rs_make_bytevector
, "make-bytevector", 1, 1, 0,
233 "Return a newly allocated bytevector of @var{len} bytes, "
234 "optionally filled with @var{fill}.")
235 #define FUNC_NAME s_scm_r6rs_make_bytevector
239 signed char *contents
;
241 SCM_VALIDATE_UINT_COPY (1, len
, c_len
);
242 if (fill
!= SCM_UNDEFINED
)
246 value
= scm_to_int (fill
);
247 if (EXPECT_FALSE ((value
< -128) || (value
> 255)))
248 scm_out_of_range (FUNC_NAME
, fill
);
249 c_fill
= (signed char) value
;
252 contents
= (signed char *) scm_gc_malloc (c_len
, SCM_GC_BYTEVECTOR
);
253 if (fill
!= SCM_UNDEFINED
)
257 for (i
= 0; i
< c_len
; i
++)
258 contents
[i
] = c_fill
;
261 return (make_bytevector (c_len
, contents
));
265 SCM_DEFINE (scm_r6rs_bytevector_length
, "bytevector-length", 1, 0, 0,
267 "Return the length (in bytes) of @var{bv}.")
268 #define FUNC_NAME s_scm_r6rs_bytevector_length
270 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv
);
272 return (scm_from_uint (SCM_R6RS_BYTEVECTOR_LENGTH (bv
)));
276 SCM_DEFINE (scm_r6rs_bytevector_eq_p
, "bytevector=?", 2, 0, 0,
278 "Return is @var{bv1} equals to @var{bv2}---i.e., if they "
279 "have the same length and contents.")
280 #define FUNC_NAME s_scm_r6rs_bytevector_eq_p
282 SCM result
= SCM_BOOL_F
;
283 unsigned c_len1
, c_len2
;
285 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv1
);
286 SCM_VALIDATE_R6RS_BYTEVECTOR (2, bv2
);
288 c_len1
= SCM_R6RS_BYTEVECTOR_LENGTH (bv1
);
289 c_len2
= SCM_R6RS_BYTEVECTOR_LENGTH (bv2
);
291 if (c_len1
== c_len2
)
293 signed char *c_bv1
, *c_bv2
;
295 c_bv1
= SCM_R6RS_BYTEVECTOR_CONTENTS (bv1
);
296 c_bv2
= SCM_R6RS_BYTEVECTOR_CONTENTS (bv2
);
298 result
= scm_from_bool (!memcmp (c_bv1
, c_bv2
, c_len1
));
305 SCM_DEFINE (scm_r6rs_bytevector_fill_x
, "bytevector-fill!", 2, 0, 0,
307 "Fill bytevector @var{bv} with @var{fill}, a byte.")
308 #define FUNC_NAME s_scm_r6rs_bytevector_fill_x
311 signed char *c_bv
, c_fill
;
313 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv
);
314 c_fill
= scm_to_int8 (fill
);
316 c_len
= SCM_R6RS_BYTEVECTOR_LENGTH (bv
);
317 c_bv
= SCM_R6RS_BYTEVECTOR_CONTENTS (bv
);
319 for (i
= 0; i
< c_len
; i
++)
322 return SCM_UNSPECIFIED
;
326 SCM_DEFINE (scm_r6rs_bytevector_copy_x
, "bytevector-copy!", 5, 0, 0,
327 (SCM source
, SCM source_start
, SCM target
, SCM target_start
,
329 "Copy @var{len} bytes from @var{source} into @var{target}, "
330 "starting reading from @var{source_start} (a positive index "
331 "within @var{source}) and start writing at "
332 "@var{target_start}.")
333 #define FUNC_NAME s_scm_r6rs_bytevector_copy_x
335 unsigned c_len
, c_source_len
, c_target_len
;
336 unsigned c_source_start
, c_target_start
;
337 signed char *c_source
, *c_target
;
339 SCM_VALIDATE_R6RS_BYTEVECTOR (1, source
);
340 SCM_VALIDATE_R6RS_BYTEVECTOR (3, target
);
342 c_len
= scm_to_uint (len
);
343 c_source_start
= scm_to_uint (source_start
);
344 c_target_start
= scm_to_uint (target_start
);
346 c_source
= SCM_R6RS_BYTEVECTOR_CONTENTS (source
);
347 c_target
= SCM_R6RS_BYTEVECTOR_CONTENTS (target
);
348 c_source_len
= SCM_R6RS_BYTEVECTOR_LENGTH (source
);
349 c_target_len
= SCM_R6RS_BYTEVECTOR_LENGTH (target
);
351 if (EXPECT_FALSE (c_source_start
+ c_len
> c_source_len
))
352 scm_out_of_range (FUNC_NAME
, source_start
);
353 if (EXPECT_FALSE (c_target_start
+ c_len
> c_target_len
))
354 scm_out_of_range (FUNC_NAME
, target_start
);
356 memcpy (c_target
+ c_target_start
,
357 c_source
+ c_source_start
,
360 return SCM_UNSPECIFIED
;
364 SCM_DEFINE (scm_r6rs_bytevector_copy
, "bytevector-copy", 1, 0, 0,
366 "Return a newly allocated copy of @var{bv}.")
367 #define FUNC_NAME s_scm_r6rs_bytevector_copy
370 signed char *c_bv
, *c_copy
;
372 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv
);
374 c_len
= SCM_R6RS_BYTEVECTOR_LENGTH (bv
);
375 c_bv
= SCM_R6RS_BYTEVECTOR_CONTENTS (bv
);
377 c_copy
= scm_gc_malloc (c_len
, SCM_GC_BYTEVECTOR
);
378 memcpy (c_copy
, c_bv
, c_len
);
380 return (make_bytevector (c_len
, c_copy
));
385 /* Operations on bytes and octets. */
387 SCM_DEFINE (scm_r6rs_bytevector_u8_ref
, "bytevector-u8-ref", 2, 0, 0,
389 "Return the octet located at @var{index} in @var{bv}.")
390 #define FUNC_NAME s_scm_r6rs_bytevector_u8_ref
392 INTEGER_NATIVE_REF (8, unsigned);
396 SCM_DEFINE (scm_r6rs_bytevector_s8_ref
, "bytevector-s8-ref", 2, 0, 0,
398 "Return the byte located at @var{index} in @var{bv}.")
399 #define FUNC_NAME s_scm_r6rs_bytevector_u8_ref
401 INTEGER_NATIVE_REF (8, signed);
405 SCM_DEFINE (scm_r6rs_bytevector_u8_set_x
, "bytevector-u8-set!", 3, 0, 0,
406 (SCM bv
, SCM index
, SCM value
),
407 "Return the octet located at @var{index} in @var{bv}.")
408 #define FUNC_NAME s_scm_r6rs_bytevector_u8_set_x
410 INTEGER_NATIVE_SET (8, unsigned);
414 SCM_DEFINE (scm_r6rs_bytevector_s8_set_x
, "bytevector-s8-set!", 3, 0, 0,
415 (SCM bv
, SCM index
, SCM value
),
416 "Return the octet located at @var{index} in @var{bv}.")
417 #define FUNC_NAME s_scm_r6rs_bytevector_u8_set_x
419 INTEGER_NATIVE_SET (8, signed);
423 #undef OCTET_ACCESSOR_PROLOGUE
426 SCM_DEFINE (scm_r6rs_bytevector_to_u8_list
, "bytevector->u8-list", 1, 0, 0,
428 "Return a newly allocated list of octets containing the "
429 "contents of @var{bv}.")
430 #define FUNC_NAME s_scm_r6rs_bytevector_to_u8_list
436 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv
);
438 c_len
= SCM_R6RS_BYTEVECTOR_LENGTH (bv
);
439 c_bv
= (unsigned char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv
);
441 lst
= scm_make_list (scm_from_uint (c_len
), SCM_UNSPECIFIED
);
442 for (i
= 0, pair
= lst
;
444 i
++, pair
= SCM_CDR (pair
))
446 SCM_SETCAR (pair
, SCM_I_MAKINUM (c_bv
[i
]));
453 SCM_DEFINE (scm_r6rs_u8_list_to_bytevector
, "u8-list->bytevector", 1, 0, 0,
455 "Turn @var{lst}, a list of octets, into a bytevector.")
456 #define FUNC_NAME s_scm_r6rs_u8_list_to_bytevector
462 SCM_VALIDATE_LIST_COPYLEN (1, lst
, c_len
);
464 c_bv
= scm_gc_malloc (c_len
, SCM_GC_BYTEVECTOR
);
465 for (i
= 0; i
< c_len
; lst
= SCM_CDR (lst
), i
++)
467 item
= SCM_CAR (lst
);
469 if (EXPECT_TRUE (SCM_I_INUMP (item
)))
473 c_item
= SCM_I_INUM (item
);
474 if (EXPECT_TRUE ((c_item
>= 0) && (c_item
< 256)))
475 c_bv
[i
] = (unsigned char) c_item
;
483 return (make_bytevector (c_len
, (signed char *) c_bv
));
486 scm_gc_free (c_bv
, c_len
, SCM_GC_BYTEVECTOR
);
487 scm_wrong_type_arg (FUNC_NAME
, 1, item
);
493 /* Compute the two's complement of VALUE (a positive integer) on SIZE octets
494 using (2^(SIZE * 8) - VALUE). */
496 twos_complement (mpz_t value
, size_t size
)
498 unsigned long bit_count
;
500 /* We expect BIT_COUNT to fit in a unsigned long thanks to the range
501 checking on SIZE performed earlier. */
502 bit_count
= (unsigned long) size
<< 3UL;
504 if (EXPECT_TRUE (bit_count
< sizeof (unsigned long)))
505 mpz_ui_sub (value
, 1UL << bit_count
, value
);
511 mpz_ui_pow_ui (max
, 2, bit_count
);
512 mpz_sub (value
, max
, value
);
518 bytevector_large_ref (const char *c_bv
, size_t c_size
, int signed_p
,
523 int c_endianness
, negative_p
= 0;
527 if (scm_is_eq (endianness
, scm_sym_big
))
528 negative_p
= c_bv
[0] & 0x80;
530 negative_p
= c_bv
[c_size
- 1] & 0x80;
533 c_endianness
= scm_is_eq (endianness
, scm_sym_big
) ? 1 : -1;
536 mpz_import (c_mpz
, 1 /* 1 word */, 1 /* word order doesn't matter */,
537 c_size
/* word is C_SIZE-byte long */,
539 0 /* nails */, c_bv
);
541 if (signed_p
&& negative_p
)
543 twos_complement (c_mpz
, c_size
);
544 mpz_neg (c_mpz
, c_mpz
);
547 result
= scm_from_mpz (c_mpz
);
548 mpz_clear (c_mpz
); /* FIXME: Needed? */
554 bytevector_large_set (char *c_bv
, size_t c_size
, int signed_p
,
555 SCM value
, SCM endianness
)
557 size_t word_count
, value_size
;
559 int c_endianness
, err
= 0;
561 c_endianness
= scm_is_eq (endianness
, scm_sym_big
) ? 1 : -1;
564 scm_to_mpz (value
, c_mpz
);
565 if (mpz_sgn (c_mpz
) < 0)
567 if (EXPECT_TRUE (signed_p
))
569 mpz_neg (c_mpz
, c_mpz
);
570 twos_complement (c_mpz
, c_size
);
579 value_size
= (mpz_sizeinbase (c_mpz
, 2) + (8 * c_size
)) / (8 * c_size
);
580 if (EXPECT_FALSE (value_size
> c_size
))
586 mpz_export (c_bv
, &word_count
, 1 /* word order doesn't matter */,
587 c_size
, c_endianness
,
588 0 /* nails */, c_mpz
);
589 if (EXPECT_FALSE (word_count
!= 1))
598 #define GENERIC_INTEGER_ACCESSOR_PROLOGUE(_sign) \
599 unsigned c_len, c_index, c_size; \
602 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv); \
603 c_index = scm_to_uint (index); \
604 c_size = scm_to_uint (size); \
606 c_len = SCM_R6RS_BYTEVECTOR_LENGTH (bv); \
607 c_bv = (char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv); \
609 /* C_SIZE must have its 3 higher bits set to zero so that \
610 multiplying it by 8 yields a number that fits in an \
612 if (EXPECT_FALSE ((c_size == 0) || (c_size >= (ULONG_MAX >> 3L)))) \
613 scm_out_of_range (FUNC_NAME, size); \
614 if (EXPECT_FALSE (c_index + c_size > c_len)) \
615 scm_out_of_range (FUNC_NAME, index);
618 #define BV_SIGNED_signed 1
619 #define BV_SIGNED_unsigned 0
621 /* Template of an integer reference function. */
622 #define GENERIC_INTEGER_REF(_sign) \
630 swap = !scm_is_eq (endianness, native_endianness); \
634 value = *(_sign char *) c_bv; \
637 value = * (INT_TYPE (16, _sign) *) c_bv; \
639 value = (INT_TYPE (16, _sign)) bswap_16 (value); \
645 result = SCM_I_MAKINUM ((_sign int) value); \
648 result = bytevector_large_ref ((char *) c_bv, \
650 BV_SIGNED_ ## _sign, endianness); \
655 bytevector_signed_ref (const char *c_bv
, size_t c_size
, SCM endianness
)
657 GENERIC_INTEGER_REF (signed);
661 bytevector_unsigned_ref (const char *c_bv
, size_t c_size
, SCM endianness
)
663 GENERIC_INTEGER_REF (unsigned);
667 /* Template of an integer assignment function. */
668 #define GENERIC_INTEGER_SET(_sign) \
673 if (EXPECT_FALSE (!SCM_I_INUMP (value))) \
676 c_value = SCM_I_INUM (value); \
680 if (EXPECT_TRUE (INT_VALID_P (8, _sign) (c_value))) \
681 * (_sign char *) c_bv = (_sign char) c_value; \
687 if (EXPECT_TRUE (INT_VALID_P (16, _sign) (c_value))) \
690 INT_TYPE (16, _sign) c_value16; \
692 swap = !scm_is_eq (endianness, native_endianness); \
695 swap ? bswap_16 (c_value) : c_value; \
696 * (INT_TYPE (16, _sign) *) c_bv = c_value16; \
710 err = bytevector_large_set (c_bv, c_size, \
711 BV_SIGNED_ ## _sign, \
712 value, endianness); \
720 scm_out_of_range (FUNC_NAME, value); \
724 bytevector_signed_set (char *c_bv
, size_t c_size
,
725 SCM value
, SCM endianness
,
726 const char *func_name
)
727 #define FUNC_NAME func_name
729 GENERIC_INTEGER_SET (signed);
734 bytevector_unsigned_set (char *c_bv
, size_t c_size
,
735 SCM value
, SCM endianness
,
736 const char *func_name
)
737 #define FUNC_NAME func_name
739 GENERIC_INTEGER_SET (unsigned);
743 #undef GENERIC_INTEGER_SET
744 #undef GENERIC_INTEGER_REF
745 #undef BV_SIGNED_unsigned
746 #undef BV_SIGNED_signed
749 SCM_DEFINE (scm_r6rs_bytevector_uint_ref
, "bytevector-uint-ref", 4, 0, 0,
750 (SCM bv
, SCM index
, SCM endianness
, SCM size
),
751 "Return the @var{size}-octet long unsigned integer at index "
752 "@var{index} in @var{bv}.")
753 #define FUNC_NAME s_scm_r6rs_bytevector_uint_ref
755 GENERIC_INTEGER_ACCESSOR_PROLOGUE (unsigned);
757 return (bytevector_unsigned_ref (&c_bv
[c_index
], c_size
, endianness
));
761 SCM_DEFINE (scm_r6rs_bytevector_sint_ref
, "bytevector-sint-ref", 4, 0, 0,
762 (SCM bv
, SCM index
, SCM endianness
, SCM size
),
763 "Return the @var{size}-octet long unsigned integer at index "
764 "@var{index} in @var{bv}.")
765 #define FUNC_NAME s_scm_r6rs_bytevector_sint_ref
767 GENERIC_INTEGER_ACCESSOR_PROLOGUE (signed);
769 return (bytevector_signed_ref (&c_bv
[c_index
], c_size
, endianness
));
773 SCM_DEFINE (scm_r6rs_bytevector_uint_set_x
, "bytevector-uint-set!", 5, 0, 0,
774 (SCM bv
, SCM index
, SCM value
, SCM endianness
, SCM size
),
775 "Set the @var{size}-octet long unsigned integer at @var{index} "
777 #define FUNC_NAME s_scm_r6rs_bytevector_uint_set_x
779 GENERIC_INTEGER_ACCESSOR_PROLOGUE (unsigned);
781 bytevector_unsigned_set (&c_bv
[c_index
], c_size
, value
, endianness
,
784 return SCM_UNSPECIFIED
;
788 SCM_DEFINE (scm_r6rs_bytevector_sint_set_x
, "bytevector-sint-set!", 5, 0, 0,
789 (SCM bv
, SCM index
, SCM value
, SCM endianness
, SCM size
),
790 "Set the @var{size}-octet long signed integer at @var{index} "
792 #define FUNC_NAME s_scm_r6rs_bytevector_sint_set_x
794 GENERIC_INTEGER_ACCESSOR_PROLOGUE (signed);
796 bytevector_signed_set (&c_bv
[c_index
], c_size
, value
, endianness
,
799 return SCM_UNSPECIFIED
;
805 /* Operations on integers of arbitrary size. */
807 #define INTEGERS_TO_LIST(_sign) \
810 size_t i, c_len, c_size; \
812 SCM_VALIDATE_R6RS_BYTEVECTOR (1, bv); \
813 SCM_VALIDATE_SYMBOL (2, endianness); \
814 c_size = scm_to_uint (size); \
816 c_bv = (char *) SCM_R6RS_BYTEVECTOR_CONTENTS (bv); \
817 c_len = SCM_R6RS_BYTEVECTOR_LENGTH (bv); \
819 lst = scm_make_list (scm_from_uint (c_len / c_size), SCM_UNSPECIFIED); \
820 for (i = 0, pair = lst; \
821 i <= c_len - c_size; \
822 i += c_size, c_bv += c_size, pair = SCM_CDR (pair)) \
825 bytevector_ ## _sign ## _ref (c_bv, c_size, \
831 SCM_DEFINE (scm_r6rs_bytevector_to_sint_list
, "bytevector->sint-list",
833 (SCM bv
, SCM endianness
, SCM size
),
834 "Return a list of signed integers of @var{size} octets "
835 "representing the contents of @var{bv}.")
836 #define FUNC_NAME s_scm_r6rs_bytevector_to_sint_list
838 INTEGERS_TO_LIST (signed);
842 SCM_DEFINE (scm_r6rs_bytevector_to_uint_list
, "bytevector->uint-list",
844 (SCM bv
, SCM endianness
, SCM size
),
845 "Return a list of unsigned integers of @var{size} octets "
846 "representing the contents of @var{bv}.")
847 #define FUNC_NAME s_scm_r6rs_bytevector_to_sint_list
849 INTEGERS_TO_LIST (unsigned);
853 #undef INTEGER_TO_LIST
856 #define INTEGER_LIST_TO_BYTEVECTOR(_sign) \
858 size_t c_len, c_size; \
859 char *c_bv, *c_bv_ptr; \
861 SCM_VALIDATE_LIST_COPYLEN (1, lst, c_len); \
862 SCM_VALIDATE_SYMBOL (2, endianness); \
863 c_size = scm_to_uint (size); \
865 if (EXPECT_FALSE ((c_size == 0) || (c_size >= (ULONG_MAX >> 3L)))) \
866 scm_out_of_range (FUNC_NAME, size); \
868 c_bv = scm_gc_malloc (c_len * c_size, SCM_GC_BYTEVECTOR); \
870 /* FIXME: We leak C_BV here if one of the elements in LST is incorrect \
871 but `scm_dynwind_free ()' isn't appropriate. */ \
873 for (c_bv_ptr = c_bv; \
874 !scm_is_null (lst); \
875 lst = SCM_CDR (lst), c_bv_ptr += c_size) \
877 bytevector_ ## _sign ## _set (c_bv_ptr, c_size, \
878 SCM_CAR (lst), endianness, \
882 result = make_bytevector (c_len * c_size, (signed char *) c_bv); \
887 SCM_DEFINE (scm_r6rs_uint_list_to_bytevector
, "uint-list->bytevector",
889 (SCM lst
, SCM endianness
, SCM size
),
890 "Return a bytevector containing the unsigned integers "
891 "listed in @var{lst} and encoded on @var{size} octets "
892 "according to @var{endianness}.")
893 #define FUNC_NAME s_scm_r6rs_uint_list_to_bytevector
895 INTEGER_LIST_TO_BYTEVECTOR (unsigned);
899 SCM_DEFINE (scm_r6rs_sint_list_to_bytevector
, "sint-list->bytevector",
901 (SCM lst
, SCM endianness
, SCM size
),
902 "Return a bytevector containing the signed integers "
903 "listed in @var{lst} and encoded on @var{size} octets "
904 "according to @var{endianness}.")
905 #define FUNC_NAME s_scm_r6rs_sint_list_to_bytevector
907 INTEGER_LIST_TO_BYTEVECTOR (signed);
911 #undef INTEGER_LIST_TO_BYTEVECTOR
915 /* Operations on 16-bit integers. */
917 SCM_DEFINE (scm_r6rs_bytevector_u16_ref
, "bytevector-u16-ref",
919 (SCM bv
, SCM index
, SCM endianness
),
920 "Return the unsigned 16-bit integer from @var{bv} at "
922 #define FUNC_NAME s_scm_r6rs_bytevector_u16_ref
924 INTEGER_REF (16, unsigned);
928 SCM_DEFINE (scm_r6rs_bytevector_s16_ref
, "bytevector-s16-ref",
930 (SCM bv
, SCM index
, SCM endianness
),
931 "Return the signed 16-bit integer from @var{bv} at "
933 #define FUNC_NAME s_scm_r6rs_bytevector_s16_ref
935 INTEGER_REF (16, signed);
939 SCM_DEFINE (scm_r6rs_bytevector_u16_native_ref
, "bytevector-u16-native-ref",
942 "Return the unsigned 16-bit integer from @var{bv} at "
943 "@var{index} using the native endianness.")
944 #define FUNC_NAME s_scm_r6rs_bytevector_u16_native_ref
946 INTEGER_NATIVE_REF (16, unsigned);
950 SCM_DEFINE (scm_r6rs_bytevector_s16_native_ref
, "bytevector-s16-native-ref",
953 "Return the unsigned 16-bit integer from @var{bv} at "
954 "@var{index} using the native endianness.")
955 #define FUNC_NAME s_scm_r6rs_bytevector_u16_native_ref
957 INTEGER_NATIVE_REF (16, signed);
961 SCM_DEFINE (scm_r6rs_bytevector_u16_set_x
, "bytevector-u16-set!",
963 (SCM bv
, SCM index
, SCM value
, SCM endianness
),
964 "Store @var{value} in @var{bv} at @var{index} according to "
966 #define FUNC_NAME s_scm_r6rs_bytevector_u16_set_x
968 INTEGER_SET (16, unsigned);
972 SCM_DEFINE (scm_r6rs_bytevector_s16_set_x
, "bytevector-s16-set!",
974 (SCM bv
, SCM index
, SCM value
, SCM endianness
),
975 "Store @var{value} in @var{bv} at @var{index} according to "
977 #define FUNC_NAME s_scm_r6rs_bytevector_s16_set_x
979 INTEGER_SET (16, signed);
983 SCM_DEFINE (scm_r6rs_bytevector_u16_native_set_x
, "bytevector-u16-native-set!",
985 (SCM bv
, SCM index
, SCM value
),
986 "Store the unsigned integer @var{value} at index @var{index} "
987 "of @var{bv} using the native endianness.")
988 #define FUNC_NAME s_scm_r6rs_bytevector_u16_native_set_x
990 INTEGER_NATIVE_SET (16, unsigned);
994 SCM_DEFINE (scm_r6rs_bytevector_s16_native_set_x
, "bytevector-s16-native-set!",
996 (SCM bv
, SCM index
, SCM value
),
997 "Store the signed integer @var{value} at index @var{index} "
998 "of @var{bv} using the native endianness.")
999 #define FUNC_NAME s_scm_r6rs_bytevector_u16_native_set_x
1001 INTEGER_NATIVE_SET (16, signed);
1005 /* FIXME: Unfinished! */
1008 /* Initialization. */
1011 scm_init_r6rs_bytevector (void)
1013 #include "bytevector.c.x"
1015 #ifdef WORDS_BIGENDIAN
1016 native_endianness
= scm_sym_big
;
1018 native_endianness
= scm_sym_little
;
1022 /* arch-tag: e5a30664-90fc-40d7-8036-ee767aea5fb6