Ejemplo n.º 1
0
static ss_t *aux_rtrim(ss_t **s, const sbool_t cat, const ss_t *src)
{
	ASSERT_RETURN_IF(!s, ss_void);
	if (!src)
		src = ss_void;
	const size_t ss = sd_get_size(src),
		     at = (cat && *s) ? sd_get_size(*s) : 0;
	if (ss > 0) {
		const sbool_t aliasing = *s == src;
		const char *ps = get_str_r(src);
		size_t i = ss - 1;
		for (; i > 0 && isspace(ps[i]); i--);
		if (isspace(ps[i]))
			i--;
		const size_t nspaces = ss - i - 1,
			     copy_size = ss - nspaces,
			     out_size = at + copy_size,
			     cat_usize = cat ? get_unicode_size(*s) : 0,
			     src_usize = *s ? get_unicode_size(*s) : 0;
		if (ss_reserve(s, out_size) >= out_size) {
			char *pt = get_str(*s);
			if (!aliasing)
				 memcpy(pt + at, ps, copy_size);
			set_size(*s, out_size);
			set_unicode_size(*s, cat_usize + src_usize - nspaces);
		}
	} else {
		if (cat)
			ss_check(s);
		else
			ss_clear(s);
	}
	return *s;
}
Ejemplo n.º 2
0
static ss_t *aux_resize(ss_t **s, const sbool_t cat, const ss_t *src,
			const size_t n, char fill_byte)
{
	ASSERT_RETURN_IF(!s, ss_void);
	if (!src)
		src = ss_void;
	const size_t src_size = sd_get_size(src),
		     at = (cat && *s) ? sd_get_size(*s) : 0,
		     out_size = at + n;  /* BEHAVIOR: n overflow TODO */
	const sbool_t aliasing = *s == src;
	if (src_size < n) { /* fill */
		if (ss_reserve(s, out_size) >= out_size) {
			char *o = get_str(*s);
			if (!aliasing) {
				const char *p = get_str_r(src);
				memcpy(o + at, p, src_size);
			}
			memset(o + at + src_size, fill_byte,
				n - src_size);
			set_size(*s, out_size);
		}
	} else { /* else: cut (implicit) */
		if (ss_reserve(s, out_size) >= out_size) {
			if (!aliasing)
				memcpy(get_str(*s) + at, get_str_r(src), n);
			set_size(*s, out_size);
		}
	}
	return *s;
}
Ejemplo n.º 3
0
static size_t get_cmp_size(const ss_t *s1, const ss_t *s2)
{
	if (!s1 || !s2)
		return 0;
	size_t s1_size = sd_get_size(s1), s2_size = sd_get_size(s2);
	return S_MAX(s1_size, s2_size);
}
Ejemplo n.º 4
0
static ss_t *aux_toenc(ss_t **s, const sbool_t cat, const ss_t *src, senc_f_t f)
{
	ASSERT_RETURN_IF(!s, ss_void);
	if (!src)
		src = ss_void;
	const int aliasing = *s == src;
	const size_t in_size = sd_get_size(src),
		     at = (cat && *s) ? sd_get_size(*s) : 0,
		     out_size = at + f(NULL, in_size, NULL);
	if (ss_reserve(s, out_size) >= out_size) {
		const ss_t *src1 = aliasing ? *s : src;
		f((const unsigned char *)get_str_r(src1), in_size,
		  (unsigned char *)get_str(*s) + at);
		if (at == 0) {
			set_unicode_size_cached(*s, S_TRUE);
			set_unicode_size(*s, in_size * 2);
		} else { /* cat */
			if (is_unicode_size_cached(*s) &&
			    at == sd_get_size(*s))
				set_unicode_size(*s, get_unicode_size(*s) +
						     in_size * 2);
			else
				set_unicode_size_cached(*s, S_FALSE);
		}
		set_size(*s, out_size);
	}
	return ss_check(s);
}
Ejemplo n.º 5
0
ss_t *ss_cat_aux(ss_t **s, const size_t nargs, const ss_t *s1, ...)
{
	ASSERT_RETURN_IF(!s, ss_void);
	if (s1 && sd_get_size(s1) > 0) {
		va_list ap;
		size_t extra_size = sd_get_size(s1);
		const ss_t *s_next, *s0 = *s;
		const size_t ss0 = *s ? sd_get_size(s0) : 0,
			     uss0 = s0 ? get_unicode_size(s0) : 0;
		va_start(ap, s1);
		size_t i = 1;
		for (; i < nargs; i++) {
			s_next = va_arg(ap, const ss_t *);
			if (s_next)
				extra_size += sd_get_size(s_next);
		}
		va_end(ap);
		if (ss_grow(s, extra_size)) {
			ss_cat_aliasing(s, s0, ss0, uss0, s1);
			if (nargs == 1)
				return *s;
			va_start(ap, s1);
			for (i = 1; i < nargs; i++) {
				s_next = va_arg(ap, const ss_t *);
				if (s_next)
					ss_cat_aliasing(s, s0, ss0, uss0,
							s_next);
			}
			va_end(ap);
		}
	}
Ejemplo n.º 6
0
static ss_t *aux_erase(ss_t **s, const sbool_t cat, const ss_t *src,
		       const size_t off, const size_t n)
{
	ASSERT_RETURN_IF(!s, ss_void);
	if (!src)
		src = ss_void;
	const size_t ss0 = sd_get_size(src),
			   at = (cat && *s) ? sd_get_size(*s) : 0;
	const sbool_t overflow = off + n > ss0;
	const size_t src_size = overflow ? ss0 - off : n,
		     copy_size = ss0 - off - src_size;
	if (*s == src) { /* BEHAVIOR: aliasing: copy-only */
		if (off + n >= ss0) { /* tail clean cut */
			set_size(*s, off);
		} else {
			char *ps = get_str(*s);
			memmove(ps + off, ps + off + n, copy_size);
			set_size(*s, ss0 - n);
		}
		set_unicode_size_cached(*s, S_FALSE);
	} else { /* copy or cat */
		const size_t out_size = at + off + copy_size;
		if (ss_reserve(s, out_size) >= out_size) {
			char *po = get_str(*s);
			memcpy(po + at, get_str_r(src), off);
			memcpy(po + at + off,
			       get_str_r(src) + off + n, copy_size);
			set_size(*s, out_size);
			set_unicode_size_cached(*s, S_FALSE);
		}
	}
	return ss_check(s);
}
Ejemplo n.º 7
0
static ss_t *aux_resize_u(ss_t **s, const sbool_t cat, ss_t *src,
			  const size_t u_chars, int fill_char)
{
	ASSERT_RETURN_IF(!s, ss_void);
	if (!src)
		src = ss_void;
	const size_t at = (cat && *s) ? sd_get_size(*s) : 0,
		     char_size = sc_wc_to_utf8_size(fill_char),
		     current_u_chars = ss_len_u(src);
	RETURN_IF(u_chars == current_u_chars, ss_check(s)); /* same */
	const sbool_t aliasing = *s == src;
	const size_t srcs = sd_get_size(src);
	if (current_u_chars < u_chars) { /* fill */
		const size_t new_elems = u_chars - current_u_chars,
			     at_inc = srcs + new_elems * char_size;
		SS_OVERFLOW_CHECK(s, at, at_inc);
		const size_t out_size = at + at_inc;
		if (ss_reserve(s, out_size) >= out_size) {
			if (!cat && !aliasing) /* copy */
				ss_clear(s);
			if (!aliasing) {
				memcpy(get_str(*s) + at, get_str_r(src), srcs);
				inc_unicode_size(*s, current_u_chars);
				inc_size(*s, srcs);
			}
			size_t i = 0;
			for (; i < new_elems; i++)
				ss_cat_char(s, fill_char);
		}
	} else { /* cut */
		const char *ps = get_str_r(src);
		size_t actual_unicode_count = 0;
		const size_t head_size = sc_unicode_count_to_utf8_size(
						ps, 0, srcs, u_chars,
						&actual_unicode_count);
		SS_OVERFLOW_CHECK(s, at, head_size);
		const size_t out_size = at + head_size;
		S_ASSERT(u_chars == actual_unicode_count);
		if (!aliasing) { /* copy or cat */
			if (ss_reserve(s, out_size) >= out_size) {
				if (!cat && !aliasing) /* copy */
					ss_clear(s);
				memcpy(get_str(*s) + at, ps, head_size);
				inc_unicode_size(*s, actual_unicode_count);
				inc_size(*s, head_size);
			}
		} else { /* cut */
			set_size(*s, head_size);
			set_unicode_size(*s, actual_unicode_count);
		}
	}
	return *s;
}
Ejemplo n.º 8
0
ss_t *ss_cpy_substr_u(ss_t **s, const ss_t *src, const size_t char_off,
		      const size_t n)
{
	ASSERT_RETURN_IF(!s, ss_void);
	ASSERT_RETURN_IF(!src || !n, ss_clear(s)); /* BEHAVIOR: empty */
	if (*s == src) { /* aliasing */
		char *ps = get_str(*s);
		size_t actual_unicode_count = 0;
		const size_t ss = sd_get_size(*s);
		const size_t off = sc_unicode_count_to_utf8_size(ps, 0,
					ss, char_off, &actual_unicode_count);
		const size_t n_size = sc_unicode_count_to_utf8_size(ps,
			off, ss, n, &actual_unicode_count);
		ASSERT_RETURN_IF(off >= ss, ss_clear(s)); /* BEHAVIOR: empty */
		const size_t copy_size = S_MIN(ss - off, n_size);
		memmove(ps, ps + off, copy_size);
		set_size(*s, copy_size);
		if (n == actual_unicode_count) {
			set_unicode_size_cached(*s, S_TRUE);
			set_unicode_size(*s, n);
		} else { /* BEHAVIOR: cache lost */
			set_unicode_size_cached(*s, S_FALSE);
		}
	} else {
		if (*s)
			ss_clear(s);
		ss_cat_substr_u(s, src, char_off, n);
	}
	return ss_check(s);
}
Ejemplo n.º 9
0
void scsi_sd_read_capacity(uint8_t lun, uint32_t *bcount, uint16_t *bsize) 
{
    const sdio_t *sdio = (const sdio_t*)scsi_lun[lun].info;

    *bcount = sd_get_size(*sdio);
    *bsize  = 512u;
}
Ejemplo n.º 10
0
static ss_t *aux_erase_u(ss_t **s, const sbool_t cat, const ss_t *src,
			 const size_t char_off, const size_t n)
{
	ASSERT_RETURN_IF(!s, ss_void);
	if (!src)
		src = ss_void;
	const char *ps = get_str_r(src);
	const size_t sso0 = *s ? sd_get_size(*s) : 0,
		     ss0 = sd_get_size(src),
		     head_size = sc_unicode_count_to_utf8_size(ps, 0, ss0,
							char_off, NULL);
	RETURN_IF(head_size >= ss0, ss_check(s)); /* BEHAVIOR */
	size_t actual_n = 0;
	const size_t cus = *s ? get_unicode_size(*s) : 0,
		     cut_size = sc_unicode_count_to_utf8_size(ps,
				head_size, ss0, n, &actual_n),
		     tail_size = ss0 - cut_size - head_size;
	size_t out_size = ss0 - cut_size,
	       prefix_usize = 0;
	if (*s == src) { /* aliasing: copy-only */
		char *po = get_str(*s);
		memmove(po + head_size, ps + head_size + cut_size, tail_size);
	} else { /* copy/cat */
		const size_t at = (cat && *s) ? sd_get_size(*s) : 0;
		out_size += at;
		if (ss_reserve(s, out_size) >= out_size) {
			char *po = get_str(*s);
			memcpy(po + at, get_str_r(src), head_size);
			memcpy(po + at + head_size,
			       get_str_r(src) + head_size + cut_size,
			       tail_size);
			set_size(*s, out_size);
			if (is_unicode_size_cached(*s) &&
			    (at == 0 || at == sso0)) {
				prefix_usize = get_unicode_size(*s);
			} else {
				set_unicode_size_cached(*s, S_FALSE);
			}
		}
	}
	if (cus > actual_n)
		set_unicode_size(*s, prefix_usize + cus - actual_n);
	else /* BEHAVIOR: unicode char count invalidation */
		set_unicode_size_cached(*s, S_FALSE);
	set_size(*s, out_size);
	return ss_check(s);
}
Ejemplo n.º 11
0
size_t ss_len_left(const ss_t *s)
{
	ASSERT_RETURN_IF(!s, 0);
	const size_t size = sd_get_size(s),
		     max_size = ss_get_max_size(s);
	S_ASSERT(s && max_size > size);
	return (s && max_size > size) ? max_size - size : 0;
}
Ejemplo n.º 12
0
static ss_t *ss_cat_aliasing(ss_t **s, const ss_t *s0, const size_t s0_size,
			     const size_t s0_unicode_size, const ss_t *src)
{
	return src == s0 ? ss_cat_cn_raw(s, get_str(*s), 0, s0_size,
					    s0_unicode_size) :
			   ss_cat_cn_raw(s, get_str_r(src), 0, sd_get_size(src),
					    get_unicode_size(src));
}
Ejemplo n.º 13
0
static ss_t *aux_ltrim(ss_t **s, const sbool_t cat, const ss_t *src)
{
	ASSERT_RETURN_IF(!s, ss_void);
	if (!src)
		src = ss_void;
	const size_t ss = sd_get_size(src);
	if (ss > 0) {
		const sbool_t aliasing = *s == src;
		const char *ps = get_str_r(src);
		size_t i = 0;
		for (; i < ss && isspace(ps[i]); i++);
		size_t at, cat_usize;
		if (cat) {
			if (*s) {
				at = sd_get_size(*s);
				cat_usize = get_unicode_size(*s);
			} else {
				at = cat_usize = 0;
			}
		} else {
			at = cat_usize = 0;
		}
		const size_t out_size = at + ss - i,
			     src_usize = get_unicode_size(src);
		if (ss_reserve(s, out_size) >= out_size) {
			char *pt = get_str(*s);
			if (!aliasing) /* copy or cat: shift data */
				memcpy(pt + at, ps + i, ss - i);
			else
				if (i > 0) /* copy: shift data */
					memmove(pt, ps + i, ss - i);
			set_size(*s, at + ss - i);
			set_unicode_size(*s, cat_usize + src_usize - i);
		}
	} else {
		if (cat)
			ss_check(s);
		else
			ss_clear(s);
	}
	return *s;
}
Ejemplo n.º 14
0
size_t ss_len_u(ss_t *s)
{
	S_ASSERT(s);
	if (!s)
		return 0;
	if (is_unicode_size_cached(s))
		return get_unicode_size(s);
	/* Not cached, so cache it: */
	const char *p = get_str_r(s);
	const size_t ss = sd_get_size(s),
		     cached_uc_size = sc_utf8_count_chars(p, ss);
	set_unicode_size_cached(s, S_TRUE);
	set_unicode_size(s, cached_uc_size);
	return cached_uc_size;
}
Ejemplo n.º 15
0
static void ss_reconfig(ss_t *s, size_t new_alloc_size, const size_t new_mt_sz)
{
	size_t size = sd_get_size(s), unicode_size = get_unicode_size(s);
	char *s_str = get_str(s);
	/* Compute offset on target location: */
	struct SSTR_Small sm;
	struct SSTR_Full sf;
	const size_t s2_off = new_mt_sz == SS_METAINFO_SMALL?
				sm.str -(char *)&sm : sf.str - (char *)&sf;
	/* Convert string: */
	memmove((char *)s + s2_off, s_str, size);
	s->is_full = sd_alloc_size_to_is_big(new_alloc_size, &ssf);
	set_size(s, size);
	set_alloc_size(s, new_alloc_size);
	set_unicode_size(s, unicode_size);
}
Ejemplo n.º 16
0
/* BEHAVIOR: aliasing is supported, e.g. append(&a, a) */
static ss_t *ss_cat_cn_raw(ss_t **s, const char *src, const size_t src_off,
			   const size_t src_size, const size_t src_usize)
{
	ASSERT_RETURN_IF(!s, ss_void);
	if (src && src_size > 0) {
		const size_t off = *s ? sd_get_size(*s) : 0;
		if (ss_grow(s, src_size)) {
			memmove(get_str(*s) + off, src + src_off, src_size);
			inc_size(*s, src_size);
			if (is_unicode_size_cached(*s)) {
				if (src_usize > 0)
					inc_unicode_size(*s, src_usize);
				else
					set_unicode_size_cached(*s, S_FALSE);
			}
		}
	}
	return ss_check(s);
}
Ejemplo n.º 17
0
ss_t *ss_cpy_substr(ss_t **s, const ss_t *src, const size_t off, const size_t n)
{
	ASSERT_RETURN_IF(!s, ss_void);
	ASSERT_RETURN_IF(!src || !n, ss_clear(s)); /* BEHAVIOR: empty */
	if (*s == src) { /* aliasing */
		char *ps = get_str(*s);
		const size_t ss = sd_get_size(*s);
		ASSERT_RETURN_IF(off >= ss, ss_clear(s)); /* BEHAVIOR: empty */
		const size_t copy_size = S_MIN(ss - off, n);
		memmove(ps, ps + off, copy_size);
		set_size(*s, copy_size);
		set_unicode_size_cached(*s, S_FALSE); /* BEHAVIOR: cache lost */
	} else {
		if (*s)
			ss_clear(s);
		ss_cat_substr(s, src, off, n);
	}
	return ss_check(s);
}
Ejemplo n.º 18
0
static ss_t *aux_toint(ss_t **s, const sbool_t cat, const sint_t num)
{
	ASSERT_RETURN_IF(!s, ss_void);
	char btmp[128], *p = btmp + sizeof(btmp) - 1;
	sint_t n = num < 0 ? -num : num;
	do {
		*p-- = '0' + n % 10;
		n /= 10;
	} while (n);
	if (num < 0)
		*p-- = '-';
	const size_t off = (size_t)((p - (char *)btmp) + 1),
		     digits = sizeof(btmp) - off,
		     at = (cat && *s) ? sd_get_size(*s) : 0;
	SS_OVERFLOW_CHECK(s, at, digits);
	const size_t out_size = at + digits;
        if (ss_reserve(s, out_size) >= out_size) {
		memcpy(get_str(*s) + at, btmp + off, digits);
		set_size(*s, out_size);
		inc_unicode_size(*s, digits);
	}
	return *s;
}
Ejemplo n.º 19
0
scsi_cmdret_t scsi_sd_read10( SCSI_PARAMS )
{
    const sdio_t   *sdio     = (const sdio_t*)scsi_lun[lun].info;
    scsi_cdb10_t   *cdb10    = (scsi_cdb10_t *)cmd;
    //uint8_t       DPO      = (cdb10->cdb_info >> 4) & 0x1;
    //uint8_t       FUA      = (cdb10->cdb_info >> 3) & 0x1;
    uint32_t        lba      = msbtohost32(cdb10->lba);
    uint32_t        nblocks  = msbtohost16(cdb10->length);
    uint32_t        sdsize   = sd_get_size(*sdio);
    sd_card_type_t  sdtype   = sd_get_type(*sdio);
    sd_error_t      sdret;
    scsi_cmdret_t   ret;
    uint32_t        la       = (sdtype != SDHC) ? lba * BLOCKSIZE : lba;

    sdret             = SD_NO_ERROR;
    sd_transfer_ended = false;
    sd_set_transfer_handler(*sdio, sd_transfer_handler);

    if ((lba + nblocks - 1) >= sdsize)
    {
	log_error("SCSI Read(10), read beyond limit (limit 0x%08x, request 0x%08x / +%d)",sdsize,lba,nblocks);
	*status = SCSI_CHECK_CONDITION;
	return SCSI_CMD_DONE;
    }

    if (datamax < BLOCKSIZE)
    {
	log_error("SCSI Read(10), read buffer is smaller than a single sector (%d/%d bytes)",datalen,BLOCKSIZE);
	*status = SCSI_CHECK_CONDITION;
	return SCSI_CMD_ERROR;
    }

    sdret = sd_read_single_block(*sdio, la, data);

    if (cont == 0)
    {
	log_info("SCSI Read(10) type %d, lba 0x%08x, length %d",sdtype,lba,nblocks);
    }
    else
    {
	DBG("-%d-\n",cont);
    }

    if (sdret != SD_NO_ERROR)
    {
	log_error("SCSI Read Command Error on SD %d",sdret);
	*status = SCSI_CHECK_CONDITION;
	return SCSI_CMD_DONE;
    }

    while (!sd_transfer_ended) 
    {
	;
    }

    sdret = sd_get_status(*sdio);

    if (sdret != SD_NO_ERROR)
    {
	log_error("SCSI Read Error on SD (lba 0x%08x) ret %d",lba,sdret);
	*status = SCSI_CHECK_CONDITION;
	return SCSI_CMD_DONE;
    }

    switch (nblocks)
    {
    case 0:
	*status        = SCSI_CHECK_CONDITION;
	ret            = SCSI_CMD_ERROR;
	break;
    case 1:
	*datalen       = BLOCKSIZE;
	*status        = SCSI_GOOD;
	ret            = SCSI_CMD_DONE;
	break;
    default:
	cdb10->lba     = msbtohost32( lba     + 1 );
	cdb10->length  = msbtohost16( nblocks - 1 );
	*datalen       = BLOCKSIZE;
	*status        = SCSI_GOOD;
	ret            = SCSI_CMD_PARTIAL;
	break;
    }
    return ret;
}
Ejemplo n.º 20
0
static void inc_size(ss_t *s, const size_t inc_size)
{
	set_size(s, sd_get_size(s) + inc_size);
}
Ejemplo n.º 21
0
static ss_t *aux_toXcase(ss_t **s, const sbool_t cat, const ss_t *src,
			 sint32_t (*towX)(sint32_t))
{
	ASSERT_RETURN_IF(!s, ss_void);
	if (!src)
		src = ss_void;
	const size_t ss = sd_get_size(src),
		     sso_max = *s ? ss_get_max_size(*s) : 0;
	const char *ps = get_str_r(src);
	ss_t *out = NULL;
	const sbool_t aliasing = *s == src;
	unsigned char is_cached_usize = 0;
	ssize_t extra = sc_utf8_calc_case_extra_size(ps, 0, ss, towX);
	size_t cached_usize = 0,
	       at;
	/* If possible, keep Unicode size cached: */
	if (*s) {
		if (is_unicode_size_cached(*s) && is_unicode_size_cached(src)) {
			is_cached_usize = 1;
			cached_usize = get_unicode_size(src) +
				       get_unicode_size(*s);
		}
		at = cat ? sd_get_size(*s) : 0;
	} else { /* copy */
		if (is_unicode_size_cached(src)) {
			is_cached_usize = 1;
			cached_usize = get_unicode_size(src);
		}
		at = 0;
	}
	/* Check if it is necessary to allocate more memory: */
	size_t sso_req = extra < 0 ? (at + ss - (size_t)(-extra)) :
				     (at + ss + (size_t)extra);
	char *po0;
	if (!*s || sso_req > sso_max || (aliasing && extra > 0)) {
		if (*s && (*s)->ext_buffer) { /* BEHAVIOR */
			S_ERROR("not enough memory: strings stored in the "
				"stored in fixed-length buffer can not be "
				"resized.");
			sd_set_alloc_errors(*s);
			return ss_check(s);
		}
		out = ss_alloc(sso_req);
		if (!out) {	/* BEHAVIOR */
			S_ERROR("not enough memory: can not "
				"change character case");
			if (*s)
				sd_set_alloc_errors(*s);
			return ss_check(s);
		}
		char *pout = get_str(out);
		if (at > 0) /* cat */
			memcpy(pout, get_str(*s), at);
		po0 = pout + at;
	} else {
		po0 = get_str(*s) + at;
	}
	/* Case conversion loop: */
	size_t i = 0;
	int c = 0;
	char *po = po0,
	      u8[SSU8_MAX_SIZE];
	for (; i < ss;) {
#ifdef S_ENABLE_UTF8_7BIT_PARALLEL_CASE_OPTIMIZATIONS
		unsigned *pou = (unsigned *)po;
		const size_t i2 = sc_parallel_toX(ps, i, ss, pou, towX);
		if (i != i2) {
			po += (i2 - i);
			i = i2;
			if (i >= ss)
				break;
		}
#endif
		const size_t csize = ss_utf8_to_wc(ps, i, ss, &c, *s);
		const int c2 = towX(c);
		size_t csize2;
		if (c2 == c) {
			csize2 = csize;
			if (!aliasing)
				memcpy(po, ps + i, csize2);
		} else {
			csize2 = sc_wc_to_utf8(c2, u8, 0, SSU8_MAX_SIZE);
			memcpy(po, u8, csize2);
		}
		i += csize;
		po += csize2;
	}
	if (out) {	/* Case of using a secondary string was required */
		ss_t *s_bck = *s;
		*s = out;
		ss_free(&s_bck);
	}
	if (*s) {
		set_size(*s, sso_req);
		set_unicode_size_cached(*s, is_cached_usize);
		set_unicode_size(*s, cached_usize);
	}
	return ss_check(s);
}
Ejemplo n.º 22
0
static ss_t *aux_replace(ss_t **s, const sbool_t cat, const ss_t *src,
			 const size_t off, const ss_t *s1, const ss_t *s2)
{
	ASSERT_RETURN_IF(!s, ss_void);
	if (!s1)
		s1 = ss_void;
	if (!s2)
		s2 = ss_void;
	if (!src)
		src = ss_void;
	const size_t at = (cat && *s) ? sd_get_size(*s) : 0;
	const char *p0 = get_str_r(src),
		   *p2 = get_str_r(s2);
	const size_t l1 = sd_get_size(s1), l2 = sd_get_size(s2);
	size_t i = off, l = sd_get_size(src);
	ss_t *out = NULL;
	ssize_t size_delta = l2 > l1 ? (ssize_t)(l2 - l1) :
				       -(ssize_t)(l1 - l2);
	sbool_t aliasing = S_FALSE;
	size_t out_size = at + l;
	char *o, *o0;
	if (l2 >= l1) { /* resize required */
		size_t nfound = 0;
		/* scan required size */
		for (;; i+= l1, nfound++)
			if ((i = ss_find(src, i, s1)) == S_NPOS)
				break;
		if (nfound == 0)	/* 0 occurrences: return */
			return ss_check(s);
		if (size_delta >= 0)
			out_size += (size_t)size_delta * nfound;
		else
			out_size -= (size_t)(-size_delta) * nfound;
		/* allocate output string */
		out = ss_alloc(out_size);
		if (!out) {
			S_ERROR("not enough memory");
			sd_set_alloc_errors(*s);
			return ss_check(s);
		}
		o0 = o = get_str(out);
		/* copy prefix data (cat) */
		if (at > 0)
			memcpy(o, get_str_r(*s), at);
	} else {
		if (s && *s && *s == src) {
			aliasing = S_TRUE;
		} else {
			if (ss_reserve(s, out_size) < out_size) /* BEHAVIOR */
				return ss_check(s);
		}
		o0 = o = get_str(*s);
	}
	typedef void (*memcpy_t)(void *, const void *, size_t);
	memcpy_t f_cpy;
	if (aliasing) {
		f_cpy = (memcpy_t)memmove;
	} else {
		f_cpy = (memcpy_t)memcpy;
		o += at;
		if (off > 0)	/* copy not affected data */
			memcpy(o, p0, off);
	}
	o += off;
	size_t i_next = s1 == s2? S_NPOS : /* no replace */
			ss_find(src, i + off, s1);
	for (i = off;;) {
		/* before match copy: */
		if (i_next == S_NPOS) {
			f_cpy(o, p0 + i, l - i);
			o += (l - i);
			break;
		}
		f_cpy(o, p0 + i, i_next - i);
		o += (i_next - i);
		/* replace: */
		f_cpy(o, p2, l2);
		o += l2;
		i = i_next + l1;
		/* prepare next search: */
		i_next = ss_find(src, i, s1);
	}
	if (out) {
		ss_t *s_bck = *s;
		*s = out;
		ss_free(&s_bck);
	}
	set_size(*s, (size_t)(o - o0));
	return *s;
}