- chr = SCM_CHAR (char_pred);
- idx = cstart;
- while (idx < cend)
- {
- if (cstr[idx] != chr)
- ls = scm_cons (SCM_MAKE_CHAR (cstr[idx]), ls);
- cstr = scm_i_string_chars (s);
- idx++;
- }
- result = scm_reverse_list_to_string (ls);
+ /* strip leading matches by incrementing cstart */
+ while (cstart < cend && scm_i_string_ref (s, cstart) == SCM_CHAR(char_pred))
+ cstart++;
+
+ /* strip trailing matches by decrementing cend */
+ while (cend > cstart && scm_i_string_ref (s, cend-1) == SCM_CHAR (char_pred))
+ cend--;
+
+ /* count chars to be kept */
+ count = 0;
+ for (idx = cstart; idx < cend; idx++)
+ if (scm_i_string_ref (s, idx) != SCM_CHAR (char_pred))
+ count++;
+
+ if (count == cend - cstart)
+ {
+ /* whole of cstart to cend is to be kept, return a copy-on-write
+ substring */
+ result_substring:
+ result = scm_i_substring (s, cstart, cend);
+ }
+ else
+ {
+ int i = 0;
+ /* new string for retained portion */
+ result = scm_i_make_string (count, NULL, 0);
+ result = scm_i_string_start_writing (result);
+ /* decrement "count" in this loop as well as using idx, so that if
+ another thread is simultaneously changing "s" there's no chance
+ it'll make us copy more than count characters */
+ for (idx = cstart; idx < cend && count != 0; idx++)
+ {
+ scm_t_wchar c = scm_i_string_ref (s, idx);
+ if (c != SCM_CHAR (char_pred))
+ {
+ scm_i_string_set_x (result, i, c);
+ i++;
+ count--;
+ }
+ }
+ scm_i_string_stop_writing ();
+ }