EXCEPT2.C
[目次 | 関数 | マクロ]
1|/*************************************************************************
2|* 1. <<< 例外処理シミュレート2 (Except2) >>>
3|**************************************************************************/
4|
5|#define STDLIBS_INCLUDE
6|#define STDLIBS_INCLUDE_STDIO_H
7|#define STDLIBS_INCLUDE_STDLIB_H
8|#define STDLIBS_INCLUDE_STRING_H
9|#define STDLIBS_INCLUDE_STDARG_H
10|#define STDLIBS_INCLUDE_SETJMP_H
11|#include <all.h>
12|
13|#include <errno.h>
14|#ifndef FOR_NOFILE
15| #include <direct.h>
16|#endif
17|
18|Except2_Sys Except2_sys; /* 2. <<< 静的変数 [Except2_sys] singleton pattern >>> */
19|
20|static Except2_Std Except2_std; /* 標準・例外メッセージ */
21|static Except2_Str Except2_str; /* 文字列・例外メッセージ */
22|
23|#ifndef FOR_NOFILE
24|static Except2_File Except2_file; /* ファイル・例外メッセージ */
25|#endif
26|
27|
28|
29|/*-----------------------------------------------------------------------*/
30|/* 3. <<< ◆例外メッセージ・インターフェイス (Except2) >>> */
31|/*-----------------------------------------------------------------------*/
32|
33|#ifndef NDEBUG
34|INF_FUNC_0( Except2,_delete, void, Except2_delete, Except2 )
35|INF_FUNC_R1( Except2,isType, bool, Except2_isType, Except2,char* )
36|INF_FUNC_R0( Except2,print, char*, Except2_print, Except2 )
37|#endif
38|
39|
40|
41|/*-----------------------------------------------------------------------*/
42|/* 4. <<< ◆標準・例外メッセージ (Except2_Str) >>> */
43|/*-----------------------------------------------------------------------*/
44|
45|
46|
47|/*************************************************************************
48|* 5. <<< [Except2_Std_newExcept2] 生成 >>>
49|*【引数】
50|* ・int code; エラーコード
51|* ・char* msg; エラーメッセージ
52|**************************************************************************/
53|Except2 Except2_Std_newExcept2( int code, const char* msg )
54|{
55| Except2_std.code = code;
56| #ifndef EXCEPT2_NOMSG
57| strcpy( Except2_std.codeStr, "???" );
58| strcpy( Except2_std.msg, msg );
59| #endif
60|
61| return Except2_Std_inf_Except2( &Except2_std );
62|}
63|
64|
65|
66|/*************************************************************************
67|* 6. <<< [Except2_Std_newExcept2_f] 生成 >>>
68|*【補足】
69|*・引数は、printf と同じです。
70|**************************************************************************/
71|Except2 Except2_Std_newExcept2_f( int code, const char* fmt, ... )
72|{
73| #ifndef EXCEPT2_NOMSG
74| va_list va;
75| #endif
76|
77| Except2_std.code = code;
78| #ifndef EXCEPT2_NOMSG
79| strcpy( Except2_std.codeStr, "???" );
80| va_start( va, fmt );
81| vsprintf( Except2_std.msg, fmt, va );
82| va_end( va );
83| #endif
84|
85| return Except2_Std_inf_Except2( &Except2_std );
86|}
87|
88|
89|
90|/*************************************************************************
91|* 7. <<< [Except2_Std_newExcept2_c] 生成 >>>
92|*【補足】
93|*・code のマクロ名を codeStr に指定します。
94|**************************************************************************/
95|Except2 Except2_Std_newExcept2_c( int code, const char* codeStr,
96| const char* msg )
97|{
98| Except2_std.code = code;
99| #ifndef EXCEPT2_NOMSG
100| strcpy( Except2_std.codeStr, codeStr );
101| strcpy( Except2_std.msg, msg );
102| #endif
103|
104| return Except2_Std_inf_Except2( &Except2_std );
105|}
106|
107|
108|
109|/*************************************************************************
110|* 8. <<< [Except2_Std_newExcept2_cf] 生成 >>>
111|*【補足】
112|*・code のマクロ名を codeStr に指定します。
113|*・引数は、printf と同じです。
114|**************************************************************************/
115|Except2 Except2_Std_newExcept2_cf( int code, const char* codeStr,
116| const char* fmt, ... )
117|{
118| #ifndef EXCEPT2_NOMSG
119| va_list va;
120| #endif
121|
122| Except2_std.code = code;
123| #ifndef EXCEPT2_NOMSG
124| strcpy( Except2_std.codeStr, codeStr );
125| va_start( va, fmt );
126| vsprintf( Except2_std.msg, fmt, va );
127| va_end( va );
128| #endif
129|
130| return Except2_Std_inf_Except2( &Except2_std );
131|}
132|
133|
134|
135|/*************************************************************************
136|* 9. <<< [Except2_Std_delete] 削除 >>>
137|**************************************************************************/
138|void Except2_Std_delete( Except2_Std* m )
139|{
140|}
141|
142|
143|
144|/*************************************************************************
145|* 10. <<< [Except2_Std_isType] 型チェック >>>
146|**************************************************************************/
147|bool Except2_Std_isType( Except2_Std* m, char* type )
148|{
149| return ( strcmp( type, "Except2_Std*" ) == 0 );
150|}
151|
152|
153|
154|/*************************************************************************
155|* 11. <<< [Except2_Std_print] 例外状況を表示する >>>
156|**************************************************************************/
157|char* Except2_Std_print( Except2_Std* m )
158|{
159| static char s[1024];
160| Except2_Std_sprint( m, s );
161| return Errors_printf_release( "%s", s );
162|}
163|
164|
165|
166|/*************************************************************************
167|* 12. <<< [Except2_Std_sprint] 例外状況を文字列にする >>>
168|**************************************************************************/
169|int Except2_Std_sprint( Except2_Std* m, char* s )
170|{
171| int iTry = Except2_sys.nTry - Except2_sys.nThrow;
172| char* try_file;
173| int try_line;
174| char* throw_file;
175| int throw_line;
176| int ret;
177|
178| if ( iTry >= 0 ) {
179| try_file = Except2_sys.try_file[iTry];
180| try_line = Except2_sys.try_line[iTry];
181| }
182|
183| throw_file = Except2_sys.throw_file[Except2_sys.nThrow - 1];
184| throw_line = Except2_sys.throw_line[Except2_sys.nThrow - 1];
185|
186| #ifdef EXCEPT2_NOMSG
187| if ( iTry >= 0 ) {
188| ret = sprintf( s, "%s(%d) : errcode %d : from try in %s(%d)",
189| throw_file, throw_line, m->code, try_file, try_line );
190| }
191| else {
192| ret = sprintf( s, "%s(%d) : errcode %d : without try block",
193| throw_file, throw_line, m->code );
194| }
195| #else
196| if ( iTry >= 0 ) {
197| ret = sprintf( s, "%s(%d) : errcode %d %s : %s : from try in %s(%d)",
198| throw_file, throw_line, m->code, m->codeStr, m->msg, try_file, try_line );
199| }
200| else {
201| ret = sprintf( s, "%s(%d) : errcode %d %s : %s : without try block",
202| throw_file, throw_line, m->code, m->codeStr, m->msg );
203| }
204| #endif
205|
206| return ret;
207|}
208|
209|
210|
211|/*************************************************************************
212|* 13. <<< [Except2_Std_inf_Except2] 例外メッセージ・インターフェイスを返す >>>
213|**************************************************************************/
214|INF_SUB_FUNC( Except2_Std, Except2, Except2_Std_by_Except2 )
215|
216|Except2 Except2_Std_inf_Except2( Except2_Std* m )
217|{
218| INF_SUB_SC_START( Except2_Std, Except2 );
219| INF_SUB_SC_METHOD_0( Except2_Std, _delete, void, Except2_Std_delete, Except2_Str );
220| INF_SUB_SC_METHOD_1( Except2_Std, isType, bool, Except2_Std_isType, Except2_Str, char* );
221| INF_SUB_SC_METHOD_0( Except2_Std, print, char*, Except2_Std_print, Except2_Str );
222| INF_SUB_SC_END( Except2_Std, Except2 );
223|}
224|
225|
226|
227|/*-----------------------------------------------------------------------*/
228|/* 14. <<< ◆文字列・例外メッセージ (Except2_Str) >>> */
229|/*-----------------------------------------------------------------------*/
230|
231|
232|
233|/*************************************************************************
234|* 15. <<< [Except2_Str_newExcept2] 生成 >>>
235|**************************************************************************/
236|Except2 Except2_Str_newExcept2( const char* msg )
237|{
238| strcpy( Except2_str.errorMsg, msg );
239|
240| return Except2_Str_inf_Except2( &Except2_str );
241|}
242|
243|
244|
245|/*************************************************************************
246|* 16. <<< [Except2_Str_newExcept2_f] 生成 >>>
247|*【補足】
248|*・引数は、printf と同じです。
249|**************************************************************************/
250|Except2 Except2_Str_newExcept2_f( const char* fmt, ... )
251|{
252| va_list va;
253|
254| va_start( va, fmt );
255| vsprintf( Except2_str.errorMsg, fmt, va );
256| va_end( va );
257|
258| return Except2_Str_inf_Except2( &Except2_str );
259|}
260|
261|
262|
263|/*************************************************************************
264|* 17. <<< [Except2_Str_delete] 削除 >>>
265|**************************************************************************/
266|void Except2_Str_delete( Except2_Str* m )
267|{
268|}
269|
270|
271|
272|/*************************************************************************
273|* 18. <<< [Except2_Str_isType] 型チェック >>>
274|**************************************************************************/
275|bool Except2_Str_isType( Except2_Str* m, char* type )
276|{
277| return ( strcmp( type, "Except2_Str*" ) == 0 );
278|}
279|
280|
281|
282|/*************************************************************************
283|* 19. <<< [Except2_Str_print] 例外状況を表示する >>>
284|**************************************************************************/
285|char* Except2_Str_print( Except2_Str* m )
286|{
287| return Errors_printf_release( "以下の例外が発生しました:\n%s\n", m->errorMsg );
288|}
289|
290|
291|
292|/*************************************************************************
293|* 20. <<< [Except2_Str_inf_Except2] 例外メッセージ・インターフェイスを返す >>>
294|**************************************************************************/
295|INF_SUB_FUNC( Except2_Str, Except2, Except2_Str_by_Except2 )
296|
297|Except2 Except2_Str_inf_Except2( Except2_Str* m )
298|{
299| INF_SUB_SC_START( Except2_Str, Except2 );
300| INF_SUB_SC_METHOD_0( Except2_Str, _delete, void, Except2_Str_delete, Except2_Str );
301| INF_SUB_SC_METHOD_1( Except2_Str, isType, bool, Except2_Str_isType, Except2_Str, char* );
302| INF_SUB_SC_METHOD_0( Except2_Str, print, char*, Except2_Str_print, Except2_Str );
303| INF_SUB_SC_END( Except2_Str, Except2 );
304|}
305|
306|
307|
308|/*-----------------------------------------------------------------------*/
309|/* 21. <<< ◆ファイル・例外メッセージ (Except2_File) >>> */
310|/*-----------------------------------------------------------------------*/
311|
312|
313|
314|/*************************************************************************
315|* 22. <<< [Except2_File_newExcept2] 生成 >>>
316|**************************************************************************/
317|#ifndef FOR_NOFILE
318|Except2 Except2_File_newExcept2( const char* fname, int errorCode )
319|{
320| if ( fname != NULL ) {
321| strcpy( Except2_file.fname, fname );
322| _getcwd( Except2_file.fullpath, _MAX_PATH );
323| #ifdef USES_STRX
324| StrX_addFName( Except2_file.fullpath, fname );
325| StrX_toRegularPath( Except2_file.fullpath );
326| #else
327| strcpy( Except2_file.fullpath, "???" );
328| #endif
329| }
330| else
331| strcpy( Except2_file.fname, "" );
332|
333| Except2_file.errorCode = errorCode;
334|
335| return Except2_File_inf_Except2( &Except2_file );
336|}
337|#endif /* not FOR_NOFILE */
338|
339|
340|
341|/*************************************************************************
342|* 23. <<< [Except2_File_delete] 削除 >>>
343|**************************************************************************/
344|#ifndef FOR_NOFILE
345|void Except2_File_delete( Except2_File* m )
346|{
347|}
348|#endif /* not FOR_NOFILE */
349|
350|
351|
352|/*************************************************************************
353|* 24. <<< [Except2_File_isType] 型チェック >>>
354|**************************************************************************/
355|#ifndef FOR_NOFILE
356|bool Except2_File_isType( Except2_File* m, char* type )
357|{
358| return ( strcmp( type, "Except2_File*" ) == 0 );
359|}
360|#endif /* not FOR_NOFILE */
361|
362|
363|
364|/*************************************************************************
365|* 25. <<< [Except2_File_print] 例外状況を表示する >>>
366|**************************************************************************/
367|#ifndef FOR_NOFILE
368|char* Except2_File_msgStr[] = {
369| "ファイルを読み込み用で開くことができません"
370| "(ファイルが無いか、ファイル名がちがいます)",
371| /* Except2_File_CannotReadOpen */
372| "ファイルを書き込み用で開くことができません"
373| "(ディスクが不足してるか書き込むフォルダがありません)",
374| /* Except2_File_CannotWriteOpen */
375| "EOF(ファイルの終端まで読み終えてしまいました)", /* Except2_File_EOF */
376| "ファイル・フォーマットが壊れています", /* Except2_File_BadFormat */
377|};
378|
379|char* Except2_File_print( Except2_File* m )
380|{
381| char* ret;
382|
383| ret = Errors_printf_release( "ファイル関連の例外が発生しました:\n\"%s\"\n(%s)\n(%d) %s\n",
384| m->fname, m->fullpath, m->errorCode, Except2_File_msgStr[ m->errorCode ] );
385| #ifndef NDEBUG
386| {
387| char* msg;
388| switch ( errno ) {
389| case ECHILD: msg = "ECHILD:子プロセスが存在しない"; break;
390| case EAGAIN: msg = "EAGAIN:これ以上プロセスを生成できない"; break;
391| case E2BIG: msg = "E2BIG:引数リストが長すぎる"; break;
392| case EACCES: msg = "EACCES:アクセスが拒否された"; break;
393| case EBADF: msg = "EBADF:不正なファイル番号"; break;
394| case EDEADLOCK: msg = "EDEADLOCK:リソースのデッドロックが発生する可能性がある"; break;
395| case EDOM: msg = "EDOM:数値演算関数の引数が関数のドメイン外の値である"; break;
396| case EINVAL: msg = "EINVAL:不正な引数"; break;
397| case EMFILE: msg = "EMFILE:開いているファイルが多すぎる"; break;
398| case ENOENT: msg = "ENOENT:ファイルまたはディレクトリがない"; break;
399| case ENOEXEC: msg = "ENOEXEC:実行ファイルのエラー"; break;
400| case ENOMEM: msg = "ENOMEM:メモリ不足"; break;
401| case ENOSPC: msg = "ENOSPC:デバイスの空き領域不足"; break;
402| case ERANGE: msg = "ERANGE:結果が大きすぎる"; break;
403| case EXDEV: msg = "EXDEV:デバイス間リンク"; break;
404| default: msg = "?"; break;
405| }
406| Errors_printf_release( "errno = %s", msg );
407| }
408| #endif
409|
410| return ret;
411|}
412|#endif /* not FOR_NOFILE */
413|
414|
415|
416|/*************************************************************************
417|* 26. <<< [Except2_File_inf_Except2] 例外メッセージ・インターフェイスを返す >>>
418|**************************************************************************/
419|#ifndef FOR_NOFILE
420|INF_SUB_FUNC( Except2_File, Except2, Except2_File_by_Except2 )
421|
422|Except2 Except2_File_inf_Except2( Except2_File* m )
423|{
424| INF_SUB_SC_START( Except2_File, Except2 );
425| INF_SUB_SC_METHOD_0( Except2_File, _delete, void, Except2_File_delete, Except2_File );
426| INF_SUB_SC_METHOD_1( Except2_File, isType, bool, Except2_File_isType, Except2_File, char* );
427| INF_SUB_SC_METHOD_0( Except2_File, print, char*, Except2_File_print, Except2_File );
428| INF_SUB_SC_END( Except2_File, Except2 );
429|}
430|#endif /* not FOR_NOFILE */
431|
432|
433|
434|/*-----------------------------------------------------------------------*/
435|/* 27. <<< ◆例外処理システム (Except2_Sys) >>> */
436|/*-----------------------------------------------------------------------*/
437|
438|
439|
440|/*************************************************************************
441|* 28. <<< try の実装 [Except2_Sys_try_imp] >>>
442|**************************************************************************/
443|int Except2_Sys_try_imp( char* file, int line )
444|{
445| if ( Except2_sys.nTry < Except2_Sys_mTry ) {
446| Except2_sys.try_file[Except2_sys.nTry] = file;
447| Except2_sys.try_line[Except2_sys.nTry] = line;
448| }
449| else {
450| Except2_sys.excepHdl( Except2_Err_BufFull, "try バッファ不足です" );
451| Except2_sys.errHdl( Except2_Err_BufFull, "try バッファ不足です" );
452| Errors_exit(__FILE__,__LINE__);
453| }
454| Except2_sys.nTry ++;
455| Except2_sys.msg_bAgain = false;
456|
457| return 0;/*dumy*/
458|}
459|
460|
461|
462|/*************************************************************************
463|* 29. <<< catch の実装 [Except2_Sys_catch_imp] >>>
464|*【引数】
465|*・int 返り値; catch するかどうか
466|**************************************************************************/
467|int Except2_Sys_catch_imp( char* className, char* file, int line )
468|{
469| int ret;
470|
471| if ( Except2_sys.msg_bAgain ) return false;
472|
473| Except2_sys.catch_file = file;
474| Except2_sys.catch_line = line;
475|
476| ret = ( strcmp( className, "..." ) == 0 );
477| if ( !ret )
478| ret = Except2_isType( Except2_sys.msg, className );
479|
480| if ( ret ) {
481| Except2_sys.msg_bCatch = true;
482| }
483|
484| return ret;
485|}
486|
487|
488|
489|/*************************************************************************
490|* 30. <<< end_catch, end_finally の実装 [Except2_Sys_end_finally_imp] >>>
491|**************************************************************************/
492|void Except2_Sys_end_finally_imp()
493|{
494| /* 例外が発生した場合 */
495| if ( Except2_sys.msg_bExist ) {
496| if ( Except2_sys.msg_bAgain ) { /* 再スローの場合 */
497| Except2_sys.msg_bAgain = false;
498| Except2_sys.msg_bCatch = false;
499| longjmp( Except2_sys.longjmp_buf[Except2_sys.nTry - Except2_sys.nThrow], 1 );
500| }
501| else if ( ! Except2_sys.msg_bCatch ) { /* catch に指定した以外のタイプの場合 */
502| Except2_sys.msg_bAgain = true;
503| throw_again(); /* スロー時のパラメータ調整のため、上の if と区別 */
504| }
505| else { /* catch して例外復帰が完了した場合 */
506| Except2_delete( Except2_sys.msg );
507| Except2_sys.msg_bExist = false;
508| Except2_sys.nTry -= Except2_sys.nThrow;
509| Except2_sys.nThrow = 0;
510| Except2_sys.msg_bCatch = false;
511| }
512| }
513|
514| /* 例外が発生していなかった場合 */
515| else {
516| Except2_sys.nTry --;
517| }
518|}
519|
520|
521|
522|/*************************************************************************
523|* 31. <<< throw の実装 [Except2_Sys_throw_imp] >>>
524|**************************************************************************/
525|void Except2_Sys_throw_imp( Except2 msg, char* file, int line )
526|{
527| int act; /* ERRORS_EXIT or ERRORS_IGNORE */
528| static char s[1024];
529|
530| /* ファイルの位置を記録する */
531| if ( Except2_sys.nThrow < Except2_Sys_mThrow ) {
532| Except2_sys.throw_file[Except2_sys.nThrow] = file;
533| Except2_sys.throw_line[Except2_sys.nThrow] = line;
534| }
535|
536| /* 違うものを再 throw するとき、前の例外を削除する */
537| if ( Except2_sys.nThrow > 0 ) {
538| if ( Except2_sys.msg.obj != msg.obj )
539| Except2_delete( Except2_sys.msg );
540| }
541|
542| /* 例外メッセージを登録する */
543| Except2_sys.msg = msg;
544| Except2_sys.msg_bExist = true;
545| Except2_sys.nThrow ++;
546|
547| #ifdef USES_ERRORS
548|
549| /* 例外処理ハンドラを起動する */
550| if ( Except2_sys.excepHdl == NULL )
551| act = ERRORS_IGNORE;
552| else {
553| if ( Except2_isType( Except2_sys.msg, "Except2_Std*" ) ) {
554| Except2_Std* e;
555| e = Except2_Std_by_Except2( Except2_sys.msg );
556|
557| #ifndef EXCEPT2_NOMSG
558| Except2_Std_sprint( e, s );
559| act = Except2_sys.excepHdl( e->code, s );
560| #else
561| act = Except2_sys.excepHdl( e->code, "" );
562| #endif
563| }
564| else
565| act = Except2_sys.excepHdl( Errors_Unofficial, "" );
566| }
567|
568| /* エラー処理ハンドラを起動する */
569| if ( act == ERRORS_IGNORE ) {
570| if ( Except2_sys.errHdl == NULL ) {
571| if ( Except2_sys.nTry < Except2_sys.nThrow )
572| act = ERRORS_EXIT;
573| else
574| act = ERRORS_IGNORE;
575| }
576| else {
577| if ( Except2_sys.nTry <= Except2_sys.nThrow ) {
578| if ( Except2_isType( Except2_sys.msg, "Except2_Std*" ) ) {
579| Except2_Std* e;
580| e = Except2_Std_by_Except2( Except2_sys.msg );
581|
582| #ifndef EXCEPT2_NOMSG
583| Except2_Std_sprint( e, s );
584| act = Except2_sys.errHdl( e->code, s );
585| #else
586| act = Except2_sys.errHdl( e->code, "" );
587| #endif
588| }
589| else
590| act = Except2_sys.errHdl( Errors_Unofficial, "" );
591| }
592| }
593| }
594| #else
595| acr = ERRORS_IGNORE;
596| #endif
597|
598| /* ロングジャンプする */
599| /* 通常のスローは、上位の catch へ、catch 内での再スロー は同位の finally へ */
600| if ( act == ERRORS_IGNORE && Except2_sys.nTry >= Except2_sys.nThrow ) {
601| if ( Except2_sys.nThrow == 1 || Except2_sys.msg_bAgain ) {
602| Except2_sys.msg_bAgain = false;
603| longjmp( Except2_sys.longjmp_buf[Except2_sys.nTry - Except2_sys.nThrow], 1 );
604| }
605| else {
606| Except2_sys.msg_bAgain = true;
607| longjmp( Except2_sys.longjmp_buf[Except2_sys.nTry - Except2_sys.nThrow + 1], 1 );
608| }
609| }
610|
611| /* デフォルト・エラーメッセージ */
612| Except2_print( msg );
613|
614| #ifdef USES_ERRORS
615| Errors_exit(__FILE__,__LINE__);
616| #else
617| exit(1);
618| #endif
619|}
620|
621|
622|
623|/*************************************************************************
624|* 32. <<< [Except2_Sys_print] 例外発生の記録を出力する >>>
625|*【補足】
626|*・ファイル trylog.txt に例外処理の出力します
627|**************************************************************************/
628|void Except2_Sys_print()
629|{
630| Except2_print( Except2_sys.msg );
631|
632| #ifndef NDEBUG
633| #ifndef FOR_NOFILE
634| {
635| int i;
636| FILE* file;
637|
638| if ( Except2_sys.nTry > 0 ) {
639| file = fopen( "trylog.txt", "wt" );
640| fprintf( file, "Except2 log...\n" );
641| for ( i = 0; i < Except2_sys.nTry; i++ ) {
642| fprintf( file, " try %s:%d\n",
643| Except2_sys.try_file[i], Except2_sys.try_line[i] );
644| }
645| for ( i = 0; i < Except2_sys.nThrow; i++ ) {
646| fprintf( file, " throw %s:%d\n",
647| Except2_sys.throw_file[i], Except2_sys.throw_line[i] );
648| }
649| if ( Except2_sys.msg_bCatch ) {
650| fprintf( file, " catch %s:%d\n",
651| Except2_sys.catch_file, Except2_sys.catch_line );
652| }
653| fclose( file );
654| Errors_printf( "以下の場所から例外が発生しました:\n%s(%d)\n"
655| "(詳細は trylog.txt に出力しました)",
656| Except2_sys.throw_file[0], Except2_sys.throw_line[0] );
657| }
658| else {
659| Errors_printf( "以下の場所から例外が発生しました:\n%s(%d)",
660| Except2_sys.throw_file[0], Except2_sys.throw_line[0] );
661| }
662| }
663| #endif
664| #endif
665|}
666|
667|