/** * @brief Delete a whole (possibly multibyte) character from a string. * @param[in] s Start of the string * @param[in] pos UTF-8 char offset from the start (not the byte offset) * @return Number of bytes deleted */ int UTF8_delete_char_at (char* s, int pos) { /* Convert the UTF-8 char offset to byte offset */ pos = UTF8_char_offset_to_byte_offset(s, pos); int start = pos; int next = pos; while (start > 0 && UTF8_CONTINUATION_BYTE(s[start])) start--; if (s[next] != 0) next++; while (s[next] != 0 && UTF8_CONTINUATION_BYTE(s[next])) next++; /* memmove is the only standard copying function that is guaranteed * to work if the source and destination overlap. */ memmove(&s[start], &s[next], strlen(&s[next]) + 1); return (next - start); }
/** * @brief copies formatted string with buffer-size checking * @param[out] dest Destination buffer * @param[in] size Size of the destination buffer * @param[in] fmt Stringformat (like printf) * @return false if overflowed - true otherwise */ bool Com_sprintf (char* dest, size_t size, const char* fmt, ...) { va_list ap; int len; if (!fmt) return false; va_start(ap, fmt); len = Q_vsnprintf(dest, size, fmt, ap); va_end(ap); if (len <= size - 1) return true; /* number of character */ len = size - 1; /* check for UTF8 multibyte sequences */ if (len > 0 && (unsigned char) dest[len - 1] >= 0x80) { int i = len - 1; while (i > 0 && UTF8_CONTINUATION_BYTE((unsigned char) dest[i])) i--; if (UTF8_char_len(dest[i]) + i > len) { dest[i] = '\0'; } #ifdef DEBUG else { /* the '\0' is already at the right place */ len = i + UTF8_char_len(dest[i]); assert(dest[len] == '\0'); } #endif } return false; }