CORD CORD_substr(CORD x, size_t i, size_t n) { size_t len = CORD_len(x); if (i >= len || n == 0) return(0); if (i + n > len) n = len - i; return(CORD_substr_checked(x, i, n)); }
CORD CORD_substr(CORD x, size_t i, size_t n) { register size_t len = CORD_len(x); if (i >= len || n <= 0) return(0); /* n < 0 is impossible in a correct C implementation, but */ /* quite possible under SunOS 4.X. */ if (i + n > len) n = len - i; return(CORD_substr_checked(x, i, n)); }
/* A version of CORD_substr that assumes i >= 0, n > 0, and i + n < length(x).*/ CORD CORD_substr_checked(CORD x, size_t i, size_t n) { if (CORD_IS_STRING(x)) { if (n > SUBSTR_LIMIT) { return(CORD_substr_closure(x, i, n, CORD_index_access_fn)); } else { char * result = (char *)GC_MALLOC_ATOMIC(n + 1); if (result == 0) OUT_OF_MEMORY; strncpy(result, x+i, n); result[n] = '\0'; return(result); } } else if (IS_CONCATENATION(x)) { struct Concatenation * conc = &(((CordRep *)x) -> concatenation); size_t left_len = LEFT_LEN(conc); size_t right_len = conc -> len - left_len; if (i >= left_len) { if (n == right_len) return(conc -> right); return(CORD_substr_checked(conc -> right, i - left_len, n)); } else if (i+n <= left_len) { if (n == left_len) return(conc -> left); return(CORD_substr_checked(conc -> left, i, n)); } else { /* Need at least one character from each side. */ CORD left_part; CORD right_part; size_t left_part_len = left_len - i; if (i == 0) { left_part = conc -> left; } else { left_part = CORD_substr_checked(conc -> left, i, left_part_len); } if (i + n == right_len + left_len) { right_part = conc -> right; } else { right_part = CORD_substr_checked(conc -> right, 0, n - left_part_len); } return(CORD_cat(left_part, right_part)); } } else /* function */ { if (n > SUBSTR_LIMIT) { if (IS_SUBSTR(x)) { /* Avoid nesting substring nodes. */ struct Function * f = &(((CordRep *)x) -> function); struct substr_args *descr = (struct substr_args *)(f -> client_data); return(CORD_substr_closure((CORD)descr->sa_cord, i + descr->sa_index, n, f -> fn)); } else { return(CORD_substr_closure(x, i, n, CORD_apply_access_fn)); } } else { char * result; struct Function * f = &(((CordRep *)x) -> function); char buf[SUBSTR_LIMIT+1]; char * p = buf; size_t j; size_t lim = i + n; for (j = i; j < lim; j++) { char c = (*(f -> fn))(j, f -> client_data); if (c == '\0') { return(CORD_substr_closure(x, i, n, CORD_apply_access_fn)); } *p++ = c; } result = (char *)GC_MALLOC_ATOMIC(n + 1); if (result == 0) OUT_OF_MEMORY; memcpy(result, buf, n); result[n] = '\0'; return(result); } } }