2010/03/22(Mon)
○ TR14652 extension for LC_TIME
ISO/IEC TR14652[pdf]のダメなところは、せっかく新しいフィールド追加したのに、それを使うためのAPIが
nl_langinfo(3)に指定する nl_item 定数を含めてまったくどこにも定義されてないことだよな。
たぶん唯一の TR14652 実装である glibc2 では nl_item 定数として
[nl_item定数] [locale(1) -k] _NL_TIME_WEEK_NDAYS week-ndays _NL_TIME_WEEK_1STDAY week-1stday _NL_TIME_WEEK_1STWEEK week-1stweek _NL_TIME_FIRST_WEEKDAY first_weekday _NL_TIME_FIRST_WORKDAY first_workday _NL_TIME_CAL_DIRECTION cal_direction _NL_TIME_TIMEZONE timezone
が定義されてるんだけど、これ将来的にどーなるかわからんので、NetBSD/Citrusの
_locale_t(=_locale_impl_t) に用意したキャッシュ(=items)には含めたくないなぁ、と。
struct _locale_cache_t {
const unsigned char *ctype_tab;
const short *tolower_tab;
const short *toupper_tab;
size_t mb_cur_max;
struct lconv ldata;
const char *items[ALT_DIGITS + 1];
};
struct _locale_impl_t {
struct _locale_cache_t cache;
...
ということで他の normal な nl_item定数と区別するために、MSB立てるとかしときたいのだけど
typedef long nl_item;
と signed の MD な型だったりするので微妙に書きづらい、LONG_MINとか使うのはevilだしなぁ。どしよ。
そもそもglibc2レベルでnl_itemを増やすと、全部のitemに対してcacheを用意するのは無理があるのよな。
wchar_t *ws;
ws = (wchar_t *)(char *)nl_langinfo(_NL_WABDAY_1);
みたいにchar*にキャストしてワイド文字返したりもする、かなりフリーダムな実装なんで非常に頭が痛い。
# ただしこの方がwprintf(3)なんかの実装に性能的に有利ではある、なんというパラノイア。
ま、どっちにしろ今後 struct lconv のフィールドや nl_item の数が増えることを想定して
struct _locale_cache_tの実装は直しといた方がいいよな。
--- setlocale_local.h 2 Dec 2009 08:53:03 -0000 1.3
+++ setlocale_local.h 21 Mar 2010 19:24:05 -0000
@@ -40,12 +40,12 @@
const short *tolower_tab;
const short *toupper_tab;
size_t mb_cur_max;
- struct lconv ldata;
- const char *items[ALT_DIGITS + 1];
+ struct lconv *ldata;
+ const char **items;
};
struct _locale_impl_t {
↑の方が後々よさげ、去年実装したとき手抜き過ぎた。
といっても locale_t はコンストラクタありなので後方互換は問題にならないし
別に今の実装のままで増やしてしまってもいいのだけど。でもしかしこの部分って
__inline struct lconv*
localeconv_l(locale_t l)
{
return ((struct _locale_impl_t)l)->cache.ldata);
}
__inline char *
nl_langinfo_l(nl_item item, locale_t l)
{
const char *s;
s = NULL;
if (item >= D_T_FMT && item <= ALT_DIGITS) {
s = ((struct _locale_impl_t)l)->cache.items[(size_t)item];
}
if (s == NULL)
s = "";
return __UNCONST(s);
}
みたいにinlineとして提供し性能を稼ぐ必要あるかもなーという想定で実装してたかんね(俺もパラノイア)。
そうすっと struct lconv のフィールドや nl_item の数が増えると後方互換が壊れるので
回避にあんまり美しくないコードを書く羽目に。
うし、この変更だけは少なくとも 6.0 にはつっこもう。
○[C1X] *cpy_s in TR24731-1
_tcscpy_sネタ。
ISO/IEC TR24731-1[pdf]では以下の場合、set_constraint_handler_s(3)でセットした例外ハンドラを呼ぶことになってますな。
(手元のNetBSD用に
以前書いた実装をみて書いてるので最新は知らんがな)
- 第1引数のコピー先がNULLの場合
- 第2引数が0あるいはRSIZE_MAXの場合(VC++にはrsize_tがないのでどうしてるかは知りません)
- 第3引数のコピー元がNULLの場合
- 第1引数(コピー先)と第3引数(コピー元)がオーバーラップする場合
TR24731-1では例外ハンドラはデフォではNULLなのでそのまま処理続行のはず。
まぁVC++だとデフォでabort_handler_s(3)がセットされてるのじゃないでしょうか。
まぁそれはおいといて、元の質問見たけど
numberOfElements コピー先の文字列バッファのサイズ。
をバイト数と勘違いする人がいるのだなぁと、あくまでコピー先の文字型の配列長でんがな。
これを誤植とかもうね(以下略
int bytes = ( ( _tcslen(c) + 1 )*sizeof(TCHAR) );
if ( fn = (TCHAR*)malloc( bytes ) ) _tcscpy_s( fn, bytes, c );
じゃなくて
int len = ( ( _tcslen(c) + 1 ) );
if ( fn = (TCHAR*)cmalloc( len, sizeof(TCHAR) ) ) _tcscpy_s( fn, len, c );
だぁね、つか長さ調べてその分アロケートするなら_tcscpy_s使う意味ないし、この関数は
TCHAR buf[BUFSIZ];
_tcscpy_s(buf, BUFSIZ, c);
のように、固定長バッファをあふれさせないように使う関数だかんね。
リンク先の回答にもあるとおり動的割り当ておkなら _tcsdup() 使えと。