まずは本家? OpenBSD の 2004/08/07 のものから。少しスタイルなんかを変えてある。
--- strlcpy.c --- 1: /* 2: * Copy src to string dst of size siz. At most siz-1 characters 3: * will be copied. Always NUL terminates (unless siz == 0). 4: * Returns strlen(src); if retval >= siz, truncation occurred. 5: */ 6: size_t 7: strlcpy(char *dst, const char *src, size_t siz) 8: { 9: char *d = dst; 10: const char *s = src; 11: size_t n = siz; 12: 13: /* Copy as many bytes as will fit */ 14: if (n != 0 && --n != 0) 15: { 16: do 17: { 18: if ((*d++ = *s++) == '\0') 19: break; 20: } 21: while (--n != 0); 22: } 23: 24: /* Not enough room in dst, add NUL and traverse rest of src */ 25: if (n == 0) 26: { 27: if (siz != 0) 28: *d = '\0'; /* NUL-terminate dst */ 29: while (*s++) 30: continue; 31: } 32: 33: return s - src - 1; /* count does not include NUL */ 34: }
なかなか玄人っぽい実装で、素人目には文字列コピーには見えないかも知れない。
前半(L14〜22)はコピー処理で、ここを抜けるのは n == 0 指定文字数-1だけコピーしたが、元の文字列全てをコピーしていない状況が1つ。その場合、後半(L25〜31)で NUL 終端して元の文字列ポインタをカウントアップし、元の文字数を返す。
もう1つのケースは、指定サイズより早く(短く)元の文字列が終わっている場合。その場合、元の文字列ポインタは終端まで進み、コピー先も終端されているので、そのまま元の文字数を返す事になる。
ちょっと気になったのは、サイズに 0 を指定しても元の文字数を返している事。どういう使い方が想定されているか良く判らないが、strlen の代用にはなっているなぁ...
別の実装として、たまたま見かけたのが VLC 0.8.6f の vlc_strlcpy。比較し易いように引数名を strlcpy に合わせて変えたりしている。
--- extras/libc.c --- 363: /** 364: * Copy a string to a sized buffer. The result is always nul-terminated 365: * (contrary to strncpy()). 366: * 367: * @param dest destination buffer 368: * @param src string to be copied 369: * @param len maximum number of characters to be copied plus one for the 370: * terminating nul. 371: * 372: * @return strlen(src) 373: */ 374: #ifndef HAVE_STRLCPY 375: extern size_t vlc_strlcpy (char *dst, const char *src, size_t siz) 376: { 377: size_t len; 378: 379: for (len = 1; (len < siz) && *src; len++) 380: *dst++ = *src++; 381: 382: if (siz) 383: *dst = '\0'; 384: 385: while (*src++) 386: len++; 387: 388: return len - 1; 389: } 390: #endif
strlcpy と等価なんだけども随分すっきりして見える。と思ったら意外に難しい動きをする。元の文字数を返す為に len 変数が用いられ、while が常に実行される。巧妙で拡張するには手を入れにくいかも知れない...
こうやって見ると、戻り値は strcpy や strncpy のように dst ポインタを返すのが易しい実装になると思うし、コピー後に strlen(src) が欲しい状況が今ひとつ良く判らないが、適切なバッファサイズか確かめる為かも知れない。
strncpy との比較で言えば、strncpy はコピー先サイズより文字列が短い場合に、残りを 0 で埋めるが、strlcpy はそうはしない。