STDPLUS.C
[目次 | 関数 | マクロ]
1|/*************************************************************************
2|* 1. <<< 標準ライブラリ拡張 (StdPlus) >>>
3|**************************************************************************/
4|
5|#include "mixer_precomp.h" /* Auto precompiled header, Look at mixer-... folder */
6|
7|#define STDLIBS_INCLUDE_STRING_H
8|#define STDLIBS_INCLUDE_STDARG_H
9|#ifdef USES_MXP_AUTOINC
10| #include "stdplus.ah" /* Auto include header, Look at mixer-... folder */
11|#endif
12|
13|#ifndef STDPLUS_NOT_ERRNO
14| #include <errno.h>
15|#endif
16|
17|
18|/*-----------------------------------------------------------------------*/
19|/* 2. <<< ◆(StdPlus) 標準ライブラリ拡張 >>> */
20|/*-----------------------------------------------------------------------*/
21|
22|int StdPlus_mallocCount = 0;
23|
24|
25|/*************************************************************************
26|* 3. <<< [StdPlus_printErrno] errno 変数の値をエラー表示する >>>
27|**************************************************************************/
28|#if !defined(STDPLUS_NOT_ERRNO) && ( defined(STDPLUS_USES_STDLIB) || defined(USES_FILEX) )
29|void StdPlus_printErrno()
30|{
31| char* s = "Unknown Error";
32|
33| switch ( errno ) {
34| case ECHILD: s = "ECHILD 子プロセスが存在しない"; break;
35| case EAGAIN: s = "EAGAIN これ以上プロセスを生成できない。"; break;
36| case E2BIG: s = "E2BIG 引数リストが長すぎる"; break;
37| case EACCES: s = "EACCES アクセスが拒否された。"; break;
38| case EBADF: s = "EBADF 不正なファイル番号。"; break;
39| case EDEADLOCK: s = "EDEADLOCK リソースのデッドロックが発生する可能性がある。"; break;
40| case EDOM: s = "EDOM 数値演算関数の引数が関数のドメイン外の値である。"; break;
41| case EEXIST: s = "EXIST ファイルが存在する。"; break;
42| case EINVAL: s = "EINVAL 不正な引数。"; break;
43| case EMFILE: s = "EMFILE 開いているファイルが多すぎる。"; break;
44| case ENOENT: s = "ENOENT ファイルまたはディレクトリがない。"; break;
45| case ENOEXEC: s = "ENOEXEC 実行ファイルのエラー。"; break;
46| case ENOMEM: s = "ENOMEM メモリ不足。"; break;
47| case ENOSPC: s = "ENOSPC デバイスの空き領域不足。"; break;
48| case ERANGE: s = "ERANGE 結果が大きすぎる。"; break;
49| case EXDEV: s = "EXDEV デバイス間リンク。"; break;
50| }
51|
52| Errors_errPrintf( "errno = %d : %s", errno, s );
53|}
54|#endif
55|
56|
57|/***********************************************************************
58|* 4. <<< [StdPlus_malloc] 拡張 malloc >>>
59|* 5. <<< [StdPlus_malloc_imp] >>>
60|*【補足】
61|*・メモリ領域を確保できなかった場合、エラーになります。
62|*・StdPlus_free と呼出し回数をチェックすることができるようになります。
63|* (StdPlus_chkFree 関数)
64|*・StdPlus_malloc と StdPlus_free はなるべく直接呼び出さないようにし、
65|* STDPLUS_USES_STDNAME を #define して、malloc を StdPlus_malloc に
66|* 書きかえるようにします。さもなければ、StdPlus_malloc と標準ライブラリの
67|* free を呼び出すようなことが起きる可能性が出てしまい、呼び出し回数の
68|* チェックがおかしくなることがあります。
69|*・例外処理により確実に free するには次のようにします。
70|* Type* p = NULL; // NULL で初期化しておく
71|* try {
72|* p = malloc( 20 ); // try の中で StdPlus_malloc を呼び出す
73|* :
74|* }
75|* finally { // finally または catch の中で StdPlus_free を呼び出す。
76|* free( p ); // StdPlus_free 内部で、NULL ならフリーしない
77|* } end_finally;
78|************************************************************************/
79|#ifdef STDPLUS_USES_STDLIB
80|
81|int StdPlus_chkAdr = 0x00000000;
82|
83|#ifndef STDPLUS_PRINT_NOT_FREE
84| void* StdPlus_malloc( int size )
85|#else
86| void* StdPlus_malloc_imp( int size, char* file, int line )
87|#endif
88|{
89| #ifdef STDPLUS_USES_STDNAME
90| #undef malloc
91| #endif
92|
93| void* p = malloc( size );
94|
95| #ifdef STDPLUS_PRINT_NOT_FREE
96| StdPlus_FreeChk_setMalloc( StdPlus_FreeChk_getGlobl(), p, file, line );
97| #endif
98|
99| if ( p == NULL )
100| error2_0( StdPlus_Err_MallocFailure, "malloc できません" );
101| else
102| StdPlus_mallocCount ++;
103|
104| /* デバッグ用、malloc した位置を知るため */
105| /* 次の free & malloc で同じアドレスを返すことがあるので注意 */
106| #ifndef NDEBUG
107| if ( (int)p == StdPlus_chkAdr ) { /* ここに開放されていないアドレスを記述する(1) */
108| Errors_printf( "malloc ( %p );", p ); /* ここにブレークポイントを張る */
109| //COUNT(0)
110| // Errors_break(1);
111| }
112| #endif
113|
114| return p;
115|
116| #ifdef STDPLUS_USES_STDNAME
117| #define malloc StdPlus_malloc
118| #endif
119|}
120|#endif
121|
122|
123|/***********************************************************************
124|* 6. <<< [StdPlus_free] 拡張 free >>>
125|* 7. <<< [StdPlus_free_imp] >>>
126|*【補足】
127|*・引数に NULL を指定した場合、何もしません。
128|*・StdPlus_malloc と呼出し回数をチェックすることができるようになります。
129|* (StdPlus_chkFree 関数)
130|*・STDPLUS_PRINT_NOT_FREE を #define すると、free していないアドレスを
131|* 表示できます。(Errors_chkDefault で)
132|*・STDPLUS_USES_STDNAME を #define すると、free を StdPlus_free に
133|* 書きかえるようになります。
134|************************************************************************/
135|#ifdef STDPLUS_USES_STDLIB
136|
137|#ifndef STDPLUS_PRINT_NOT_FREE
138| void StdPlus_free( void* p )
139|#else
140| void StdPlus_free_imp( void* p, char* file, int line )
141|#endif
142|{
143| #ifdef STDPLUS_USES_STDNAME
144| #undef free
145| #endif
146|
147| #ifdef STDPLUS_PRINT_NOT_FREE
148| StdPlus_FreeChk_setFree( StdPlus_FreeChk_getGlobl(), p, file, line );
149| #endif
150|
151| if ( p != NULL ) {
152|
153| /* デバッグ用、free した位置を知るため */
154| /* 次の free & malloc で同じアドレスを返すことがあるので注意 */
155| #ifndef NDEBUG
156| if ( (int)p == StdPlus_chkAdr ) /* ここに開放されていないアドレスを記述する(2) */
157| Errors_printf( "free ( %p );", p ); /* ここにブレークポイントを張る */
158| #endif
159|
160| free( p );
161| StdPlus_mallocCount --;
162| }
163|
164| #ifdef STDPLUS_USES_STDNAME
165| #define free StdPlus_free
166| #endif
167|}
168|#endif
169|
170|
171|/***********************************************************************
172|* 8. <<< [StdPlus_chkMalloc] malloc したアドレスをチェックする >>>
173|*【引数】
174|* ・void* p1 ...; malloc したポインタの羅列(最後は StdPlus_End)
175|* ・int 返り値; Errors_NoError か StdPlus_Err_MallocFailure
176|*【例】
177|* StdPlus_chkMalloc( ptr, ptr2, StdPlus_End );
178|*【補足】
179|*・例外処理と StdPlus_malloc を使用すれば、本関数を使わなくても
180|* 同じことができます。
181|*・第1引数以降は malloc したポインタを並べて、最後は StdPlus_End を
182|* 指定します。
183|*・指定したポインタの中に1つでも NULL があれば、エラーになります。
184|* その際、NULL 以外のポインタを free してからエラーハンドラを呼び出します。
185|* エラーハンドラから戻ったら StdPlus_Err_MallocFailure を返します。
186|************************************************************************/
187|#ifdef STDPLUS_USES_STDLIB
188|int StdPlus_chkMalloc( void* p1, ... )
189|{
190| va_list va;
191| void* p;
192| bool err = false;
193|
194| /* NULL が1つでもあるかどうか */
195| va_start( va, p1 );
196| for (;;) {
197| p = va_arg( va, void* );
198| if ( p == StdPlus_End ) break;
199| if ( p == NULL ) { err = true; break; }
200| }
201| va_end( va );
202|
203| /* NULL があれば、NULL 以外を全て free してエラー */
204| if ( err ) {
205| va_start( va, p1 );
206| for (;;) {
207| p = va_arg( va, void* );
208| if ( p == StdPlus_End ) break;
209| if ( p != NULL ) free( p );
210| }
211| va_end( va );
212|
213| error2_0( StdPlus_Err_MallocFailure, "malloc できませんでした" );
214| return StdPlus_Err_MallocFailure;
215| }
216| else {
217| return Errors_NoError;
218| }
219|}
220|#endif
221|
222|
223|/***********************************************************************
224|* 9. <<< [StdPlus_chkFree] free した回数をチェックする >>>
225|*【補足】
226|*・ERRORS_FINISHCHK から呼び出されます。
227|*・通常、プログラムの最後で呼び出します。
228|*・StdPlus_malloc と StdPlus_free の呼出し回数が異なるときは、
229|* エラーになります。
230|************************************************************************/
231|void StdPlus_chkFree()
232|{
233| if ( StdPlus_mallocCount != 0 ) {
234| #ifdef STDPLUS_PRINT_NOT_FREE
235| StdPlus_FreeChk_printNotFree( StdPlus_FreeChk_getGlobl() );
236| #endif
237| Errors_printf_release( "malloc と free の回数が合いません。(%+d)",
238| StdPlus_mallocCount );
239| }
240|}
241|
242|
243|/**************************************************************************
244|* 10. <<< [StdPlus_itoa] 数値を文字列に変換する >>>
245|*【引数】
246|* ・int value; 数値
247|* ・char* string; 文字列を格納する領域の先頭アドレス
248|* ・int radix; 進数
249|* ・char* 返り値; string と同じ
250|*【補足】
251|*・16進数などのアルファベット文字は大文字になります。
252|*・標準ライブラリに _itoa は存在しません。
253|***************************************************************************/
254|char* StdPlus_itoa( int value, char* string, int radix )
255|{
256| char* p = string;
257| char* pp;
258| int m;
259| int bMinus;
260|
261| ASSERT( 1 <= radix && radix <= 36);
262|
263| bMinus = (value < 0 );
264| if ( bMinus ) value = -value;
265|
266| /* 下の桁から数字を格納する */
267| if ( radix <= 10 ) {
268| do {
269| m = value % radix;
270| *p = m + '0';
271| value /= radix;
272| p++;
273| } while ( value != 0 );
274| }
275| else {
276| do {
277| m = value % radix;
278| *p = m + ( m < 10 ? '0' : 'A'-10 );
279| value /= radix;
280| p++;
281| } while ( value != 0 );
282| }
283| if ( bMinus ) {
284| *p = '-'; p++;
285| }
286| *p = '\0';
287|
288| /* 下の桁から上の桁を入れ替える */
289| pp = string; p--;
290| while ( pp < p ) {
291| m = *pp; *pp = *p; *p = m;
292| pp++; p--;
293| }
294|
295| return string;
296|}
297|
298|
299|
300|
301|/**************************************************************************
302|* 11. <<< [StdPlus_utoa] 数値を文字列に変換する >>>
303|*【引数】
304|* ・unsigned int value; 数値
305|* ・char* string; 文字列を格納する領域の先頭アドレス
306|* ・int radix; 進数
307|* ・char* 返り値; string と同じ
308|*【補足】
309|*・16進数などのアルファベット文字は大文字になります。
310|*・標準ライブラリに _utoa は存在しません。
311|***************************************************************************/
312|char* StdPlus_utoa( unsigned value, char* string, int radix )
313|{
314| char* p = string;
315| char* pp;
316| int m;
317|
318| ASSERT( 1 <= radix && radix <= 36);
319|
320| /* 下の桁から数字を格納する */
321| if ( radix <= 10 ) {
322| do {
323| m = value % radix;
324| *p = m + '0';
325| value /= radix;
326| p++;
327| } while ( value != 0 );
328| }
329| else {
330| do {
331| m = value % radix;
332| *p = m + ( m < 10 ? '0' : 'A'-10 );
333| value /= radix;
334| p++;
335| } while ( value != 0 );
336| }
337| *p = '\0';
338|
339| /* 下の桁から上の桁を入れ替える */
340| pp = string; p--;
341| while ( pp < p ) {
342| m = *pp; *pp = *p; *p = m;
343| pp++; p--;
344| }
345|
346| return string;
347|}
348|
349|
350|
351|
352|/**************************************************************************
353|* 12. <<< [StdPlus_xtoi] 16進数文字列を数値に変換する >>>
354|*【引数】
355|* ・char* hex; 16進数文字列
356|* ・int 返り値; 数値
357|***************************************************************************/
358|int StdPlus_xtoi( char* hex )
359|{
360| char* s = hex;
361| int c;
362| int num = 0;
363|
364| while ( *s != '\0' ) {
365| c = *s;
366| if ( c >= '0' && c < '9' ) num = num * 16 + (c - '0');
367| else if ( c >= 'A' && c < 'F' ) num = num * 16 + (c - 'A' + 10);
368| else if ( c >= 'a' && c < 'f' ) num = num * 16 + (c - 'a' + 10);
369| else return num;
370| s++;
371| }
372| return num;
373|}
374|
375|
376|
377|/***********************************************************************
378|* 13. <<< [StdPlus_inputS] 文字列の初期値の入力 >>>
379|*【引数】
380|* ・char* msg; プロンプト・メッセージ
381|* ・char* out; 入力結果(出力)
382|* ・int out_size; out のサイズ
383|* ・char* def; デフォルト値
384|*【補足】
385|*・sdvex を使用しています。
386|*・BS キーで入力しなおします。
387|*・リターンキーのみで、デフォルト値が入力結果に格納されます。
388|************************************************************************/
389|#ifdef USES_SDVEX
390|void StdPlus_inputS( const char* msg, char* out, int out_size, const char* def )
391|{
392| int i = 0;
393| int c;
394| printf( "%s", msg );
395|
396| for (;;) {
397| c = inkey();
398| if ( c == 0 ) continue;
399| else if ( c == 13 ) break;
400| #ifdef USES_ERRORS
401| else if ( c == 0x1B )
402| error2_0( 0, "ユーザ・ブレイク" );
403| #endif
404| else if ( c == 8 ) {
405| printf( "\n%s", msg );
406| i = 0;
407| }
408| else {
409| if ( i < out_size - 1 ) {
410| printf( "%c", c );
411| out[i] = c;
412| i++;
413| }
414| }
415| }
416|
417| /* 値を設定する */
418| if ( i == 0 ) {
419| strcpy( out, def );
420| }
421| else {
422| out[i] = '\0';
423| }
424| printf( "\n" );
425|}
426|#endif
427|
428|
429|
430|/***********************************************************************
431|* 14. <<< [StdPlus_inputX] 16進数の初期値の入力 >>>
432|************************************************************************/
433|#ifdef USES_SDVEX
434|int StdPlus_inputX( const char* msg, int def )
435|{
436| enum { buf_size = 9 };
437| char buf[buf_size];
438|
439| StdPlus_inputS( msg, buf, buf_size, "" );
440|
441| if ( buf[0] == '\0' ) return def;
442| else return _xtoi( buf );
443|}
444|#endif
445|
446|
447|
448|/*-----------------------------------------------------------------------*/
449|/* 15. <<< ◆(StdPlus_FreeChk) free のし忘れを追跡するツール >>> */
450|/*-----------------------------------------------------------------------*/
451|
452|#ifndef ERRORS_CUT_DEBUT_TOOL
453|#ifdef STDPLUS_PRINT_NOT_FREE
454|
455|bool StdPlus_FreeChk_inited = false;
456|StdPlus_FreeChk StdPlus_FreeChk_globl;
457|
458|/***********************************************************************
459|* 16. <<< [StdPlus_FreeChk_init] 初期化する >>>
460|*【補足】
461|*・→StdPlus_FreeChk クラスの補足
462|************************************************************************/
463|void StdPlus_FreeChk_init( StdPlus_FreeChk* m )
464|{
465| StdPlus_FreeChkE* p;
466| StdPlus_FreeChkE* p_over = m->rec + StdPlus_FreeChk_Depth;
467|
468| StdPlus_FreeChk_inited = true;
469|
470| Errors_printf_release( "free し忘れの追跡ツールを起動します。" );
471|
472| m->count = 0;
473| for ( p = m->rec; p < p_over; p++ ) {
474| p->adr = NULL;
475| }
476|}
477|
478|
479|
480|/***********************************************************************
481|* 17. <<< [StdPlus_FreeChk_setMalloc] malloc に関する記録をする >>>
482|*【内部補足】
483|*・StdPlus_malloc の内部で呼び出されます。
484|************************************************************************/
485|int StdPlus_FreeChk_breakID = 2430;
486|
487|static void StdPlus_breakFunc() {BK} /* ここにブレークポイントを張ってください */
488|
489|
490|void StdPlus_FreeChk_setMalloc( StdPlus_FreeChk* m, void* adr, char* file, int line )
491|{
492| StdPlus_FreeChkE* p;
493| StdPlus_FreeChkE* p_over;
494| m->count ++;
495| if ( StdPlus_FreeChk_breakID == m->count ) StdPlus_breakFunc();
496|
497| if ( ! StdPlus_FreeChk_inited ) {
498| StdPlus_FreeChk_init( &StdPlus_FreeChk_globl );
499| // Errors_printf( "StdPlus_FreeChk_init を呼び出してください" );
500| // error();
501| }
502| p_over = m->rec + StdPlus_FreeChk_Depth;
503|
504| for ( p = m->rec; p < p_over; p++ ) {
505| if ( p->adr == NULL ) {
506| #if ERRORS_DEBUG_FALSE
507| Errors_printf( "malloc (%p) in %s(%d)", adr, file, line );
508| #endif
509| p->id = m->count; p->adr = adr; p->file = file; p->line = line;
510| return;
511| }
512| }
513| error2_0( StdPlus_Err_CannotContinueCheck,
514| "StdPlus_FreeChk_Depth を大きくしてください。" );
515|}
516|
517|
518|
519|/***********************************************************************
520|* 18. <<< [StdPlus_FreeChk_setFree] free に関する記録をする >>>
521|*【内部補足】
522|*・StdPlus_free の内部で呼び出されます。
523|************************************************************************/
524|void StdPlus_FreeChk_setFree( StdPlus_FreeChk* m, void* adr, char* file, int line )
525|{
526| StdPlus_FreeChkE* p;
527| StdPlus_FreeChkE* p_over;
528|
529| if ( ! StdPlus_FreeChk_inited ) {
530| StdPlus_FreeChk_init( &StdPlus_FreeChk_globl );
531| //Errors_printf( "StdPlus_FreeChk_init を呼び出してください" );
532| //error();
533| }
534| p_over = m->rec + StdPlus_FreeChk_Depth;
535|
536| if ( adr == NULL ) {
537| error2_2( StdPlus_Err_NullFree, "NULL がフリーされました in %s(%d)", file, line );
538| }
539|
540| for ( p = m->rec; p < p_over; p++ ) {
541| if ( p->adr == adr ) {
542| p->adr = NULL;
543| return;
544| }
545| }
546| error();
547|}
548|
549|/***********************************************************************
550|* 19. <<< [StdPlus_FreeChk_printNotFree] free していないアドレスを表示する >>>
551|************************************************************************/
552|void StdPlus_FreeChk_printNotFree( StdPlus_FreeChk* m )
553|{
554| StdPlus_FreeChkE* p;
555| StdPlus_FreeChkE* p_over = m->rec + StdPlus_FreeChk_Depth;
556| int count = 0;
557|
558| if ( ! StdPlus_FreeChk_inited ) {
559| Errors_printf( "StdPlus_FreeChk_init を呼び出してください" );
560| error();
561| }
562|
563| Errors_printf( "StdPlus_FreeChk result: Not free adress is ..." );
564| for ( p = m->rec; p < p_over; p++ ) {
565| if ( p->adr != NULL ) {
566| Errors_printf( "id = %d, adr = %p in %s(%d)", p->id, p->adr, p->file, p->line );
567| count++;
568| if ( count == 100 ) {
569| Errors_printf( "100件を超えたので続きの表示を中止します。" );
570| break;
571| }
572| }
573| }
574| Errors_printf( "StdPlus_FreeChk Done." );
575|}
576|
577|#endif
578|#endif
579|
580|