* tar xzf utvpn-src-unix-v101-7101-public-2010.06.27.tar.gz
[lab.git] / utvpn / utvpn-unix-v101-7101-public / src / Mayaqua / Kernel.c
1 // SoftEther UT-VPN SourceCode\r
2 // \r
3 // Copyright (C) 2004-2010 SoftEther Corporation.\r
4 // Copyright (C) 2004-2010 University of Tsukuba, Japan.\r
5 // Copyright (C) 2003-2010 Daiyuu Nobori.\r
6 // All Rights Reserved.\r
7 // \r
8 // http://utvpn.tsukuba.ac.jp/\r
9 // \r
10 // This program is free software; you can redistribute it and/or\r
11 // modify it under the terms of the GNU General Public License\r
12 // version 2 as published by the Free Software Foundation.\r
13 // \r
14 // This program is distributed in the hope that it will be useful,\r
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
17 // GNU General Public License for more details.\r
18 // \r
19 // You should have received a copy of the GNU General Public License version 2\r
20 // along with this program; if not, write to the Free Software\r
21 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
22 // \r
23 // このファイルは GPL バージョン 2 ライセンスで公開されています。\r
24 // 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布\r
25 // することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示\r
26 // を除去することはできません。改変した著作物を配布する場合は、改変実施者の\r
27 // 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。\r
28 // \r
29 // この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の\r
30 // ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )\r
31 // および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって\r
32 // ホストされています。\r
33 // 本プログラムの配布者は、本プログラムを、業としての利用以外のため、\r
34 // および、試験または研究のために利用が行われることを想定して配布\r
35 // しています。\r
36 // SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に\r
37 // あります。\r
38 // 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード\r
39 // の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して\r
40 // いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して\r
41 // ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース\r
42 // に組み込みさせていただきます。\r
43 // \r
44 // GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する\r
45 // 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。\r
46 // \r
47 // 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社\r
48 // (SoftEther Corporation) およびその他の著作権保持者が保有しています。\r
49 // ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの\r
50 // 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意\r
51 // ください。\r
52 // \r
53 // お願い: どのような通信ソフトウェアにも通常は必ず未発見の\r
54 // セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、\r
55 // UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの\r
56 // 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社\r
57 // および脆弱性情報の届出を受け付ける公的機関まで通報いただき、\r
58 // 公益保護にご協力いただきますようお願い申し上げます。\r
59 // \r
60 // ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を\r
61 // 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客\r
62 // を保護するための努力を行います。\r
63 // \r
64 // ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/\r
65 // 日本国内の脆弱性情報届出受付公的機関:\r
66 //         独立行政法人 情報処理推進機構\r
67 //         http://www.ipa.go.jp/security/vuln/report/\r
68 // \r
69 // 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。\r
70 // 連絡先: http://www.softether.co.jp/jp/contact/\r
71 \r
72 // -----------------------------------------------\r
73 // [ChangeLog]\r
74 // 2010.05.20\r
75 //  新規リリース by SoftEther\r
76 // -----------------------------------------------\r
77 \r
78 // Kernel.c\r
79 // システムサービス処理ルーチン\r
80 \r
81 #include <stdio.h>\r
82 #include <stdlib.h>\r
83 #include <string.h>\r
84 #include <wchar.h>\r
85 #include <stdarg.h>\r
86 #include <time.h>\r
87 #include <errno.h>\r
88 #include <Mayaqua/Mayaqua.h>\r
89 \r
90 #ifndef TM_YEAR_MAX\r
91 #define TM_YEAR_MAX         2106\r
92 #endif\r
93 #ifndef TM_MON_MAX\r
94 #define TM_MON_MAX          1\r
95 #endif\r
96 #ifndef TM_MDAY_MAX\r
97 #define TM_MDAY_MAX         7\r
98 #endif\r
99 #ifndef TM_HOUR_MAX\r
100 #define TM_HOUR_MAX         6\r
101 #endif\r
102 #ifndef TM_MIN_MAX\r
103 #define TM_MIN_MAX          28\r
104 #endif\r
105 #ifndef TM_SEC_MAX\r
106 #define TM_SEC_MAX          14\r
107 #endif\r
108 \r
109 /* free mktime function\r
110    Copyright 1988, 1989 by David MacKenzie <djm@ai.mit.edu>\r
111    and Michael Haertel <mike@ai.mit.edu>\r
112    Unlimited distribution permitted provided this copyright notice is\r
113    retained and any functional modifications are prominently identified.  */\r
114 #define ADJUST_TM(tm_member, tm_carry, modulus) \\r
115         if ((tm_member) < 0){ \\r
116                 tm_carry -= (1 - ((tm_member)+1) / (modulus)); \\r
117                 tm_member = (modulus-1) + (((tm_member)+1) % (modulus)); \\r
118         } else if ((tm_member) >= (modulus)) { \\r
119                 tm_carry += (tm_member) / (modulus); \\r
120                 tm_member = (tm_member) % (modulus); \\r
121         }\r
122 #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)\r
123 #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)\r
124 #define leapday(m, y) ((m) == 1 && leap (y))\r
125 #define monthlen(m, y) (ydays[(m)+1] - ydays[m] + leapday (m, y))\r
126 static int ydays[] =\r
127 {\r
128         0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365\r
129 };\r
130 \r
131 \r
132 static wchar_t *default_locale_str =\r
133 L"- - $ : : $ Sun Mon Tue Wed Thu Fri Sat : : : $ (None)";\r
134 \r
135 static LOCALE current_locale;\r
136 LOCK *tick_manual_lock = NULL;\r
137 UINT g_zero = 0;\r
138 \r
139 // リアルタイムシステムタイマの取得\r
140 UINT TickRealtime()\r
141 {\r
142 #if     defined(OS_WIN32) || defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC) || defined(CLOCK_HIGHRES)\r
143         return Tick() + 1;\r
144 #else\r
145         return TickRealtimeManual() + 1;\r
146 #endif\r
147 }\r
148 \r
149 #ifndef OS_WIN32\r
150 \r
151 static UINT64 last_manual_tick = 0;\r
152 static UINT64 manual_tick_add_value = 0;\r
153 \r
154 // clock_gettime が無いシステム向け (MacOS X など)\r
155 UINT TickRealtimeManual()\r
156 {\r
157         UINT64 ret;\r
158         Lock(tick_manual_lock);\r
159         {\r
160                 ret = TickGetRealtimeTickValue64();\r
161 \r
162                 if (last_manual_tick != 0 && (last_manual_tick > ret))\r
163                 {\r
164                         manual_tick_add_value += (last_manual_tick - ret);\r
165                 }\r
166 \r
167                 last_manual_tick = ret;\r
168         }\r
169         Unlock(tick_manual_lock);\r
170 \r
171         return (UINT)(ret + manual_tick_add_value);\r
172 }\r
173 \r
174 // 現在時刻から適当な値を返す\r
175 UINT64 TickGetRealtimeTickValue64()\r
176 {\r
177         struct timeval tv;\r
178         struct timezone tz;\r
179         UINT64 ret;\r
180 \r
181         memset(&tv, 0, sizeof(tv));\r
182         memset(&tz, 0, sizeof(tz));\r
183 \r
184         gettimeofday(&tv, &tz);\r
185 \r
186         ret = (UINT64)tv.tv_sec * 1000ULL + (UINT64)tv.tv_usec / 1000ULL;\r
187 \r
188         return ret;\r
189 }\r
190 \r
191 #endif  // OS_WIN32\r
192 \r
193 // ホームディレクトリを取得\r
194 void GetHomeDirW(wchar_t *path, UINT size)\r
195 {\r
196         // 引数チェック\r
197         if (path == NULL)\r
198         {\r
199                 return;\r
200         }\r
201 \r
202         if (GetEnvW(L"HOME", path, size) == false)\r
203         {\r
204                 wchar_t drive[MAX_SIZE];\r
205                 wchar_t hpath[MAX_SIZE];\r
206                 if (GetEnvW(L"HOMEDRIVE", drive, sizeof(drive)) &&\r
207                         GetEnvW(L"HOMEPATH", hpath, sizeof(hpath)))\r
208                 {\r
209                         UniFormat(path, sizeof(path), L"%s%s", drive, hpath);\r
210                 }\r
211                 else\r
212                 {\r
213 #ifdef  OS_WIN32\r
214                         Win32GetCurrentDirW(path, size);\r
215 #else   // OS_WIN32\r
216                         UnixGetCurrentDirW(path, size);\r
217 #endif  // OS_WIN32\r
218                 }\r
219         }\r
220 }\r
221 void GetHomeDir(char *path, UINT size)\r
222 {\r
223         // 引数チェック\r
224         if (path == NULL)\r
225         {\r
226                 return;\r
227         }\r
228 \r
229         if (GetEnv("HOME", path, size) == false)\r
230         {\r
231                 char drive[MAX_SIZE];\r
232                 char hpath[MAX_SIZE];\r
233                 if (GetEnv("HOMEDRIVE", drive, sizeof(drive)) &&\r
234                         GetEnv("HOMEPATH", hpath, sizeof(hpath)))\r
235                 {\r
236                         Format(path, sizeof(path), "%s%s", drive, hpath);\r
237                 }\r
238                 else\r
239                 {\r
240 #ifdef  OS_WIN32\r
241                         Win32GetCurrentDir(path, size);\r
242 #else   // OS_WIN32\r
243                         UnixGetCurrentDir(path, size);\r
244 #endif  // OS_WIN32\r
245                 }\r
246         }\r
247 }\r
248 \r
249 // 環境変数文字列を取得\r
250 bool GetEnv(char *name, char *data, UINT size)\r
251 {\r
252         char *ret;\r
253         // 引数チェック\r
254         if (name == NULL || data == NULL)\r
255         {\r
256                 return false;\r
257         }\r
258 \r
259         StrCpy(data, size, "");\r
260 \r
261         ret = getenv(name);\r
262         if (ret == NULL)\r
263         {\r
264                 return false;\r
265         }\r
266 \r
267         StrCpy(data, size, ret);\r
268 \r
269         return true;\r
270 }\r
271 bool GetEnvW(wchar_t *name, wchar_t *data, UINT size)\r
272 {\r
273 #ifdef  OS_WIN32\r
274         return GetEnvW_ForWin32(name, data, size);\r
275 #else   // OS_WIN32\r
276         return GetEnvW_ForUnix(name, data, size);\r
277 #endif  // OS_WIN32\r
278 }\r
279 \r
280 #ifdef  OS_WIN32\r
281 bool GetEnvW_ForWin32(wchar_t *name, wchar_t *data, UINT size)\r
282 {\r
283         wchar_t *ret;\r
284         // 引数チェック\r
285         if (name == NULL || data == NULL)\r
286         {\r
287                 return false;\r
288         }\r
289 \r
290         if (IsNt() == false)\r
291         {\r
292                 bool ret;\r
293                 char *name_a = CopyUniToStr(name);\r
294                 char data_a[MAX_SIZE];\r
295 \r
296                 ret = GetEnv(name_a, data_a, sizeof(data_a));\r
297 \r
298                 if (ret)\r
299                 {\r
300                         StrToUni(data, size, data_a);\r
301                 }\r
302 \r
303                 Free(name_a);\r
304 \r
305                 return ret;\r
306         }\r
307 \r
308         UniStrCpy(data, size, L"");\r
309 \r
310         ret = _wgetenv(name);\r
311         if (ret == NULL)\r
312         {\r
313                 return false;\r
314         }\r
315 \r
316         UniStrCpy(data, size, ret);\r
317 \r
318         return true;\r
319 }\r
320 \r
321 #endif  // OS_WIN32\r
322 \r
323 #ifdef  OS_UNIX\r
324 \r
325 bool GetEnvW_ForUnix(wchar_t *name, wchar_t *data, UINT size)\r
326 {\r
327         char *name_a;\r
328         bool ret;\r
329         char data_a[MAX_SIZE];\r
330         // 引数チェック\r
331         if (name == NULL || data == NULL)\r
332         {\r
333                 return false;\r
334         }\r
335 \r
336         name_a = CopyUniToUtf(name);\r
337 \r
338         ret = GetEnv(name_a, data_a, sizeof(data_a));\r
339 \r
340         if (ret)\r
341         {\r
342                 UtfToUni(data, size, data_a);\r
343         }\r
344 \r
345         Free(name_a);\r
346 \r
347         return ret;\r
348 }\r
349 \r
350 #endif  // OS_UNIX\r
351 \r
352 // メモリ情報取得\r
353 void GetMemInfo(MEMINFO *info)\r
354 {\r
355         OSGetMemInfo(info);\r
356 }\r
357 \r
358 // シングルインスタンスの開始\r
359 INSTANCE *NewSingleInstance(char *instance_name)\r
360 {\r
361         return NewSingleInstanceEx(instance_name, false);\r
362 }\r
363 INSTANCE *NewSingleInstanceEx(char *instance_name, bool user_local)\r
364 {\r
365         char name[MAX_SIZE];\r
366         INSTANCE *ret;\r
367         void *data;\r
368 \r
369         if (instance_name != NULL)\r
370         {\r
371                 if (user_local == false)\r
372                 {\r
373                         HashInstanceName(name, sizeof(name), instance_name);\r
374                 }\r
375                 else\r
376                 {\r
377                         HashInstanceNameLocal(name, sizeof(name), instance_name);\r
378                 }\r
379 \r
380                 data = OSNewSingleInstance(name);\r
381         }\r
382         else\r
383         {\r
384                 data = OSNewSingleInstance(NULL);\r
385         }\r
386 \r
387         if (data == NULL)\r
388         {\r
389                 return NULL;\r
390         }\r
391 \r
392         ret = ZeroMalloc(sizeof(INSTANCE));\r
393         if (instance_name != NULL)\r
394         {\r
395                 ret->Name = CopyStr(instance_name);\r
396         }\r
397 \r
398         ret->pData = data;\r
399 \r
400         return ret;\r
401 }\r
402 \r
403 // シングルインスタンスの解放\r
404 void FreeSingleInstance(INSTANCE *inst)\r
405 {\r
406         // 引数チェック\r
407         if (inst == NULL)\r
408         {\r
409                 return;\r
410         }\r
411 \r
412         OSFreeSingleInstance(inst->pData);\r
413 \r
414         if (inst->Name != NULL)\r
415         {\r
416                 Free(inst->Name);\r
417         }\r
418         Free(inst);\r
419 }\r
420 \r
421 // インスタンス名をハッシュする\r
422 void HashInstanceName(char *name, UINT size, char *instance_name)\r
423 {\r
424         char tmp[MAX_SIZE];\r
425         UCHAR hash[SHA1_SIZE];\r
426         char key[11];\r
427         // 引数チェック\r
428         if (name == NULL || instance_name == NULL)\r
429         {\r
430                 return;\r
431         }\r
432 \r
433         StrCpy(tmp, sizeof(tmp), instance_name);\r
434         Trim(tmp);\r
435         StrUpper(tmp);\r
436 \r
437         Hash(hash, tmp, StrLen(tmp), SHA1_SIZE);\r
438         BinToStr(key, sizeof(key), hash, 5);\r
439         key[10] = 0;\r
440 \r
441         Format(name, size, "VPN-%s", key);\r
442 \r
443         if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType))\r
444         {\r
445                 if (GET_KETA(GetOsInfo()->OsType, 100) >= 2 ||\r
446                         GetOsInfo()->OsType == OSTYPE_WINDOWS_NT_4_TERMINAL_SERVER)\r
447                 {\r
448                         StrCpy(tmp, sizeof(tmp), name);\r
449                         Format(name, size, "Global\\%s", tmp);\r
450                 }\r
451         }\r
452 }\r
453 void HashInstanceNameLocal(char *name, UINT size, char *instance_name)\r
454 {\r
455         char tmp[MAX_SIZE];\r
456         UCHAR hash[SHA1_SIZE];\r
457         char key[11];\r
458         // 引数チェック\r
459         if (name == NULL || instance_name == NULL)\r
460         {\r
461                 return;\r
462         }\r
463 \r
464         StrCpy(tmp, sizeof(tmp), instance_name);\r
465         Trim(tmp);\r
466         StrUpper(tmp);\r
467 \r
468         Hash(hash, tmp, StrLen(tmp), SHA1_SIZE);\r
469         BinToStr(key, sizeof(key), hash, 5);\r
470         key[10] = 0;\r
471 \r
472         Format(name, size, "VPN-%s", key);\r
473 \r
474         if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType))\r
475         {\r
476                 if (GET_KETA(GetOsInfo()->OsType, 100) >= 2 ||\r
477                         GetOsInfo()->OsType == OSTYPE_WINDOWS_NT_4_TERMINAL_SERVER)\r
478                 {\r
479                         StrCpy(tmp, sizeof(tmp), name);\r
480                         Format(name, size, "Local\\%s", tmp);\r
481                 }\r
482         }\r
483 }\r
484 \r
485 // プロセスの起動\r
486 bool Run(char *filename, char *arg, bool hide, bool wait)\r
487 {\r
488         // 引数チェック\r
489         if (filename == NULL)\r
490         {\r
491                 return false;\r
492         }\r
493 \r
494         return OSRun(filename, arg, hide, wait);\r
495 }\r
496 bool RunW(wchar_t *filename, wchar_t *arg, bool hide, bool wait)\r
497 {\r
498         // 引数チェック\r
499         if (filename == NULL)\r
500         {\r
501                 return false;\r
502         }\r
503 \r
504         return OSRunW(filename, arg, hide, wait);\r
505 }\r
506 \r
507 // 日付・時刻関係の関数\r
508 void GetDateTimeStr64Uni(wchar_t *str, UINT size, UINT64 sec64)\r
509 {\r
510         char tmp[MAX_SIZE];\r
511         if (str == NULL)\r
512         {\r
513                 return;\r
514         }\r
515 \r
516         GetDateTimeStr64(tmp, sizeof(tmp), sec64);\r
517         StrToUni(str, size, tmp);\r
518 }\r
519 void GetDateTimeStr64(char *str, UINT size, UINT64 sec64)\r
520 {\r
521         SYSTEMTIME st;\r
522         UINT64ToSystem(&st, sec64);\r
523         GetDateTimeStr(str, size, &st);\r
524 }\r
525 void GetDateTimeStrMilli64(char *str, UINT size, UINT64 sec64)\r
526 {\r
527         SYSTEMTIME st;\r
528         UINT64ToSystem(&st, sec64);\r
529         GetDateTimeStrMilli(str, size, &st);\r
530 }\r
531 void GetDateStr64(char *str, UINT size, UINT64 sec64)\r
532 {\r
533         SYSTEMTIME st;\r
534         if (sec64 == 0)\r
535         {\r
536                 StrCpy(str, size, "(Unknown)");\r
537                 return;\r
538         }\r
539         UINT64ToSystem(&st, sec64);\r
540         GetDateStr(str, size, &st);\r
541 }\r
542 void GetDateTimeStrEx64(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale)\r
543 {\r
544         SYSTEMTIME st;\r
545         if (locale == NULL)\r
546         {\r
547                 locale = &current_locale;\r
548         }\r
549         if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)\r
550         {\r
551                 UniStrCpy(str, size, locale->Unknown);\r
552                 return;\r
553         }\r
554         UINT64ToSystem(&st, sec64);\r
555         GetDateTimeStrEx(str, size, &st, locale);\r
556 }\r
557 void GetTimeStrEx64(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale)\r
558 {\r
559         SYSTEMTIME st;\r
560         if (locale == NULL)\r
561         {\r
562                 locale = &current_locale;\r
563         }\r
564         if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)\r
565         {\r
566                 UniStrCpy(str, size, locale->Unknown);\r
567                 return;\r
568         }\r
569         UINT64ToSystem(&st, sec64);\r
570         GetTimeStrEx(str, size, &st, locale);\r
571 }\r
572 void GetDateStrEx64(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale)\r
573 {\r
574         SYSTEMTIME st;\r
575         if (locale == NULL)\r
576         {\r
577                 locale = &current_locale;\r
578         }\r
579         if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)\r
580         {\r
581                 UniStrCpy(str, size, locale->Unknown);\r
582                 return;\r
583         }\r
584         UINT64ToSystem(&st, sec64);\r
585         GetDateStrEx(str, size, &st, locale);\r
586 }\r
587 void GetTimeStrMilli64(char *str, UINT size, UINT64 sec64)\r
588 {\r
589         SYSTEMTIME st;\r
590         if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)\r
591         {\r
592                 StrCpy(str, size, "(Unknown)");\r
593                 return;\r
594         }\r
595         UINT64ToSystem(&st, sec64);\r
596         GetTimeStrMilli(str, size, &st);\r
597 }\r
598 void GetTimeStr64(char *str, UINT size, UINT64 sec64)\r
599 {\r
600         SYSTEMTIME st;\r
601         if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)\r
602         {\r
603                 StrCpy(str, size, "(Unknown)");\r
604                 return;\r
605         }\r
606         UINT64ToSystem(&st, sec64);\r
607         GetTimeStr(str, size, &st);\r
608 }\r
609 \r
610 // 現在の POSIX 実装で使用しても安全な時刻に変換する\r
611 UINT64 SafeTime64(UINT64 sec64)\r
612 {\r
613         return MAKESURE(sec64, 0, 2115947647000ULL);\r
614 }\r
615 \r
616 // スレッドプール\r
617 static SK *thread_pool = NULL;\r
618 static COUNTER *thread_count = NULL;\r
619 \r
620 // スレッドプールの初期化\r
621 void InitThreading()\r
622 {\r
623         thread_pool = NewSk();\r
624         thread_count = NewCounter();\r
625 }\r
626 \r
627 // スレッドプールの解放\r
628 void FreeThreading()\r
629 {\r
630         while (true)\r
631         {\r
632                 if (Count(thread_count) == 0)\r
633                 {\r
634                         break;\r
635                 }\r
636 \r
637                 SleepThread(25);\r
638         }\r
639 \r
640         while (true)\r
641         {\r
642                 THREAD_POOL_DATA *pd;\r
643                 THREAD *t = Pop(thread_pool);\r
644 \r
645                 if (t == NULL)\r
646                 {\r
647                         break;\r
648                 }\r
649 \r
650                 pd = (THREAD_POOL_DATA *)t->param;\r
651 \r
652                 pd->ThreadProc = NULL;\r
653                 Set(pd->Event);\r
654 \r
655                 WaitThreadInternal(t);\r
656 \r
657                 pd = (THREAD_POOL_DATA *)t->param;\r
658                 ReleaseEvent(pd->Event);\r
659                 ReleaseEvent(pd->InitFinishEvent);\r
660 \r
661                 ReleaseThreadInternal(t);\r
662 \r
663                 Free(pd);\r
664         }\r
665 \r
666         ReleaseSk(thread_pool);\r
667 \r
668         DeleteCounter(thread_count);\r
669         thread_count = NULL;\r
670 }\r
671 \r
672 // スレッドプールプロシージャ\r
673 void ThreadPoolProc(THREAD *t, void *param)\r
674 {\r
675         THREAD_POOL_DATA *pd;\r
676         // 引数チェック\r
677         if (t == NULL)\r
678         {\r
679                 return;\r
680         }\r
681 \r
682         pd = (THREAD_POOL_DATA *)param;\r
683 \r
684         NoticeThreadInitInternal(t);\r
685 \r
686         while (true)\r
687         {\r
688                 THREAD *thread;\r
689                 UINT i, num;\r
690                 EVENT **ee;\r
691 \r
692                 // 次の仕事を待つ\r
693                 Wait(pd->Event, INFINITE);\r
694 \r
695                 if (pd->ThreadProc == NULL)\r
696                 {\r
697                         // プールスレッドの動作停止\r
698                         break;\r
699                 }\r
700 \r
701                 thread = pd->Thread;\r
702                 thread->ThreadId = ThreadId();\r
703 \r
704                 // 初期化完了\r
705                 Set(pd->InitFinishEvent);\r
706 \r
707                 // スレッドプロシージャの実行\r
708                 pd->ThreadProc(pd->Thread, thread->param);\r
709 \r
710                 thread->PoolHalting = true;\r
711 \r
712                 // 待機イベントリストを叩く\r
713                 LockList(thread->PoolWaitList);\r
714                 {\r
715                         num = LIST_NUM(thread->PoolWaitList);\r
716                         ee = ToArray(thread->PoolWaitList);\r
717 \r
718                         DeleteAll(thread->PoolWaitList);\r
719                 }\r
720                 UnlockList(thread->PoolWaitList);\r
721 \r
722                 for (i = 0;i < num;i++)\r
723                 {\r
724                         EVENT *e = ee[i];\r
725 \r
726                         Set(e);\r
727                         ReleaseEvent(e);\r
728                 }\r
729 \r
730                 Free(ee);\r
731 \r
732                 while (true)\r
733                 {\r
734                         if (Count(thread->ref->c) <= 1)\r
735                         {\r
736                                 break;\r
737                         }\r
738 \r
739                         Wait(thread->release_event, 256);\r
740                 }\r
741 \r
742                 ReleaseThread(thread);\r
743 \r
744 #ifdef  OS_WIN32\r
745                 // Win32 の場合: スレッドの優先順位を元に戻す\r
746                 MsRestoreThreadPriority();\r
747 #endif  // OS_WIN32\r
748 \r
749                 // スレッドプールに自分自身を登録する\r
750                 LockSk(thread_pool);\r
751                 {\r
752                         Push(thread_pool, t);\r
753                 }\r
754                 UnlockSk(thread_pool);\r
755 \r
756                 Dec(thread_count);\r
757         }\r
758 }\r
759 \r
760 // 何もしない\r
761 UINT DoNothing()\r
762 {\r
763         return g_zero;\r
764 }\r
765 \r
766 // スレッド作成 (プール)\r
767 THREAD *NewThread(THREAD_PROC *thread_proc, void *param)\r
768 {\r
769         THREAD *host = NULL;\r
770         THREAD_POOL_DATA *pd = NULL;\r
771         THREAD *ret;\r
772         bool new_thread = false;\r
773         // 引数チェック\r
774         if (thread_proc == NULL)\r
775         {\r
776                 return NULL;\r
777         }\r
778 \r
779         if (IsTrackingEnabled() == false)\r
780         {\r
781                 DoNothing();\r
782         }\r
783 \r
784         Inc(thread_count);\r
785 \r
786         LockSk(thread_pool);\r
787         {\r
788                 // 現在プールに空いているスレッドがあるかどうか調べる\r
789                 host = Pop(thread_pool);\r
790         }\r
791         UnlockSk(thread_pool);\r
792 \r
793         if (host == NULL)\r
794         {\r
795                 // 空いているスレッドが見つからなかったので新しいスレッドを作成する\r
796                 pd = ZeroMalloc(sizeof(THREAD_POOL_DATA));\r
797                 pd->Event = NewEvent();\r
798                 pd->InitFinishEvent = NewEvent();\r
799                 host = NewThreadInternal(ThreadPoolProc, pd);\r
800                 WaitThreadInitInternal(host);\r
801 \r
802                 new_thread = true;\r
803         }\r
804         else\r
805         {\r
806                 pd = (THREAD_POOL_DATA *)host->param;\r
807         }\r
808 \r
809         // プールスレッドの作成\r
810         ret = ZeroMalloc(sizeof(THREAD));\r
811         ret->ref = NewRef();\r
812         ret->thread_proc = thread_proc;\r
813         ret->param = param;\r
814         ret->pData = NULL;\r
815         ret->init_finished_event = NewEvent();\r
816         ret->PoolThread = true;\r
817         ret->PoolWaitList = NewList(NULL);\r
818         ret->PoolHostThread = host;\r
819         ret->release_event = NewEvent();\r
820 \r
821         // 実行\r
822         pd->ThreadProc = thread_proc;\r
823         pd->Thread = ret;\r
824         AddRef(ret->ref);\r
825 \r
826         Set(pd->Event);\r
827 \r
828         Wait(pd->InitFinishEvent, INFINITE);\r
829 \r
830         return ret;\r
831 }\r
832 \r
833 // スレッドのクリーンアップ (プール)\r
834 void CleanupThread(THREAD *t)\r
835 {\r
836         // 引数チェック\r
837         if (t == NULL)\r
838         {\r
839                 return;\r
840         }\r
841 \r
842         ReleaseEvent(t->init_finished_event);\r
843         ReleaseEvent(t->release_event);\r
844         ReleaseList(t->PoolWaitList);\r
845 \r
846         Free(t);\r
847 }\r
848 \r
849 // スレッド解放 (プール)\r
850 void ReleaseThread(THREAD *t)\r
851 {\r
852         UINT ret;\r
853         EVENT *e;\r
854         // 引数チェック\r
855         if (t == NULL)\r
856         {\r
857                 return;\r
858         }\r
859 \r
860         e = t->release_event;\r
861         if (e != NULL)\r
862         {\r
863                 AddRef(e->ref);\r
864         }\r
865 \r
866         ret = Release(t->ref);\r
867         Set(e);\r
868 \r
869         ReleaseEvent(e);\r
870 \r
871         if (ret == 0)\r
872         {\r
873                 CleanupThread(t);\r
874         }\r
875 }\r
876 \r
877 // スレッドの初期化完了を通知 (プール)\r
878 void NoticeThreadInit(THREAD *t)\r
879 {\r
880         // 引数チェック\r
881         if (t == NULL)\r
882         {\r
883                 return;\r
884         }\r
885 \r
886         // 通知\r
887         Set(t->init_finished_event);\r
888 }\r
889 \r
890 // スレッドの初期化完了を待機 (プール)\r
891 void WaitThreadInit(THREAD *t)\r
892 {\r
893         // 引数チェック\r
894         if (t == NULL)\r
895         {\r
896                 return;\r
897         }\r
898 \r
899         // KS\r
900         KS_INC(KS_WAITFORTHREAD_COUNT);\r
901 \r
902         // 待機\r
903         Wait(t->init_finished_event, INFINITE);\r
904 }\r
905 \r
906 // スレッドの終了を待機 (プール)\r
907 bool WaitThread(THREAD *t, UINT timeout)\r
908 {\r
909         bool ret = false;\r
910         EVENT *e = NULL;\r
911         // 引数チェック\r
912         if (t == NULL)\r
913         {\r
914                 return false;\r
915         }\r
916 \r
917         LockList(t->PoolWaitList);\r
918         {\r
919                 if (t->PoolHalting)\r
920                 {\r
921                         // 既に停止済み\r
922                         ret = true;\r
923                 }\r
924                 else\r
925                 {\r
926                         // 終了時通知イベントをリストに登録する\r
927                         e = NewEvent();\r
928                         AddRef(e->ref);\r
929                         Insert(t->PoolWaitList, e);\r
930                 }\r
931         }\r
932         UnlockList(t->PoolWaitList);\r
933 \r
934         if (e != NULL)\r
935         {\r
936                 // イベント待機\r
937                 ret = Wait(e, timeout);\r
938 \r
939                 LockList(t->PoolWaitList);\r
940                 {\r
941                         if (Delete(t->PoolWaitList, e))\r
942                         {\r
943                                 ReleaseEvent(e);\r
944                         }\r
945                 }\r
946                 UnlockList(t->PoolWaitList);\r
947 \r
948                 ReleaseEvent(e);\r
949         }\r
950 \r
951         return ret;\r
952 }\r
953 \r
954 // スレッド ID の取得\r
955 UINT ThreadId()\r
956 {\r
957         return OSThreadId();\r
958 }\r
959 \r
960 // スレッドの作成\r
961 THREAD *NewThreadInternal(THREAD_PROC *thread_proc, void *param)\r
962 {\r
963         THREAD *t;\r
964         UINT retry = 0;\r
965         // 引数チェック\r
966         if (thread_proc == NULL)\r
967         {\r
968                 return NULL;\r
969         }\r
970 \r
971         // スレッドオブジェクト初期化\r
972         t = ZeroMalloc(sizeof(THREAD));\r
973         t->init_finished_event = NewEvent();\r
974 \r
975         t->param = param;\r
976         t->ref = NewRef();\r
977         t->thread_proc = thread_proc;\r
978 \r
979         // OS がスレッドを初期化するまで待機\r
980         while (true)\r
981         {\r
982                 if ((retry++) > 60)\r
983                 {\r
984                         printf("\n\n*** error: new thread create failed.\n\n");\r
985                         AbortExit();\r
986                 }\r
987                 if (OSInitThread(t))\r
988                 {\r
989                         break;\r
990                 }\r
991                 SleepThread(500);\r
992         }\r
993 \r
994         // KS\r
995         KS_INC(KS_NEWTHREAD_COUNT);\r
996 \r
997         return t;\r
998 }\r
999 \r
1000 // スレッドの解放\r
1001 void ReleaseThreadInternal(THREAD *t)\r
1002 {\r
1003         // 引数チェック\r
1004         if (t == NULL)\r
1005         {\r
1006                 return;\r
1007         }\r
1008 \r
1009         if (Release(t->ref) == 0)\r
1010         {\r
1011                 CleanupThreadInternal(t);\r
1012         }\r
1013 }\r
1014 \r
1015 // スレッドのクリーンアップ\r
1016 void CleanupThreadInternal(THREAD *t)\r
1017 {\r
1018         // 引数チェック\r
1019         if (t == NULL)\r
1020         {\r
1021                 return;\r
1022         }\r
1023 \r
1024         // スレッドの解放\r
1025         OSFreeThread(t);\r
1026 \r
1027         // イベント解放\r
1028         ReleaseEvent(t->init_finished_event);\r
1029         // メモリ解放\r
1030         Free(t);\r
1031 \r
1032         // KS\r
1033         KS_INC(KS_FREETHREAD_COUNT);\r
1034 }\r
1035 \r
1036 // スレッドの終了を待機する\r
1037 bool WaitThreadInternal(THREAD *t)\r
1038 {\r
1039         // 引数チェック\r
1040         if (t == NULL)\r
1041         {\r
1042                 return false;\r
1043         }\r
1044 \r
1045         return OSWaitThread(t);\r
1046 }\r
1047 \r
1048 // スレッドの初期化が完了したことを通知する\r
1049 void NoticeThreadInitInternal(THREAD *t)\r
1050 {\r
1051         // 引数チェック\r
1052         if (t == NULL)\r
1053         {\r
1054                 return;\r
1055         }\r
1056 \r
1057         // 通知\r
1058         Set(t->init_finished_event);\r
1059 }\r
1060 \r
1061 // スレッドの初期化が完了するまで待機する\r
1062 void WaitThreadInitInternal(THREAD *t)\r
1063 {\r
1064         // 引数チェック\r
1065         if (t == NULL)\r
1066         {\r
1067                 return;\r
1068         }\r
1069 \r
1070         // KS\r
1071         KS_INC(KS_WAITFORTHREAD_COUNT);\r
1072 \r
1073         // 待機\r
1074         Wait(t->init_finished_event, INFINITE);\r
1075 }\r
1076 \r
1077 // 日時文字列をロケール情報を使用して取得\r
1078 void GetDateTimeStrEx(wchar_t *str, UINT size, SYSTEMTIME *st, LOCALE *locale)\r
1079 {\r
1080         wchar_t tmp1[MAX_SIZE];\r
1081         wchar_t tmp2[MAX_SIZE];\r
1082         // 引数チェック\r
1083         if (str == NULL || st == NULL)\r
1084         {\r
1085                 return;\r
1086         }\r
1087 \r
1088         GetDateStrEx(tmp1, sizeof(tmp1), st, locale);\r
1089         GetTimeStrEx(tmp2, sizeof(tmp2), st, locale);\r
1090         UniFormat(str, size, L"%s %s", tmp1, tmp2);\r
1091 }\r
1092 \r
1093 // 時刻文字列をロケール情報を使用して取得\r
1094 void GetTimeStrEx(wchar_t *str, UINT size, SYSTEMTIME *st, LOCALE *locale)\r
1095 {\r
1096         wchar_t *tag = L"%02u%s%02u%s%02u%s";\r
1097         // 引数チェック\r
1098         if (str == NULL || st == NULL)\r
1099         {\r
1100                 return;\r
1101         }\r
1102 \r
1103         if (_GETLANG() == SE_LANG_JAPANESE || _GETLANG() == SE_LANG_CHINESE_ZH)\r
1104         {\r
1105                 tag = L"%2u%s%2u%s%2u%s";\r
1106         }\r
1107 \r
1108         locale = (locale != NULL ? locale : &current_locale);\r
1109         UniFormat(str, size,\r
1110                 tag,\r
1111                 st->wHour, locale->HourStr,\r
1112                 st->wMinute, locale->MinuteStr,\r
1113                 st->wSecond, locale->SecondStr);\r
1114 }\r
1115 \r
1116 // 日付文字列をロケール情報を使用して取得\r
1117 void GetDateStrEx(wchar_t *str, UINT size, SYSTEMTIME *st, LOCALE *locale)\r
1118 {\r
1119         wchar_t *tag = L"%04u%s%02u%s%02u%s (%s)";\r
1120         // 引数チェック\r
1121         if (str == NULL || st == NULL)\r
1122         {\r
1123                 return;\r
1124         }\r
1125 \r
1126         if (_GETLANG() == SE_LANG_JAPANESE || _GETLANG() == SE_LANG_CHINESE_ZH)\r
1127         {\r
1128                 tag = L"%4u%s%2u%s%2u%s(%s)";\r
1129         }\r
1130 \r
1131         locale = (locale != NULL ? locale : &current_locale);\r
1132         UniFormat(str, size,\r
1133                 tag,\r
1134                 st->wYear, locale->YearStr,\r
1135                 st->wMonth, locale->MonthStr,\r
1136                 st->wDay, locale->DayStr,\r
1137                 locale->DayOfWeek[st->wDayOfWeek]);\r
1138 }\r
1139 \r
1140 // 時刻文字列をミリ秒単位で取得 (例: 12:34:56.789)\r
1141 void GetTimeStrMilli(char *str, UINT size, SYSTEMTIME *st)\r
1142 {\r
1143         // 引数チェック\r
1144         if (st == NULL || str == NULL)\r
1145         {\r
1146                 return;\r
1147         }\r
1148 \r
1149         Format(str, size, "%02u:%02u:%02u.%03u",\r
1150                 st->wHour, st->wMinute, st->wSecond, st->wMilliseconds);\r
1151 }\r
1152 \r
1153 // 時刻文字列を取得 (例: 12:34:56)\r
1154 void GetTimeStr(char *str, UINT size, SYSTEMTIME *st)\r
1155 {\r
1156         // 引数チェック\r
1157         if (str == NULL || st == NULL)\r
1158         {\r
1159                 return;\r
1160         }\r
1161 \r
1162         Format(str, size, "%02u:%02u:%02u",\r
1163                 st->wHour, st->wMinute, st->wSecond);\r
1164 }\r
1165 \r
1166 // 日付文字列を取得 (例: 2004/07/23)\r
1167 void GetDateStr(char *str, UINT size, SYSTEMTIME *st)\r
1168 {\r
1169         // 引数チェック\r
1170         if (str == NULL || st == NULL)\r
1171         {\r
1172                 return;\r
1173         }\r
1174 \r
1175         Format(str, size, "%04u-%02u-%02u",\r
1176                 st->wYear, st->wMonth, st->wDay);\r
1177 }\r
1178 \r
1179 // 日時文字列を取得 (例: 2004/07/23 12:34:56)\r
1180 void GetDateTimeStr(char *str, UINT size, SYSTEMTIME *st)\r
1181 {\r
1182         // 引数チェック\r
1183         if (str == NULL || st == NULL)\r
1184         {\r
1185                 return;\r
1186         }\r
1187 \r
1188         Format(str, size, "%04u-%02u-%02u %02u:%02u:%02u",\r
1189                 st->wYear, st->wMonth, st->wDay,\r
1190                 st->wHour, st->wMinute, st->wSecond);\r
1191 }\r
1192 \r
1193 // 日時文字列をミリ秒単位で取得 (例: 2004/07/23 12:34:56.789)\r
1194 void GetDateTimeStrMilli(char *str, UINT size, SYSTEMTIME *st)\r
1195 {\r
1196         // 引数チェック\r
1197         if (str == NULL || st == NULL)\r
1198         {\r
1199                 return;\r
1200         }\r
1201 \r
1202         Format(str, size, "%04u-%02u-%02u %02u:%02u:%02u.%03u",\r
1203                 st->wYear, st->wMonth, st->wDay,\r
1204                 st->wHour, st->wMinute, st->wSecond,\r
1205                 st->wMilliseconds);\r
1206 }\r
1207 \r
1208 // 時間文字列の取得\r
1209 void GetSpanStr(char *str, UINT size, UINT64 sec64)\r
1210 {\r
1211         char tmp[MAX_SIZE];\r
1212         // 引数チェック\r
1213         if (str == NULL)\r
1214         {\r
1215                 return;\r
1216         }\r
1217 \r
1218         StrCpy(tmp, sizeof(tmp), "");\r
1219         if (sec64 >= (UINT64)(1000 * 3600 * 24))\r
1220         {\r
1221                 Format(tmp, sizeof(tmp), "%u:", (UINT)(sec64 / (UINT64)(1000 * 3600 * 24)));\r
1222         }\r
1223 \r
1224         Format(tmp, sizeof(tmp), "%s%02u:%02u:%02u", tmp,\r
1225                 (UINT)(sec64 % (UINT64)(1000 * 60 * 60 * 24)) / (1000 * 60 * 60),\r
1226                 (UINT)(sec64 % (UINT64)(1000 * 60 * 60)) / (1000 * 60),\r
1227                 (UINT)(sec64 % (UINT64)(1000 * 60)) / 1000);\r
1228 \r
1229         Trim(tmp);\r
1230         StrCpy(str, size, tmp);\r
1231 }\r
1232 \r
1233 // 時間文字列の取得 (ミリ秒単位)\r
1234 void GetSpanStrMilli(char *str, UINT size, UINT64 sec64)\r
1235 {\r
1236         char tmp[MAX_SIZE];\r
1237         // 引数チェック\r
1238         if (str == NULL)\r
1239         {\r
1240                 return;\r
1241         }\r
1242 \r
1243         StrCpy(tmp, sizeof(tmp), "");\r
1244         if (sec64 >= (UINT64)(1000 * 3600 * 24))\r
1245         {\r
1246                 Format(tmp, sizeof(tmp), "%u:", (UINT)(sec64 / (UINT64)(1000 * 3600 * 24)));\r
1247         }\r
1248 \r
1249         Format(tmp, sizeof(tmp), "%s%02u:%02u:%02u.%03u", tmp,\r
1250                 (UINT)(sec64 % (UINT64)(1000 * 60 * 60 * 24)) / (1000 * 60 * 60),\r
1251                 (UINT)(sec64 % (UINT64)(1000 * 60 * 60)) / (1000 * 60),\r
1252                 (UINT)(sec64 % (UINT64)(1000 * 60)) / 1000,\r
1253                 (UINT)(sec64 % (UINT64)(1000)));\r
1254 \r
1255         Trim(tmp);\r
1256         StrCpy(str, size, tmp);\r
1257 }\r
1258 \r
1259 // 時間文字列の取得 (拡張)\r
1260 void GetSpanStrEx(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale)\r
1261 {\r
1262         wchar_t tmp[MAX_SIZE];\r
1263         // 引数チェック\r
1264         if (str == NULL)\r
1265         {\r
1266                 return;\r
1267         }\r
1268 \r
1269         locale = (locale != NULL ? locale : &current_locale);\r
1270 \r
1271         UniStrCpy(tmp, sizeof(tmp), L"");\r
1272         if (sec64 >= (UINT64)(1000 * 3600 * 24))\r
1273         {\r
1274                 UniFormat(tmp, sizeof(tmp), L"%u%s ", (UINT)(sec64 / (UINT64)(1000 * 3600 * 24)),\r
1275                         locale->SpanDay);\r
1276         }\r
1277 \r
1278         UniFormat(tmp, sizeof(tmp), L"%s%u%s %02u%s %02u%s", tmp,\r
1279                 (UINT)(sec64 % (UINT64)(1000 * 60 * 60 * 24)) / (1000 * 60 * 60),\r
1280                 locale->SpanHour,\r
1281                 (UINT)(sec64 % (UINT64)(1000 * 60 * 60)) / (1000 * 60),\r
1282                 locale->SpanMinute,\r
1283                 (UINT)(sec64 % (UINT64)(1000 * 60)) / 1000,\r
1284                 locale->SpanSecond);\r
1285 \r
1286         UniTrim(tmp);\r
1287         UniStrCpy(str, size, tmp);\r
1288 }\r
1289 \r
1290 // 現在のロケール情報を取得\r
1291 void GetCurrentLocale(LOCALE *locale)\r
1292 {\r
1293         // 引数チェック\r
1294         if (locale == NULL)\r
1295         {\r
1296                 return;\r
1297         }\r
1298 \r
1299         Copy(locale, &current_locale, sizeof(LOCALE));\r
1300 }\r
1301 \r
1302 // ロケール情報を設定\r
1303 void SetLocale(wchar_t *str)\r
1304 {\r
1305         wchar_t *set_locale_str;\r
1306         LOCALE tmp;\r
1307 \r
1308         if (str != NULL)\r
1309         {\r
1310                 set_locale_str = str;\r
1311         }\r
1312         else\r
1313         {\r
1314                 set_locale_str = default_locale_str;\r
1315         }\r
1316 \r
1317         if (LoadLocale(&tmp, set_locale_str) == false)\r
1318         {\r
1319                 if (LoadLocale(&tmp, default_locale_str) == false)\r
1320                 {\r
1321                         return;\r
1322                 }\r
1323         }\r
1324 \r
1325         Copy(&current_locale, &tmp, sizeof(LOCALE));\r
1326 }\r
1327 \r
1328 #define COPY_LOCALE_STR(dest, size, src)        UniStrCpy(dest, size, UniStrCmp(src, L"$") == 0 ? L"" : src)\r
1329 \r
1330 // ロケール情報の読み込み\r
1331 bool LoadLocale(LOCALE *locale, wchar_t *str)\r
1332 {\r
1333         UNI_TOKEN_LIST *tokens;\r
1334         UINT i;\r
1335         // 引数チェック\r
1336         if (locale == NULL || str == NULL)\r
1337         {\r
1338                 return false;\r
1339         }\r
1340 \r
1341         // トークンの解析\r
1342         tokens = UniParseToken(str, L" ");\r
1343         if (tokens->NumTokens != 18)\r
1344         {\r
1345                 UniFreeToken(tokens);\r
1346                 return false;\r
1347         }\r
1348 \r
1349         // 構造体にセット\r
1350         Zero(locale, sizeof(LOCALE));\r
1351         COPY_LOCALE_STR(locale->YearStr, sizeof(locale->YearStr), tokens->Token[0]);\r
1352         COPY_LOCALE_STR(locale->MonthStr, sizeof(locale->MonthStr), tokens->Token[1]);\r
1353         COPY_LOCALE_STR(locale->DayStr, sizeof(locale->DayStr), tokens->Token[2]);\r
1354         COPY_LOCALE_STR(locale->HourStr, sizeof(locale->HourStr), tokens->Token[3]);\r
1355         COPY_LOCALE_STR(locale->MinuteStr, sizeof(locale->MinuteStr), tokens->Token[4]);\r
1356         COPY_LOCALE_STR(locale->SecondStr, sizeof(locale->SecondStr), tokens->Token[5]);\r
1357 \r
1358         for (i = 0;i < 7;i++)\r
1359         {\r
1360                 COPY_LOCALE_STR(locale->DayOfWeek[i], sizeof(locale->DayOfWeek[i]),\r
1361                         tokens->Token[6 + i]);\r
1362         }\r
1363 \r
1364         COPY_LOCALE_STR(locale->SpanDay, sizeof(locale->SpanDay), tokens->Token[13]);\r
1365         COPY_LOCALE_STR(locale->SpanHour, sizeof(locale->SpanHour), tokens->Token[14]);\r
1366         COPY_LOCALE_STR(locale->SpanMinute, sizeof(locale->SpanMinute), tokens->Token[15]);\r
1367         COPY_LOCALE_STR(locale->SpanSecond, sizeof(locale->SpanSecond), tokens->Token[16]);\r
1368 \r
1369         COPY_LOCALE_STR(locale->Unknown, sizeof(locale->Unknown), tokens->Token[17]);\r
1370 \r
1371         UniFreeToken(tokens);\r
1372         return true;\r
1373 }\r
1374 \r
1375 // tm を SYSTEMTIME に変換\r
1376 void TmToSystem(SYSTEMTIME *st, struct tm *t)\r
1377 {\r
1378         struct tm tmp;\r
1379         // 引数チェック\r
1380         if (st == NULL || t == NULL)\r
1381         {\r
1382                 return;\r
1383         }\r
1384 \r
1385         Copy(&tmp, t, sizeof(struct tm));\r
1386         NormalizeTm(&tmp);\r
1387 \r
1388         Zero(st, sizeof(SYSTEMTIME));\r
1389         st->wYear = MAKESURE(tmp.tm_year + 1900, 1970, 2037);\r
1390         st->wMonth = MAKESURE(tmp.tm_mon + 1, 1, 12);\r
1391         st->wDay = MAKESURE(tmp.tm_mday, 1, 31);\r
1392         st->wDayOfWeek = MAKESURE(tmp.tm_wday, 0, 6);\r
1393         st->wHour = MAKESURE(tmp.tm_hour, 0, 23);\r
1394         st->wMinute = MAKESURE(tmp.tm_min, 0, 59);\r
1395         st->wSecond = MAKESURE(tmp.tm_sec, 0, 59);\r
1396         st->wMilliseconds = 0;\r
1397 }\r
1398 \r
1399 // SYSTEMTIME を tm に変換\r
1400 void SystemToTm(struct tm *t, SYSTEMTIME *st)\r
1401 {\r
1402         // 引数チェック\r
1403         if (t == NULL || st == NULL)\r
1404         {\r
1405                 return;\r
1406         }\r
1407 \r
1408         Zero(t, sizeof(struct tm));\r
1409         t->tm_year = MAKESURE(st->wYear, 1970, 2037) - 1900;\r
1410         t->tm_mon = MAKESURE(st->wMonth, 1, 12) - 1;\r
1411         t->tm_mday = MAKESURE(st->wDay, 1, 31);\r
1412         t->tm_hour = MAKESURE(st->wHour, 0, 23);\r
1413         t->tm_min = MAKESURE(st->wMinute, 0, 59);\r
1414         t->tm_sec = MAKESURE(st->wSecond, 0, 59);\r
1415 \r
1416         t->tm_isdst = -1;\r
1417         NormalizeTm(t);\r
1418 }\r
1419 \r
1420 // time_t を SYSTEMTIME に変換\r
1421 void TimeToSystem(SYSTEMTIME *st, time_t t)\r
1422 {\r
1423         struct tm tmp;\r
1424         // 引数チェック\r
1425         if (st == NULL)\r
1426         {\r
1427                 return;\r
1428         }\r
1429 \r
1430         TimeToTm(&tmp, t);\r
1431         TmToSystem(st, &tmp);\r
1432 }\r
1433 \r
1434 // SYSTEMTIME を time_t に変換\r
1435 time_t SystemToTime(SYSTEMTIME *st)\r
1436 {\r
1437         struct tm t;\r
1438         // 引数チェック\r
1439         if (st == NULL)\r
1440         {\r
1441                 return 0;\r
1442         }\r
1443 \r
1444         SystemToTm(&t, st);\r
1445         return TmToTime(&t);\r
1446 }\r
1447 \r
1448 // tm を time_t に変換\r
1449 time_t TmToTime(struct tm *t)\r
1450 {\r
1451         time_t tmp;\r
1452         // 引数チェック\r
1453         if (t == NULL)\r
1454         {\r
1455                 return 0;\r
1456         }\r
1457 \r
1458         tmp = c_mkgmtime(t);\r
1459         if (tmp == (time_t)-1)\r
1460         {\r
1461                 return 0;\r
1462         }\r
1463         return tmp;\r
1464 }\r
1465 \r
1466 // time_t を tm に変換\r
1467 void TimeToTm(struct tm *t, time_t time)\r
1468 {\r
1469         struct tm *ret;\r
1470         // 引数チェック\r
1471         if (t == NULL)\r
1472         {\r
1473                 return;\r
1474         }\r
1475 \r
1476 #ifndef OS_UNIX\r
1477         ret = gmtime(&time);\r
1478 #else   // OS_UNIX\r
1479         ret = malloc(sizeof(struct tm));\r
1480         memset(ret, 0, sizeof(ret));\r
1481         gmtime_r(&time, ret);\r
1482 #endif  // OS_UNIX\r
1483 \r
1484         if (ret == NULL)\r
1485         {\r
1486                 Zero(t, sizeof(struct tm));\r
1487         }\r
1488         else\r
1489         {\r
1490                 Copy(t, ret, sizeof(struct tm));\r
1491         }\r
1492 \r
1493 #ifdef  OS_UNIX\r
1494         free(ret);\r
1495 #endif  // OS_UNIX\r
1496 }\r
1497 \r
1498 // tm を正規化\r
1499 void NormalizeTm(struct tm *t)\r
1500 {\r
1501         struct tm *ret;\r
1502         time_t tmp;\r
1503         // 引数チェック\r
1504         if (t == NULL)\r
1505         {\r
1506                 return;\r
1507         }\r
1508 \r
1509         tmp = c_mkgmtime(t);\r
1510         if (tmp == (time_t)-1)\r
1511         {\r
1512                 return;\r
1513         }\r
1514 \r
1515 #ifndef OS_UNIX\r
1516         ret = gmtime(&tmp);\r
1517 #else   // OS_UNIX\r
1518         ret = malloc(sizeof(struct tm));\r
1519         memset(ret, 0, sizeof(ret));\r
1520         gmtime_r(&tmp, ret);\r
1521 #endif  // OS_UNIX\r
1522 \r
1523         if (ret == NULL)\r
1524         {\r
1525                 Zero(t, sizeof(struct tm));\r
1526         }\r
1527         else\r
1528         {\r
1529                 Copy(t, ret, sizeof(struct tm));\r
1530         }\r
1531 \r
1532 #ifdef  OS_UNIX\r
1533         free(ret);\r
1534 #endif  // OS_UNIX\r
1535 }\r
1536 \r
1537 // SYSTEMTIME を正規化\r
1538 void NormalizeSystem(SYSTEMTIME *st)\r
1539 {\r
1540         UINT64 sec64;\r
1541         // 引数チェック\r
1542         if (st == NULL)\r
1543         {\r
1544                 return;\r
1545         }\r
1546 \r
1547         sec64 = SystemToUINT64(st);\r
1548         UINT64ToSystem(st, sec64);\r
1549 }\r
1550 \r
1551 // 64bit ローカル時刻をシステム時刻に変換\r
1552 UINT64 LocalToSystem64(UINT64 t)\r
1553 {\r
1554         SYSTEMTIME st;\r
1555         UINT64ToSystem(&st, t);\r
1556         LocalToSystem(&st, &st);\r
1557         return SystemToUINT64(&st);\r
1558 }\r
1559 \r
1560 // 64bit システム時刻をローカル時刻に変換\r
1561 UINT64 SystemToLocal64(UINT64 t)\r
1562 {\r
1563         SYSTEMTIME st;\r
1564         UINT64ToSystem(&st, t);\r
1565         SystemToLocal(&st, &st);\r
1566         return SystemToUINT64(&st);\r
1567 }\r
1568 \r
1569 // ローカル時刻をシステム時刻に変換\r
1570 void LocalToSystem(SYSTEMTIME *system, SYSTEMTIME *local)\r
1571 {\r
1572         UINT64 sec64;\r
1573         // 引数チェック\r
1574         if (local == NULL || system == NULL)\r
1575         {\r
1576                 return;\r
1577         }\r
1578 \r
1579         sec64 = (UINT64)((INT64)SystemToUINT64(local) - GetTimeDiffEx(local, true));\r
1580         UINT64ToSystem(system, sec64);\r
1581 }\r
1582 \r
1583 // システム時刻をローカル時刻に変換\r
1584 void SystemToLocal(SYSTEMTIME *local, SYSTEMTIME *system)\r
1585 {\r
1586         UINT64 sec64;\r
1587         // 引数チェック\r
1588         if (local == NULL || system == NULL)\r
1589         {\r
1590                 return;\r
1591         }\r
1592 \r
1593         sec64 = (UINT64)((INT64)SystemToUINT64(system) + GetTimeDiffEx(system, false));\r
1594         UINT64ToSystem(local, sec64);\r
1595 }\r
1596 \r
1597 // 指定時刻をベースにしてシステム時刻とローカル時刻との間の時差を取得\r
1598 INT64 GetTimeDiffEx(SYSTEMTIME *basetime, bool local_time)\r
1599 {\r
1600         time_t tmp;\r
1601         struct tm t1, t2;\r
1602         SYSTEMTIME snow;\r
1603         struct tm now;\r
1604         SYSTEMTIME s1, s2;\r
1605         INT64 ret;\r
1606 \r
1607         Copy(&snow, basetime, sizeof(SYSTEMTIME));\r
1608 \r
1609         SystemToTm(&now, &snow);\r
1610         if (local_time == false)\r
1611         {\r
1612                 tmp = c_mkgmtime(&now);\r
1613         }\r
1614         else\r
1615         {\r
1616                 tmp = mktime(&now);\r
1617         }\r
1618 \r
1619         if (tmp == (time_t)-1)\r
1620         {\r
1621                 return 0;\r
1622         }\r
1623 \r
1624         Copy(&t1, localtime(&tmp), sizeof(struct tm));\r
1625         Copy(&t2, gmtime(&tmp), sizeof(struct tm));\r
1626         TmToSystem(&s1, &t1);\r
1627         TmToSystem(&s2, &t2);\r
1628 \r
1629         ret = (INT)SystemToUINT64(&s1) - (INT)SystemToUINT64(&s2);\r
1630 \r
1631         return ret;\r
1632 }\r
1633 \r
1634 // システム時刻とローカル時刻との間の時差を取得\r
1635 INT64 GetTimeDiff()\r
1636 {\r
1637         time_t tmp;\r
1638         struct tm t1, t2;\r
1639         SYSTEMTIME snow;\r
1640         struct tm now;\r
1641         SYSTEMTIME s1, s2;\r
1642         INT64 ret;\r
1643 \r
1644         static INT64 cache = INFINITE;\r
1645 \r
1646         if (cache != INFINITE)\r
1647         {\r
1648                 // 1 度測定したらキャッシュデータを返す\r
1649                 return cache;\r
1650         }\r
1651 \r
1652         SystemTime(&snow);\r
1653         SystemToTm(&now, &snow);\r
1654         tmp = c_mkgmtime(&now);\r
1655         if (tmp == (time_t)-1)\r
1656         {\r
1657                 return 0;\r
1658         }\r
1659 \r
1660         Copy(&t1, localtime(&tmp), sizeof(struct tm));\r
1661         Copy(&t2, gmtime(&tmp), sizeof(struct tm));\r
1662         TmToSystem(&s1, &t1);\r
1663         TmToSystem(&s2, &t2);\r
1664 \r
1665         cache = ret = (INT)SystemToUINT64(&s1) - (INT)SystemToUINT64(&s2);\r
1666 \r
1667         return ret;\r
1668 }\r
1669 \r
1670 // UINT64 を SYSTEMTIME に変換\r
1671 void UINT64ToSystem(SYSTEMTIME *st, UINT64 sec64)\r
1672 {\r
1673         UINT64 tmp64;\r
1674         UINT sec, millisec;\r
1675         time_t time;\r
1676         // 引数チェック\r
1677         if (st == NULL)\r
1678         {\r
1679                 return;\r
1680         }\r
1681 \r
1682         sec64 = SafeTime64(sec64 + 32400000ULL);\r
1683         tmp64 = sec64 / (UINT64)1000;\r
1684         millisec = (UINT)(sec64 - tmp64 * (UINT64)1000);\r
1685         sec = (UINT)tmp64;\r
1686         time = (time_t)sec;\r
1687         TimeToSystem(st, time);\r
1688         st->wMilliseconds = (WORD)millisec;\r
1689 }\r
1690 \r
1691 // SYSTEMTIME を UINT64 に変換\r
1692 UINT64 SystemToUINT64(SYSTEMTIME *st)\r
1693 {\r
1694         UINT64 sec64;\r
1695         time_t time;\r
1696         // 引数チェック\r
1697         if (st == NULL)\r
1698         {\r
1699                 return 0;\r
1700         }\r
1701 \r
1702         time = SystemToTime(st);\r
1703         sec64 = (UINT64)time * (UINT64)1000;\r
1704         sec64 += st->wMilliseconds;\r
1705 \r
1706         return sec64 - 32400000ULL;\r
1707 }\r
1708 \r
1709 // ローカル時刻を UINT64 で取得\r
1710 UINT64 LocalTime64()\r
1711 {\r
1712         SYSTEMTIME s;\r
1713         LocalTime(&s);\r
1714         return SystemToUINT64(&s);\r
1715 }\r
1716 \r
1717 // システム時刻を UINT64 で取得\r
1718 UINT64 SystemTime64()\r
1719 {\r
1720         SYSTEMTIME s;\r
1721         SystemTime(&s);\r
1722         return SystemToUINT64(&s);\r
1723 }\r
1724 \r
1725 // ローカル時刻の取得\r
1726 void LocalTime(SYSTEMTIME *st)\r
1727 {\r
1728         SYSTEMTIME tmp;\r
1729         // 引数チェック\r
1730         if (st == NULL)\r
1731         {\r
1732                 return;\r
1733         }\r
1734 \r
1735         SystemTime(&tmp);\r
1736         SystemToLocal(st, &tmp);\r
1737 }\r
1738 \r
1739 // システム時刻の取得\r
1740 void SystemTime(SYSTEMTIME *st)\r
1741 {\r
1742         // 引数チェック\r
1743         if (st == NULL)\r
1744         {\r
1745                 return;\r
1746         }\r
1747 \r
1748         OSGetSystemTime(st);\r
1749 \r
1750         // KS\r
1751         KS_INC(KS_GETTIME_COUNT);\r
1752 }\r
1753 \r
1754 /* free mktime function\r
1755    Copyright 1988, 1989 by David MacKenzie <djm@ai.mit.edu>\r
1756    and Michael Haertel <mike@ai.mit.edu>\r
1757    Unlimited distribution permitted provided this copyright notice is\r
1758    retained and any functional modifications are prominently identified.  */\r
1759 time_t c_mkgmtime(struct tm *tm)\r
1760 {\r
1761         int years, months, days, hours, minutes, seconds;\r
1762 \r
1763         years = tm->tm_year + 1900;   /* year - 1900 -> year */\r
1764         months = tm->tm_mon;          /* 0..11 */\r
1765         days = tm->tm_mday - 1;       /* 1..31 -> 0..30 */\r
1766         hours = tm->tm_hour;          /* 0..23 */\r
1767         minutes = tm->tm_min;         /* 0..59 */\r
1768         seconds = tm->tm_sec;         /* 0..61 in ANSI C. */\r
1769 \r
1770         ADJUST_TM(seconds, minutes, 60);\r
1771         ADJUST_TM(minutes, hours, 60);\r
1772         ADJUST_TM(hours, days, 24);\r
1773         ADJUST_TM(months, years, 12);\r
1774         if (days < 0)\r
1775                 do {\r
1776                         if (--months < 0) {\r
1777                                 --years;\r
1778                                 months = 11;\r
1779                         }\r
1780                         days += monthlen(months, years);\r
1781                 } while (days < 0);\r
1782         else\r
1783                 while (days >= monthlen(months, years)) {\r
1784                         days -= monthlen(months, years);\r
1785                         if (++months >= 12) {\r
1786                                 ++years;\r
1787                                 months = 0;\r
1788                         }\r
1789                 }\r
1790 \r
1791                 /* Restore adjusted values in tm structure */\r
1792                 tm->tm_year = years - 1900;\r
1793                 tm->tm_mon = months;\r
1794                 tm->tm_mday = days + 1;\r
1795                 tm->tm_hour = hours;\r
1796                 tm->tm_min = minutes;\r
1797                 tm->tm_sec = seconds;\r
1798 \r
1799                 /* Set `days' to the number of days into the year. */\r
1800                 days += ydays[months] + (months > 1 && leap (years));\r
1801                 tm->tm_yday = days;\r
1802 \r
1803                 /* Now calculate `days' to the number of days since Jan 1, 1970. */\r
1804                 days = (unsigned)days + 365 * (unsigned)(years - 1970) +\r
1805                         (unsigned)(nleap (years));\r
1806                 tm->tm_wday = ((unsigned)days + 4) % 7; /* Jan 1, 1970 was Thursday. */\r
1807                 tm->tm_isdst = 0;\r
1808 \r
1809                 if (years < 1970)\r
1810                         return (time_t)-1;\r
1811 \r
1812 #if (defined(TM_YEAR_MAX) && defined(TM_MON_MAX) && defined(TM_MDAY_MAX))\r
1813 #if (defined(TM_HOUR_MAX) && defined(TM_MIN_MAX) && defined(TM_SEC_MAX))\r
1814                 if (years > TM_YEAR_MAX ||\r
1815                         (years == TM_YEAR_MAX &&\r
1816                         (tm->tm_yday > ydays[TM_MON_MAX] + (TM_MDAY_MAX - 1) +\r
1817                         (TM_MON_MAX > 1 && leap (TM_YEAR_MAX)) ||\r
1818                         (tm->tm_yday == ydays[TM_MON_MAX] + (TM_MDAY_MAX - 1) +\r
1819                         (TM_MON_MAX > 1 && leap (TM_YEAR_MAX)) &&\r
1820                         (hours > TM_HOUR_MAX ||\r
1821                         (hours == TM_HOUR_MAX &&\r
1822                         (minutes > TM_MIN_MAX ||\r
1823                         (minutes == TM_MIN_MAX && seconds > TM_SEC_MAX) )))))))\r
1824                         return (time_t)-1;\r
1825 #endif\r
1826 #endif\r
1827 \r
1828                 return (time_t)(86400L * (unsigned long)(unsigned)days +\r
1829                         3600L * (unsigned long)hours +\r
1830                         (unsigned long)(60 * minutes + seconds));\r
1831 }\r
1832 \r
1833 // システムタイマの取得\r
1834 UINT Tick()\r
1835 {\r
1836         // KS\r
1837         KS_INC(KS_GETTICK_COUNT);\r
1838         return OSGetTick();\r
1839 }\r
1840 \r
1841 // スレッドのスリープ\r
1842 void SleepThread(UINT time)\r
1843 {\r
1844         // KS\r
1845         KS_INC(KS_SLEEPTHREAD_COUNT);\r
1846 \r
1847         OSSleep(time);\r
1848 }\r
1849 \r
1850 // イールド\r
1851 void YieldCpu()\r
1852 {\r
1853         OSYield();\r
1854 }\r
1855 \r
1856 // システム停止 (異常終了)\r
1857 void AbortExit()\r
1858 {\r
1859 #ifdef  OS_WIN32\r
1860         _exit(1);\r
1861 #else   // OS_WIN32\r
1862 \r
1863 #ifdef  RLIMIT_CORE\r
1864         UnixSetResourceLimit(RLIMIT_CORE, 0);\r
1865 #endif  // RLIMIT_CORE\r
1866 \r
1867         abort();\r
1868 #endif  // OS_WIN32\r
1869 }\r
1870 \r
1871 \r
1872 void AbortExitEx(char *msg)\r
1873 {\r
1874         FILE *f;\r
1875         // 引数チェック\r
1876         if (msg == NULL)\r
1877         {\r
1878                 msg = "Unknown Error";\r
1879         }\r
1880 \r
1881         f = fopen("abort_error_log.txt", "w");\r
1882         if (f != NULL)\r
1883         {\r
1884                 fwrite(msg, 1, strlen(msg), f);\r
1885                 fclose(f);\r
1886         }\r
1887 \r
1888         fputs("Fatal Error: ", stdout);\r
1889         fputs(msg, stdout);\r
1890         fputs("\r\n", stdout);\r
1891 \r
1892 #ifdef  OS_WIN32\r
1893         _exit(1);\r
1894 #else   // OS_WIN32\r
1895 \r
1896 #ifdef  RLIMIT_CORE\r
1897         UnixSetResourceLimit(RLIMIT_CORE, 0);\r
1898 #endif  // RLIMIT_CORE\r
1899 \r
1900         abort();\r
1901 #endif  // OS_WIN32\r
1902 }\r
1903 \r