To answer my own question, there is a C function that I ended up with (not using C ++ for this project):
Notes: - Understand that this is not a strncpy clone for utf8, it is more like strlcpy from openbsd. - utf8_skip_data copied from glib gutf8.c - It does not check utf8 - this is what I intended.
Hope this is helpful to others and interested in feedback, but please, not a single pedantic fanatic about NULL behavior unless it is an actual error, or misleading / incorrect behavior.
Thanks to James Kanze, who served as the basis for this, but was also incomplete with C ++ (I need version C).
static const size_t utf8_skip_data[256] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1 }; char *strlcpy_utf8(char *dst, const char *src, size_t maxncpy) { char *dst_r = dst; size_t utf8_size; if (maxncpy > 0) { while (*src != '\0' && (utf8_size = utf8_skip_data[*((unsigned char *)src)]) < maxncpy) { maxncpy -= utf8_size; switch (utf8_size) { case 6: *dst ++ = *src ++; case 5: *dst ++ = *src ++; case 4: *dst ++ = *src ++; case 3: *dst ++ = *src ++; case 2: *dst ++ = *src ++; case 1: *dst ++ = *src ++; } } *dst= '\0'; } return dst_r; }