FWIW, part of the fun of strjcpy is that it is also much easier to write than strxcpy (and watch as I go further and further out on a limb with sketchy C that is likely wrong, lol... I
did test it, at least! ;P):
char *strjcpy(char *restrict dst, const char *restrict src, size_t len) {
for (;; ++dst, --len)
if (!len || !(*dst = *src++))
return dst;
}
(edit) Oh, I have an even cuter implementation (which might look "too clever" but actually demonstrates something important about the function)! Essentially, what makes strjcpy so "pure" is that the NULL return is really a "special case" in strxcpy that you're having to "undo" in that wrapper, whereas the semantics of strjcpy--which may
sound a bit weird--are mapping directly to what naturally terminates the loop: running out of space on one of the two inputs. This purity then gets taken advantage of by the caller to get such easy call chaining and error propagation, as one of these loops can "continue through" into the next loop without any adaptation logic.
char *strjcpy(char *restrict dst, const char *restrict src, size_t len) {
for (; len && (*dst = *src++); ++dst, --len);
return dst;
}
(edit) Ok: one difference is that this implementation of strjcpy (this isn't intrinsic to the return value surface I described: just to the gloriously simple versions in this comment; your adapted version, for example, is "fine") doesn't put a NUL byte in case of truncation... though, I personally am not at all sold on doing that: I want to firmly fail the operation, rather than try to "use" the truncated data :/. Adding that special case would still result in strjcpy being simpler than strxcpy (and doesn't break its semantics advantages: just make sure to return the address of dst+len, not that extra NUL), but it isn't quite so amazingly simpler at that point ;P.