C:\home\SVGCats_src\src\inifile.c
1|/*********************************************************************** 2|* 1. <<< 初期化ファイル (IniFile) >>> 3|* 【拡張予定】 4|* ・コメントが書けること(これに関してのみ Windows との互換を考えない) 5|* ・ユーザが書いたコメントを消さないこと 6|************************************************************************/ 7| 8|#include "mixer_precomp.h" /* Auto precompiled header, Look at mixer-... folder */ 9|// #pragma hdrstop 10| 11|#ifdef USES_MXP_AUTOINC 12| #include <inifile.ah> /* Auto include header, Look at mixer-... folder */ 13|#endif 14| 15|char* IniFile_Write_componeName = "IniFile_Write"; 16|char* IniFile_Read_componeName = "IniFile_Read"; 17| 18| 19| 20|/*---------------------------------------------------------*/ 21|/* 2. <<<◆初期化ファイル・書き込みツール [IniFile_Write] >>> */ 22|/*---------------------------------------------------------*/ 23| 24| 25| 26|/*********************************************************************** 27|* 3. <<< [IniFile_Write_init] 初期化する・ファイルを開く >>> 28|************************************************************************/ 29|void IniFile_Write_init( IniFile_Write* m, const char* fname ) 30|{ 31| ERRORS_FINISHCHK_FOR_INIT( IniFile_Write_finish ); 32| 33| m->file = fopen( fname, "wt" ); 34| if ( m->file == NULL ) { 35| error2_1( FileX_Err_CannotWriteOpen, 36| "書きこみモードで open できません。%s", fname ); 37| } 38| m->firstSection = true; 39|} 40| 41| 42| 43|/*********************************************************************** 44|* 4. <<< [IniFile_Write_finish] 後始末する・ファイルを閉じる >>> 45|************************************************************************/ 46|void IniFile_Write_finish( IniFile_Write* m ) 47|{ 48| ERRORS_FINISHCHK_FOR_FINISH( IniFile_Write_finish ); 49| 50| fputs( " \n", m->file ); 51| fclose( m->file ); 52|} 53| 54| 55| 56|/*********************************************************************** 57|* 5. <<< [IniFile_Write_putSection] セクションを出力する >>> 58|************************************************************************/ 59|void IniFile_Write_putSection( IniFile_Write* m, const char* section ) 60|{ 61| if ( ! m->firstSection ) 62| fputs( " \n", m->file ); 63| m->firstSection = false; 64| fprintf( m->file, "[%s] \n", section ); 65|} 66| 67| 68| 69|/*********************************************************************** 70|* 6. <<< [IniFile_Write_putVar] 属性値を出力する >>> 71|*【引数】 72|* ・char* attr_name; 属性名 73|* ・char* types; 型リスト 74|* ・... 属性の値を並べたもの 75|*【補足】 76|*・types には、以下の型指定文字を並べた文字列を指定します。 77|* ・'s' 文字列型 78|* ・'i' 整数型(int型) 79|* ・'b' 論理型(bool型) 80|* ・'x' 整数型16進数(int型) 81|* ・'t' 日時型(time_t*型) 82|* ・'-' 属性値を無視(格納する変数を指定しない) 83|*【例】 84|*・attr = 1, string, 2 という属性値を出力する場合、 85|* printf と同様に、以下のように記述します。 86|* IniFile_Write_putVar( file, "attr", "isi", 1, "string", 2 ); 87|************************************************************************/ 88|void IniFile_Write_putVar( IniFile_Write* m, const char* attr_name, 89| const char* types, ... ) 90|{ 91| static char s[4096]; 92| va_list va; 93| 94| fprintf( m->file, "%s = ", attr_name ); 95| 96| va_start( va, types ); 97| 98| if ( *types != '\0' ) { 99| for (;;) { 100| switch ( *types ) { 101| case 's': 102| StrX_toCSV( s, va_arg( va, char* ), sizeof(s) ); 103| fputs( s, m->file ); 104| break; 105| case 'i': 106| fprintf( m->file, "%d", va_arg(va, int) ); 107| break; 108| case 'b': 109| fprintf( m->file, "%c", ( va_arg(va, bool) ? '1' : '0' ) ); 110| break; 111| case 'x': 112| fprintf( m->file, "0x%X", va_arg(va, int) ); 113| break; 114| case 't': 115| #ifdef USES_TIMEDATE 116| ASSERT( sizeof(s) >= TimeDate_loadBuf_size ); 117| TimeDate_saveStr( va_arg(va, time_t*), s ); 118| fputs( s, m->file ); 119| break; 120| #endif 121| default: 122| ASSERT( *types == '-' ); 123| break; 124| } 125| 126| types ++; 127| if ( *types == '\0' ) 128| break; 129| 130| fputs( ", ", m->file ); 131| } 132| } 133| 134| va_end( va ); 135| 136| fputs( "\n", m->file ); 137|} 138| 139| 140| 141|/*********************************************************************** 142|* 7. <<< [IniFile_Write_putLabel] ラベルを出力する >>> 143|*【引数】 144|* ・char* label; ラベル 145|*【補足】 146|*・ファイルには、ラベルの直後に ':' が付きます。 147|*・出力したラベルは、IniFile_Read_getVar 関数を使ってスキップする 148|* 必要があります。その際、型リストは "" にします。 149|************************************************************************/ 150|void IniFile_Write_putLabel( IniFile_Write* m, const char* label ) 151|{ 152| fprintf( m->file, "%s:\n", label ); 153|} 154| 155| 156| 157|/*********************************************************************** 158|* 8. <<< [IniFile_Write_putMultiLine] 複数行を出力する >>> 159|*【引数】 160|* ・char* attr_name; 属性名 161|* ・char* retStr; 改行文字("\r\n"や"\n") 162|* ・char* s; 複数行の文字列 163|*【補足】 164|*・ファイルには、以下のように同じ属性が並びます。 165|* attr = text of line 1 166|* attr = text of line 2 167|* attr = text of line 3 168|************************************************************************/ 169|#ifdef USES_STRX 170|void IniFile_Write_putMultiLine( IniFile_Write* m, const char* attr_name, 171| const char* retStr, const char* s ) 172|{ 173| enum { data_size = 256 }; 174| char* r; 175| char data[data_size]; 176| 177| for (;;) { 178| r = strstr( s, retStr ); 179| if ( r != NULL ) { 180| *(char*)r = '\0'; 181| StrX_toCSV( data, s, data_size - 1 ); 182| fprintf( m->file, "%s = %s\n", attr_name, data ); 183| *(char*)r = *retStr; 184| s = r + strlen( retStr ); 185| } 186| else { 187| if ( ! StrX_isSpaceStr( s ) ) { 188| StrX_toCSV( data, s, data_size - 1 ); 189| fprintf( m->file, "%s = %s\n", attr_name, data ); 190| } 191| return; 192| } 193| } 194|} 195|#endif 196| 197| 198|/************************************************************************** 199|* 9. <<< [IniFile_Write_putTypeInfo] ファイルのバージョンを読みこんでチェックする >>> 200|*【補足】 201|*・IniFile_Read_checkTypeInfo でデータをチェックできます。 202|***************************************************************************/ 203|void IniFile_Write_putTypeInfo( IniFile_Write* m, const char* appName, 204| int verNum ) 205|{ 206| IniFile_Write_putVar( m, "Application", "s", appName ); 207| IniFile_Write_putVar( m, "Version", "i", verNum ); 208|} 209| 210|/*********************************************************************** 211|* 10. <<< [IniFile_Write_putMultiStrV] 複数の文字列を複数行で出力する >>> 212|*【引数】 213|* ・char* attr_name; 属性名 214|* ・StrV_Set* strs; 複数の文字列 215|*【補足】 216|*・ファイルには、以下のように同じ属性が並びます。 217|* attr = string of number 1 218|* attr = string of number 2 219|* attr = string of number 3 220|************************************************************************/ 221|#ifdef USES_STRV 222|void IniFile_Write_putMultiStrV( IniFile_Write* m, const char* attr_name, 223| StrV_Set* strs ) 224|{ 225| StrV_SetP sp; 226| 227| for ( StrV_Set_forEach( strs, &sp ) ) { 228| fprintf( m->file, "%s = %s\n", attr_name, sp.p ); 229| } 230|} 231|#endif 232| 233| 234|/*********************************************************************** 235|* 11. <<< [IniFile_Write_putMultiStrVM] 複数の文字列を複数行で出力する >>> 236|*【引数】 237|* ・char* attr_name; 属性名 238|* ・StrV_Mem* strs; 複数の文字列 239|*【補足】 240|*・ファイルには、以下のように同じ属性が並びます。 241|* attr = string of number 1 242|* attr = string of number 2 243|* attr = string of number 3 244|************************************************************************/ 245|#ifdef USES_STRV 246|void IniFile_Write_putMultiStrVM( IniFile_Write* m, const char* attr_name, 247| StrV_Mem* strs ) 248|{ 249| StrV_SetP sp; 250| 251| for ( StrV_Mem_forEach( strs, &sp ) ) { 252| fprintf( m->file, "%s = %s\n", attr_name, sp.p ); 253| } 254|} 255|#endif 256| 257| 258|/*********************************************************************** 259|* 12. <<< [IniFile_Write_putMultiStrAV] 複数の文字列を複数行で出力する >>> 260|*【引数】 261|* ・char* attr_name; 属性名 262|* ・ArrX_Able* strs; 複数の文字列(要素は StrV_AbleElem 型) 263|*【補足】 264|*・ファイルには、以下のように同じ属性が並びます。 265|* attr = string of number 1 266|* attr = string of number 2 267|* attr = string of number 3 268|************************************************************************/ 269|#ifdef USES_STRV 270|void IniFile_Write_putMultiStrAV( IniFile_Write* m, const char* attr_name, 271| ArrX_Able* strs ) 272|{ 273| StrV_AbleElem* sv; 274| 275| for ( ArrX_Able_forEach( strs, &sv, StrV_AbleElem ) ) { 276| fprintf( m->file, "%s = %s\n", attr_name, sv->s ); 277| } 278|} 279|#endif 280| 281| 282|/*********************************************************************** 283|* 13. <<< [IniFile_Write_putPathes] ファイルパスの集合を出力する >>> 284|*【引数】 285|* ・char* section_name; セクション名 286|* ・char** pathes; ファイルパスの集合の先頭アドレス 287|* ・int nPath; ファイルパスの数 288|*【補足】 289|*・ファイルパスの集合は、1つのセクションを占有します。 290|*・次の出力は、セクションの出力から始めてください。 291|*【例】 292|*・出力したデータは、IniFile_Read_getPathes 関数から入力することができます。 293|************************************************************************/ 294|void IniFile_Write_putPathes( IniFile_Write* m, const char* section_name, 295| char** pathes, int nPath ) 296|{ 297| int i; 298| static char prevFolder[_MAX_PATH]; 299| static char s[_MAX_PATH]; 300| 301| IniFile_Write_putSection( m, section_name ); 302| 303| for ( i = 0; i < nPath; i++ ) { 304| 305| /* フォルダ・パスを出力する */ 306| ASSERT( strlen( *pathes ) < _MAX_PATH ); 307| strcpy( s, *pathes ); 308| StrX_cutFName( s ); 309| if ( s[0] == '\0' ) strcpy( s, "." ); 310| if ( i == 0 || strcmp( s, prevFolder ) != 0 ) { 311| IniFile_Write_putVar( m, "Folder", "s", s ); 312| strcpy( prevFolder, s ); 313| } 314| 315| /* ファイル名を出力する */ 316| StrX_cpyFName( s, *pathes ); 317| IniFile_Write_putVar( m, "File", "s", s ); 318| 319| pathes ++; 320| } 321|} 322| 323| 324| 325|/*---------------------------------------------------------*/ 326|/* 14. <<<◆初期化ファイル・読み込みツール [IniFile_Read] >>> */ 327|/*---------------------------------------------------------*/ 328| 329| 330| 331| 332|/*********************************************************************** 333|* 15. <<< [IniFile_Read_init] 初期化する・ファイルを開く >>> 334|************************************************************************/ 335|void IniFile_Read_init( IniFile_Read* m, const char* fname, 336| char* lineBuf, int lineBuf_sizeof ) 337|{ 338| m->file = FileX_open( fname, "rt" ); 339| if ( m->file == NULL ) { 340| error2_1( FileX_Err_CannotReadOpen, 341| "読みこみモードで open できません。%s", fname ); 342| } 343| m->lineBuf = lineBuf; 344| m->lineBuf_sizeof = lineBuf_sizeof; 345| m->string_sizeof = 256; 346| strcpy( m->path, fname ); 347| 348| ERRORS_FINISHCHK_FOR_INIT( IniFile_Read_finish ); 349|} 350| 351| 352| 353|/*********************************************************************** 354|* 16. <<< [IniFile_Read_setStringSize] 文字列を読み込むときの最大サイズ >>> 355|*【機能】 356|*・IniFile_Read_getVar で文字列型を読み込むときに指定するバッファの 357|* サイズを指定します。 358|************************************************************************/ 359|void IniFile_Read_setStringSize( IniFile_Read* m, int size ) 360|{ 361| m->string_sizeof = size; 362|} 363| 364| 365| 366|/*********************************************************************** 367|* 17. <<< [IniFile_Read_finish] 後始末する・ファイルを閉じる >>> 368|************************************************************************/ 369|void IniFile_Read_finish( IniFile_Read* m ) 370|{ 371| ERRORS_FINISHCHK_FOR_FINISH( IniFile_Read_finish ); 372| 373| fclose( m->file ); 374|} 375| 376| 377| 378|/*********************************************************************** 379|* 18. <<< [IniFile_Read_setSection] セクションを選択する >>> 380|*【補足】 381|*・次のセクションが指定の名前と異なるときは、IniFile_NotFoundSection エラー 382|* になります。 383|*・ファイルの最後まで読んだら FileX_Err_EOF エラーになります。 384|************************************************************************/ 385|void IniFile_Read_setSection( IniFile_Read* m, const char* section ) 386|{ 387| char* buf = m->lineBuf; 388| char* p; 389| long pos = ftell( m->file ); 390| 391| /* 空行を飛ばして、セクションを読み込む */ 392| do { 393| fgets( buf, m->lineBuf_sizeof, m->file ); 394| StrX_trim( buf ); 395| 396| if ( feof( m->file ) ) { 397| error2_2( FileX_Err_EOF, "EOF in IniFile_Read_setSection %s [%s]", 398| m->path, section ); 399| } 400| } while ( buf[0] == '\0' ); 401| 402| /* フォーマットのチェック */ 403| p = strchr( buf, ']' ); 404| if ( buf[0] != '[' || p == NULL ) { 405| error2_2( IniFile_Err_BadFormat, 406| "フォーマットがおかしい in IniFile_Read_setSection %s [%s]", 407| m->path, section ); 408| } 409| *p = '\0'; 410| 411| /* セクション名のチェック */ 412| if ( stricmp( section, buf + 1 ) != 0 ) { 413| fseek( m->file, pos, SEEK_SET ); 414| error2_2( IniFile_NotFoundSection, 415| "セクション名が期待したものと異なる %s [%s]", m->path, section ); 416| } 417|} 418| 419| 420| 421|/*********************************************************************** 422|* 19. <<< [IniFile_Read_reset] ファイルポインタを先頭に戻す >>> 423|*【補足】 424|*・section に一致するセクションが無い場合は IniFile_NotFoundSection エラー 425|* になり、ファイルポインタは末尾に移動します。 426|************************************************************************/ 427|void IniFile_Read_reset( IniFile_Read* m ) 428|{ 429| rewind( m->file ); 430|} 431| 432| 433| 434|/*********************************************************************** 435|* 20. <<< [IniFile_Read_searchSection] セクションを検索する >>> 436|*【引数】 437|* ・char* section; 検索するセクション名 438|* ・bool upward; 上方にも検索するかどうか 439|* ・long 返り値; 見つかったセクション中の先頭の属性のファイルアドレス 440|*【補足】 441|*・section に一致するセクションが無い場合は IniFile_NotFoundSection エラー 442|* になり、ファイルポインタは末尾に移動します。 443|************************************************************************/ 444|long IniFile_Read_searchSection( IniFile_Read* m, const char* section, 445| bool upward ) 446|{ 447| char* buf = m->lineBuf; 448| char* p; 449| int eof_count = 0; 450| 451| for (;;) { 452| 453| /* 1行読み込む */ 454| fgets( buf, m->lineBuf_sizeof, m->file ); 455| if ( buf[strlen(buf)-1] == '\n' ) 456| buf[strlen(buf)-1] = '\0'; 457| 458| /* 1回目の EOF なら、ファイルの先頭へ、2回目なら例外 */ 459| if ( feof( m->file ) ) { 460| eof_count ++; 461| if ( eof_count >= 2 || ! upward ) { 462| error2_1( IniFile_NotFoundSection, 463| "セクション %s が見つかりません", section ); 464| } 465| rewind( m->file ); 466| } 467| 468| /* セクション名が一致するか判定する */ 469| if ( buf[0] == '[' ) { 470| p = strchr( buf, ']' ); 471| if ( p != NULL ) { 472| *p = '\0'; 473| if ( strcmp( section, buf + 1 ) == 0 ) 474| return ftell( m->file ); 475| } 476| } 477| } 478|} 479| 480| 481| 482|/*********************************************************************** 483|* 21. <<< [IniFile_Read_searchSection2] 第一属性が一致するセクションを検索する >>> 484|*【引数】 485|* ・char* section; 検索するセクション名 486|* ・char* attr; 第一属性名 487|* ・char* type; 第一属性のタイプ 488|* ・... 第一属性の値と比較する値 489|* ・long 返り値; 見つかったセクション中の先頭の属性のファイルアドレス 490|************************************************************************/ 491|#ifdef USES_BIGSTACK 492|void IniFile_Read_searchSection2( IniFile_Read* m, const char* section, 493| const char* attr, const char* type, ... ) 494|{ 495| void* var; 496| va_list va; 497| void* p; 498| int i; 499| bool b; 500| 501| BigStack_start(); 502| c_try { 503| switch ( *type ) { 504| case 's': 505| var = BigStack_alloc( m->string_sizeof + 1 ); 506| va_start( va, type ); 507| p = va_arg( va, void* ); 508| va_end( va ); 509| do { 510| IniFile_Read_searchSection( m, section, true ); 511| IniFile_Read_getVar( m, attr, type, var ); 512| } while ( strcmp( var, p ) != 0 ); 513| break; 514| case 'i': 515| var = BigStack_alloc( sizeof(int) ); 516| va_start( va, type ); 517| i = va_arg( va, int ); 518| va_end( va ); 519| do { 520| IniFile_Read_searchSection( m, section, true ); 521| IniFile_Read_getVar( m, attr, type, var ); 522| } while ( *(int*)var != i ); 523| break; 524| case 'b': 525| var = BigStack_alloc( sizeof(bool) ); 526| va_start( va, type ); 527| b = va_arg( va, bool ); 528| va_end( va ); 529| do { 530| IniFile_Read_searchSection( m, section, true ); 531| IniFile_Read_getVar( m, attr, type, var ); 532| } while ( *(bool*)var != b ); 533| break; 534| } 535| } 536| c_finally { 537| BigStack_end(); 538| } c_end_finally; 539|} 540|#endif /* USES_BIGSTACK */ 541| 542| 543| 544| 545|/* 22. <<< -------- 属性値の入力 -------- >>> */ 546| 547| 548| 549|/*********************************************************************** 550|* 23. <<< [IniFile_Read_getCount] 同じ属性名の数を数える >>> 551|************************************************************************/ 552|int IniFile_Read_getCount( IniFile_Read* m, const char* attr_name ) 553|{ 554| int count = 0; 555| long pos; 556| char* buf = m->lineBuf; 557| char* p; 558| char c; 559| 560| pos = ftell( m->file ); 561| 562| for (;;) { 563| if ( fgets( buf, m->lineBuf_sizeof, m->file ) == NULL ) break; 564| while ( *buf == ' ' || *buf == '\t' ) { 565| if ( *buf == '\0' ) break; 566| buf++; 567| } 568| p = &buf[strlen(attr_name)]; 569| c = *p; 570| if ( c != ' ' && c != '=' && c != ':' ) break; 571| *p = '\0'; 572| if ( stricmp( buf, attr_name ) != 0 ) break; 573| count ++; 574| } 575| 576| fseek( m->file, pos, SEEK_SET ); 577| return count; 578|} 579| 580| 581| 582|/*********************************************************************** 583|* 24. <<< [IniFile_Read_getVar] 属性値を入力する >>> 584|*【引数】 585|* ・char* attr_name; 属性名 586|* ・char* types; 型リスト 587|* ・... 属性の値を格納するアドレスを並べたもの 588|* ・long 返り値; この属性行の先頭のファイルアドレス 589|*【補足】 590|*・types には、以下の型指定文字を並べた文字列を指定します。 591|* ・'s'or'S' 文字列型(char*型、引数の型は char*) 592|* ・'i' 整数型(int型、引数の型は int*) 593|* ・'b' 論理型(bool型、引数の型は bool*) 594|* ・'t' 日時型(time_t*型、引数の型は time_t*) 595|* ・'-' 属性値を無視(格納する変数を指定しない) 596|*・属性名が違っていると、例外を投げます。 597|*・'S' にして初期化ファイル中の属性値が省略されている場合、なにも値を格納しません。 598|* つまり、この関数を呼ぶ前にデフォルト値を入れておくことが出来ます。 599|*【内部補足】 600|*・行頭または空行の行頭にしてから、呼び出します。 601|*・この関数から返ったとき、ファイルポインタは、属生行の次に移動しています。 602|*【例】 603|*・attr = 1, string, 2 という属性値を入力する場合、 604|* scanf と同様に、以下のように記述します。 605|* IniFile_Read_getVar( file, "attr", "isi", &i1, s, &i2 ); 606|************************************************************************/ 607|long IniFile_Read_getVar( IniFile_Read* m, const char* attr_name, 608| const char* types, ... ) 609|{ 610| long pos; 611| char* buf; 612| va_list va; 613| 614| pos = ftell( m->file ); 615| 616| /* 属性名をチェックする */ 617| buf = IniFile_Read_readAttrName( m, attr_name ); 618| 619| /* 値を読み込む */ 620| va_start( va, types ); 621| IniFile_Read_readVar( m, buf, types, va ); 622| va_end( va ); 623| 624| return pos; 625|} 626| 627| 628| 629|/*********************************************************************** 630|* 25. <<< [IniFile_Read_getNextCount] 全属性の数を返す >>> 631|*【補足】 632|*・現在のファイルポインタの位置から次のセクションまで、またはファイルの終了 633|* までの属性の数を返します。 634|************************************************************************/ 635|int IniFile_Read_getNextCount( IniFile_Read* m ) 636|{ 637| int count = 0; 638| long pos; 639| char* buf = m->lineBuf; 640| 641| pos = ftell( m->file ); 642| 643| for (;;) { 644| fgets( buf, m->lineBuf_sizeof, m->file ); 645| if ( feof( m->file ) ) break; 646| 647| if ( buf[strlen(buf)-1] == '\n' ) 648| buf[strlen(buf)-1] = '\0'; 649| StrX_trim( buf ); 650| 651| if ( ! StrX_isSpaceStr( buf ) ) { 652| if ( buf[0] == '[' ) break; 653| count ++; 654| } 655| } 656| 657| fseek( m->file, pos, SEEK_SET ); 658| return count; 659|} 660| 661| 662|/*********************************************************************** 663|* 26. <<< [IniFile_Read_getNextVar] 次の属性名と属性値を入力する >>> 664|*【引数】 665|* ・char* attr_name; 属性名を格納するアドレス(出力) 666|* ・char* types; 型リスト 667|* ・... 属性の値を格納するアドレスを並べたもの(出力) 668|* ・long 返り値; この属性行の先頭のファイルアドレス, -1L=次は無い 669|*【補足】 670|*・次の属性が無い場合(次の行は、次のセクションの場合)、-1L を返します。 671|************************************************************************/ 672|long IniFile_Read_getNextVar( IniFile_Read* m, char* attr_name, 673| const char* types, ... ) 674|{ 675| long pos; 676| char* buf = m->lineBuf; 677| char* p; 678| va_list va; 679| 680| pos = ftell( m->file ); 681| 682| /* 空行を飛ばして、属性行を読み込む */ 683| do { 684| fgets( buf, m->lineBuf_sizeof, m->file ); 685| if ( feof( m->file ) ) 686| return -1L; 687| 688| if ( buf[strlen(buf)-1] == '\n' ) 689| buf[strlen(buf)-1] = '\0'; 690| StrX_trim( buf ); 691| } while ( StrX_isSpaceStr( buf ) ); 692| 693| /* セクションの区切りに来たら、NULL を返す */ 694| if ( buf[0] == '[' ) { 695| fseek( m->file, pos, SEEK_SET ); 696| return -1L; 697| } 698| 699| /* 属性名を取得する */ 700| p = strchr( buf, '=' ); 701| if ( p != NULL ) *p = '\0'; 702| StrX_trim( buf ); 703| strcpy( attr_name, buf ); 704| 705| /* 値を読み込む */ 706| if ( p == NULL ) p = strchr( buf, '\0' ); 707| else p = p + 1; 708| va_start( va, types ); 709| IniFile_Read_readVar( m, p, types, va ); 710| va_end( va ); 711| 712| return pos; 713|} 714| 715| 716|/*********************************************************************** 717|* 27. <<< [IniFile_Read_getVarByPos] ファイルアドレスから属性値を入力する >>> 718|*【引数】 719|* ・long pos; ファイルアドレス 720|* ・char* types; 型リスト(IniFile_Read_getVar 関数を参照) 721|* ・... 属性の値を格納するアドレスを並べたもの 722|************************************************************************/ 723|void IniFile_Read_getVarByPos( IniFile_Read* m, long pos, 724| const char* types, ... ) 725|{ 726| va_list va; 727| char* buf = m->lineBuf; 728| char* p; 729| 730| fseek( m->file, pos, SEEK_SET ); 731| 732| /* イコールまでスキップする */ 733| for(;;) { 734| fgets( buf, m->lineBuf_sizeof, m->file ); 735| p = buf; 736| while ( *p != '\0' ) { 737| if ( *p == '=' ) 738| goto exit_for; 739| p++; 740| } 741| } 742|exit_for: 743| 744| /* 値の先頭までスキップする */ 745| p++; 746| while ( *p == ' ' ) p++; 747| StrX_trim( p ); 748| 749| /* 値を読み込む */ 750| va_start( va, types ); 751| IniFile_Read_readVar( m, p, types, va ); 752| va_end( va ); 753|} 754| 755| 756| 757|/*********************************************************************** 758|* 28. <<< [IniFile_Read_getPlusVar] 属性値を入力する(追加用)>>> 759|*【補足】 760|*・バージョンアップにより属性を追加した場合に容易に対応するための 761|* IniFile_Read_getVar 関数です。 762|*・格納する変数列の後に、デフォルト値を以下のように指定します。 763|* IniFile_Read_getVar( file, "attr", "isi", &i1, s, &i2, 10, "abc", 5 ); 764|*・なるべく、この関数を使わずに、バージョン番号によって読み込むルーチンを 765|* 変えるようにしてください。 766|************************************************************************/ 767|void IniFile_Read_getPlusVar( IniFile_Read* m, const char* attr_name, 768| const char* types, ... ) 769|{ 770| char* buf; 771| va_list va; 772| int* i; 773| char* s; 774| bool* b; 775| 776| // ASSERT( strlen(types) <= 1 ); /*未対応*/ 777| 778| /* 属性値を入力する */ 779| if ( IniFile_Read_getCount( m, attr_name ) > 0 ) { 780| 781| /* 属性名をチェックする */ 782| buf = IniFile_Read_readAttrName( m, attr_name ); 783| 784| /* 値を読み込む */ 785| va_start( va, types ); 786| IniFile_Read_readVar( m, buf, types, va ); 787| va_end( va ); 788| } 789| 790| /* デフォルト値を格納する */ 791| else { 792| va_start( va, types ); 793| switch ( *types ) { 794| case 'i': 795| i = va_arg( va, int* ); 796| *i = va_arg( va, int ); 797| break; 798| case 'b': 799| b = va_arg( va, bool* ); 800| *b = va_arg( va, bool ); 801| break; 802| case 's': 803| s = va_arg( va, char* ); 804| strcpy( s, va_arg( va, char* ) ); 805| break; 806| } 807| va_end( va ); 808| } 809|} 810| 811|/************************************************************************** 812|* 29. <<< [IniFile_Read_checkTypeInfo] ファイルのバージョンを読みこんでチェックする >>> 813|*【引数】 814|*・int verNum_start; アプリが対応しているバージョンの最小値(整数) 815|*・int verNum_end; アプリが対応しているバージョンの最大値(整数) 816|*【補足】 817|*・IniFile_Write_putTypeInfo で出力したデータをチェックします。 818|*・エラーが発生したら内部で、error2_2 を呼び出しています。 819|* エラーコードは、IniFile_Err_OtherApp か IniFile_Err_OtherVer です。 820|***************************************************************************/ 821|void IniFile_Read_checkTypeInfo( IniFile_Read* m, const char* appName, 822| int verNum_start, int verNum_end ) 823|{ 824| int n; 825| char s[256]; 826| 827| IniFile_Read_getVar( m, "Application", "s", s ); 828| if ( strcmp( s, appName ) != 0 ) { 829| error2_2( IniFile_Err_OtherApp, "アプリケーションが異なります (file:%s, app:%s)", 830| s, appName ); 831| } 832| IniFile_Read_getVar( m, "Version", "i", &n ); 833| if ( n < verNum_start || n > verNum_end ) { 834| error2_3( IniFile_Err_OtherVer, "アプリが対応していない、新しいバージョンのファイルです" 835| " (file:%d, app:%d〜%d)", n, verNum_start, verNum_end ); 836| } 837|} 838| 839|/*********************************************************************** 840|* 30. <<< [IniFile_Read_getVar2] 任意数の属性値を入力する >>> 841|*【引数】 842|* ・StrX_Mem* mem; 文字列を格納する領域 →補足 843|* ・char* attr_name; 属性名 844|* ・char* types; 型リスト 845|* ・... 属性の値を格納するアドレスを並べたもの 846|* ・long 返り値; この属性行の先頭のファイルアドレス 847|*【補足】 848|*・types に文字列型を指定しなければ、mem には NULL を指定できます。 849|*・types には、以下の型指定文字を並べた文字列を指定します。 850|* ・'s' 文字列型(char* 型、引数の型は char**) 851|* ・'i' 整数型(int型、引数の型は int*) 852|* ・'b' 論理型(bool型、引数の型は bool*) 853|* ・'*s' 文字列配列型(引数の型は ArrX_Buf* と ArrX*)(→[*1]) 854|* ・'*i' 整数配列型(引数の型は ArrX_Buf* と ArrX*) 855|* ・'-' 属性値を無視(格納する変数を指定しない) 856|*・[*1] types=="*s" の場合、IniFile_Read_getVar2s 関数が便利です。 857|*・属性名が違っていると、例外を投げます。 858|*・配列には、ArrX_Buf が用意する限り、任意の要素数の要素を格納することが 859|* できます。 860|*・属性値が省略された場合、文字列型では NULL が格納され、 861|* 整数型では何も値を格納しません。数値型では、この関数を呼ぶ前に 862|* デフォルト値を入れておくことが出来ます。 863|*【内部補足】 864|*・行頭または空行の行頭にしてから、呼び出します。 865|*・この関数から返ったとき、ファイルポインタは、属生行の次に移動しています。 866|*【例】 867|*・attr = 1, string, 2 という属性値を入力する場合、 868|* scanf と同様に、以下のように記述します。 869|* ただし、文字列は、char** 型を指定することに注意してください 870|* IniFile_Read_getVar2( file, mem, "attr", "isi", &i1, &s, &i2 ); 871|*・attr = 1, 2, 4, 6 という属性値を配列に入力する場合、 872|* 以下のように記述します。 873|* IniFile_Read_getVar2( file, mem, "attr", "*i", buf, arr ); 874|* ただし、arr のメモリ領域を buf から確保します。 875|* ・ArrX_Buf* buf; 配列の領域(初期化済みを指定) 876|* ・ArrX* arr; 配列(未初期化状態のを指定) 877|*・attr = 1, abc, def, ghi という属性値のうち、2列目(abc)以降を 878|+ を配列に入力する場合、以下のように記述します。 879|* IniFile_Read_getVar2( file, mem, "attr", "i*s", &i, buf, arr ); 880|************************************************************************/ 881|#ifdef USES_STRX 882|long IniFile_Read_getVar2( IniFile_Read* m, StrX_Mem* mem, 883| const char* attr_name, const char* types, ... ) 884|{ 885| long pos; 886| char* buf; 887| va_list va; 888| 889| pos = ftell( m->file ); 890| 891| /* 属性名をチェックする */ 892| buf = IniFile_Read_readAttrName( m, attr_name ); 893| 894| /* 値を読み込む */ 895| va_start( va, types ); 896| IniFile_Read_readVar2( m, buf, mem, types, va ); 897| va_end( va ); 898| 899| return pos; 900|} 901|#endif 902| 903| 904|/*********************************************************************** 905|* 31. <<< [IniFile_Read_getVar2s] 任意数の文字列型属性値を入力する(StrX_Mem) >>> 906|*【引数】 907|* ・StrX_Mem* mem; 文字列を格納する領域 →補足 908|* ・char* attr_name; 属性名 909|* ・StrX_Set* set; 入力した文字列(複数)を格納する集合(出力) 910|* ・long 返り値; この属性行の先頭のファイルアドレス 911|************************************************************************/ 912|#ifdef USES_STRX 913|long IniFile_Read_getVar2s( IniFile_Read* m, StrX_Mem* mem, 914| const char* attr_name, StrX_Set* set ) 915|{ 916| long ret; 917| 918| StrX_Set_init1( set, mem ); 919| ret = IniFile_Read_getVar2( m, mem, attr_name, "*s", NULL, NULL ); 920| StrX_Set_init2( set, mem ); 921| 922| return ret; 923|} 924|#endif 925| 926| 927| 928|/*********************************************************************** 929|* 32. <<< [IniFile_Read_getVar2sv] 任意数の文字列型属性値を入力する(StrV_Mem) >>> 930|*【引数】 931|* ・StrV_Mem* mem; 文字列を格納する領域 →補足 932|* ・char* attr_name; 属性名 933|* ・StrV_Set* set; 入力した文字列(複数)を格納する集合(出力) 934|* ・long 返り値; この属性行の先頭のファイルアドレス 935|************************************************************************/ 936|#ifdef USES_ARRX 937|#ifdef USES_STRV 938|void IniFile_Read_getVar2sv( IniFile_Read* m, StrV_Mem* mem, 939| const char* attr_name, StrV_Set* set ) 940|{ 941| char* vars; 942| char* nextVar; 943| 944| StrV_Set_init1( set, mem ); 945| vars = IniFile_Read_readAttrName( m, attr_name ); 946| StrV_Mem_setMax( mem, m->string_sizeof ); 947| 948| for (;;) { 949| 950| nextVar = StrX_meltCSV( vars, vars ); 951| strcpy( StrV_Mem_alloc( mem ), vars ); 952| 953| if ( nextVar == NULL ) break; 954| 955| /* 次の値を格納する準備をする */ 956| vars = nextVar; 957| while ( *vars == ' ' ) vars ++; 958| } 959| StrV_Set_init2( set, mem ); 960|} 961|#endif 962|#endif 963| 964| 965| 966|/*********************************************************************** 967|* 33. <<< [IniFile_Read_getVar2av] StrV_AbleElem 型の文字列を入力する >>> 968|*【引数】 969|* ・char* attr_name; 属性名 970|* ・ArrX_Able* set; 入力した文字列を格納する StrV_AbleElem 型構造体の集合 971|*【補足】 972|*・set の無効になっている要素に追加します。 973|************************************************************************/ 974|#ifdef USES_ARRX 975|#ifdef USES_STRV 976|void IniFile_Read_getVar2av( IniFile_Read* m, const char* attr_name, 977| ArrX_Able* set ) 978|{ 979| char* vars; 980| char* nextVar; 981| StrV_AbleElem* s; 982| 983| vars = IniFile_Read_readAttrName( m, attr_name ); 984| 985| for (;;) { 986| 987| nextVar = StrX_meltCSV( vars, vars ); 988| s = ArrX_Able_getFirstDisabled( set, StrV_AbleElem ); 989| StrV_cpy( &s->s, vars ); 990| 991| if ( nextVar == NULL ) break; 992| 993| /* 次の値を格納する準備をする */ 994| vars = nextVar; 995| while ( *vars == ' ' ) vars ++; 996| } 997|} 998|#endif 999|#endif 1000| 1001|/*********************************************************************** 1002|* 34. <<< [IniFile_Read_getPlusVar2] 任意数の属性値を入力する(追加用)>>> 1003|*【機能】 1004|*・StrX_Mem を指定する IniFile_Read_getPlusVar 関数です。 1005|*【補足】 1006|*・もし、文字列のデフォルト値を入力する場合、StrX_Mem を使用しないで、 1007|* 指定したデフォルト文字列を参照するようにします。もし、デフォルト文字列 1008|* がリテラル(文字列定数)でない場合、注意してください。 1009|************************************************************************/ 1010|#ifdef USES_STRX 1011|void IniFile_Read_getPlusVar2( IniFile_Read* m, StrX_Mem* mem, 1012| const char* attr_name, const char* types, ... ) 1013|{ 1014| char* buf; 1015| va_list va; 1016| int* i; 1017| char** s; 1018| bool* b; 1019| 1020| ASSERT( strlen(types) == 1 ); /*未対応*/ 1021| 1022| /* 属性値を入力する */ 1023| if ( IniFile_Read_getCount( m, attr_name ) > 0 ) { 1024| 1025| /* 属性名をチェックする */ 1026| buf = IniFile_Read_readAttrName( m, attr_name ); 1027| 1028| /* 値を読み込む */ 1029| va_start( va, types ); 1030| IniFile_Read_readVar2( m, buf, mem, types, va ); 1031| va_end( va ); 1032| } 1033| 1034| /* デフォルト値を格納する */ 1035| else { 1036| va_start( va, types ); 1037| switch ( *types ) { 1038| case 'i': 1039| i = va_arg( va, int* ); 1040| *i = va_arg( va, int ); 1041| break; 1042| case 'b': 1043| b = va_arg( va, bool* ); 1044| *b = va_arg( va, bool ); 1045| break; 1046| case 's': 1047| s = va_arg( va, char** ); 1048| *s = va_arg( va, char* ); /* 参照する */ 1049| break; 1050| } 1051| va_end( va ); 1052| } 1053|} 1054|#endif 1055| 1056| 1057| 1058|/*********************************************************************** 1059|* 35. <<< [IniFile_Read_getVars] 同じ属性名の構造体を連続入力する >>> 1060|*【引数】 1061|* ・StrX_Mem* mem; 文字列を格納する領域 1062|* ・ArrX_Buf* pmem; 構造体を格納する領域 1063|* ・char* attr_name; 属性名 1064|* ・char* types; 型リスト 1065|* ・ArrX* arr; 構造体配列(出力) 1066|*【補足】 1067|*・型リストに関しては、IniFile_Read_getVar2 関数を参照。 1068|*・たとえば、types="isi" なら、以下の構造体の配列を arr に格納します。 1069|* struct { int p1; char* p2; int p3; }; 1070|* ファイルでは次のような形になります。 1071|* Struct = 1, abc, 11 1072|* Struct = 2, efg, 22 1073|* : : 1074|* ただし、構造体の領域は pmem、文字列の領域は mem を使用します。 1075|*・行を配列、列を配列要素とみなす場合、IniFile_Read_getVar2 を使います。 1076|*・型リストに指定する要素が1つの場合、構造体でなく基本型で構いません。 1077|* たとえば、types="i" なら、ArrX は、int 型の配列になります。 1078|*・arr == NULL の場合、pmem に格納するだけです。 1079|************************************************************************/ 1080|#ifdef USES_ARRX 1081|#ifdef USES_STRX 1082|void IniFile_Read_getVars( IniFile_Read* m, StrX_Mem* mem, ArrX_Buf* pmem, 1083| const char* attr_name, const char* types, ArrX* arr ) 1084|{ 1085| int i,n; 1086| int* pp_first; /* 最初の構造体へのポインタ */ 1087| int* pp; /* 現在の構造体へのポインタ */ 1088| char* buf; /* 行バッファ中の現在の値の位置 */ 1089| char* nextBuf; /* 次の buf */ 1090| const char* t; /* types のポインタ */ 1091| 1092| ASSERT( sizeof(int) == sizeof(char*) ); 1093| 1094| n = IniFile_Read_getCount( m, attr_name ); 1095| pp_first = ArrX_Buf_allocs( pmem, int, n * strlen( types ) ); 1096| pp = pp_first; 1097| for ( i = 0; i < n; i++ ) { 1098| t = types; 1099| buf = IniFile_Read_readAttrName( m, attr_name ); 1100| if ( *t != '\0' ) { 1101| for (;;) { 1102| 1103| /* 値の文字列を作る */ 1104| nextBuf = StrX_meltCSV( buf, buf ); 1105| 1106| /* それぞれの型の値を読み込む */ 1107| switch ( *t ) { 1108| case 's': 1109| if ( (int)strlen( buf ) > m->string_sizeof - 1 ) 1110| buf[m->string_sizeof - 1] = '\0'; 1111| *pp = (int)StrX_Mem_alloc( mem ); 1112| strcpy( (char*)*pp, buf ); 1113| break; 1114| case 'i': 1115| *pp = atoi( buf ); 1116| break; 1117| #ifdef USES_TIMEDATE 1118| case 't': 1119| TimeDate_loadStr( pp, buf ); 1120| break; 1121| #endif 1122| default: 1123| Errors_notSupport(); 1124| } 1125| pp ++; 1126| t ++; 1127| if ( *t == '\0' ) 1128| break; 1129| 1130| if ( nextBuf == NULL ) { 1131| error2_1( IniFile_Err_FewData, 1132| "%s 属性のデータのが少ない", attr_name ); 1133| } 1134| buf = nextBuf + 1; 1135| while ( *buf == ' ' ) buf ++; 1136| } 1137| } 1138| } 1139| if ( arr != NULL ) 1140| ArrX_init2( arr, pp_first, pp ); 1141|} 1142|#endif 1143|#endif /* USES_ARRX */ 1144| 1145| 1146| 1147|/*********************************************************************** 1148|* 36. <<< [IniFile_Read_getVars2] 同じ属性名の構造体を連続入力する2 >>> 1149|*【引数】 1150|* ・StrX_Mem* mem; 文字列を格納する領域 1151|* ・ArrX_Buf* pmem; 構造体を格納する領域 1152|* ・char* attr_name; 属性名 1153|* ・char* types; 型リスト 1154|* ・ArrX* arr; 構造体配列(出力),または NULL 1155|* ・int size; 1つの構造体のメモリサイズ 1156|* ・... オフセット値(Offset型)の羅列 1157|*【補足】 1158|*・IniFile_Read_getVars との違いは、構造体メンバへの格納先を任意に 1159|* 指定できることです。 1160|*・たとえば、types="si" で、以下の構造体(の配列)に格納する場合、 1161|* ... の引数は次のように指定します。 1162|* struct { int p1; char* p2; int p3; }; 1163|* 引数= Offset_init2(s,p2), Offset_init2(s,p3) 1164|* ただし s は、構造体への任意のポインタとする。 1165|*・arr == NULL の場合、pmem に格納するだけです。 1166|************************************************************************/ 1167|#ifdef USES_ARRX 1168|#ifdef USES_STRX 1169|#ifdef USES_OFFSET 1170|void IniFile_Read_getVars2( IniFile_Read* m, StrX_Mem* mem, ArrX_Buf* pmem, 1171| const char* attr_name, const char* types, ArrX* arr, int size, ... ) 1172|{ 1173| va_list va; 1174| int i,n; 1175| char* pp_first; /* 最初の構造体へのポインタ */ 1176| char* pp; /* 現在の構造体へのポインタ */ 1177| char* pp2; /* 構造体のメンバ変数へのポインタ */ 1178| char* buf; /* 行バッファ中の現在の値の位置 */ 1179| char* nextBuf; /* 次の buf */ 1180| const char* t; /* types のポインタ */ 1181| 1182| ASSERT( sizeof(int) == sizeof(char*) ); 1183| 1184| n = IniFile_Read_getCount( m, attr_name ); 1185| pp_first = ArrX_Buf_allocs( pmem, char, n * size ); 1186| pp = pp_first; 1187| for ( i = 0; i < n; i++ ) { 1188| t = types; 1189| buf = IniFile_Read_readAttrName( m, attr_name ); 1190| va_start( va, size ); 1191| if ( *t != '\0' ) { 1192| for (;;) { 1193| 1194| /* 値の文字列を作る */ 1195| nextBuf = StrX_meltCSV( buf, buf ); 1196| 1197| /* オフセット */ 1198| pp2 = &Offset_ref( va_arg(va,int), pp, char ); 1199| 1200| /* それぞれの型の値を読み込む */ 1201| switch ( *t ) { 1202| case 's': 1203| if ( (int)strlen( buf ) > m->string_sizeof - 1 ) 1204| buf[m->string_sizeof - 1] = '\0'; 1205| *(char**)pp2 = StrX_Mem_alloc( mem ); 1206| strcpy( *(char**)pp2, buf ); 1207| break; 1208| case 'i': 1209| *(int*)pp2 = atoi( buf ); 1210| break; 1211| #ifdef USES_TIMEDATE 1212| case 't': 1213| TimeDate_loadStr( (time_t*)pp2, buf ); 1214| break; 1215| #endif 1216| } 1217| t ++; 1218| if ( *t == '\0' ) 1219| break; 1220| 1221| if ( nextBuf == NULL ) { 1222| error2_1( IniFile_Err_FewData, 1223| "%s 属性のデータのが少ない", attr_name ); 1224| } 1225| buf = nextBuf + 1; 1226| while ( *buf == ' ' ) buf ++; 1227| } 1228| } 1229| pp += size; 1230| va_end( va ); 1231| } 1232| if ( arr != NULL ) 1233| ArrX_init2( arr, pp_first, pp ); 1234|} 1235|#endif /* USES_OFFSET */ 1236|#endif 1237|#endif /* USES_ARRX */ 1238| 1239| 1240| 1241|/*********************************************************************** 1242|* 37. <<< [IniFile_Read_getMultiLine] 複数行を入力する >>> 1243|*【引数】 1244|* ・char* attr_name; 属性名 1245|* ・char* buf; 複数行バッファ 1246|* ・int buf_sizeof; buf の領域のサイズ 1247|* ・char* retStr; 改行文字("\r\n"や"\n") 1248|* ・char* 返り値; buf 1249|*【補足】 1250|*・属性名が違っていると、例外を投げます。 1251|*・複数行は、初期化ファイル内では、次のように同じ属性が続きます。 1252|* attr = text of line 1 1253|* attr = text of line 2 1254|* attr = text of line 3 1255|*・1行あたり IniFile_Read_setStringSize で設定した値のバイト数しか 1256|* 読み込むことができません。逆に、設定した値が大きすぎると、次の行を 1257|* 読み込むための buf の余裕がすぐに無くなります。 1258|************************************************************************/ 1259|char* IniFile_Read_getMultiLine( IniFile_Read* m, const char* attr_name, 1260| char* retStr, char* buf, int buf_sizeof ) 1261|{ 1262| int i,n; 1263| char* p; 1264| char* p_over; 1265| 1266| p = buf; 1267| p_over = buf + buf_sizeof; 1268| 1269| n = IniFile_Read_getCount( m, attr_name ); 1270| for ( i = 0; i < n; i++ ) { 1271| if ( p_over - p < m->string_sizeof ) { 1272| error2_1( IniFile_Err_FewBuf, 1273| "バッファ領域が少ない(%s属性)", attr_name ); 1274| } 1275| IniFile_Read_getVar( m, attr_name, "s", p ); 1276| p = strchr( p, '\0' ); 1277| strcat( p, retStr ); 1278| p = strchr( p, '\0' ); 1279| } 1280| *p = '\0'; 1281| 1282| return buf; 1283|} 1284| 1285| 1286| 1287|/*********************************************************************** 1288|* 38. <<< [IniFile_Read_getMultiLineM] 複数行を入力する >>> 1289|*【引数】 1290|* ・char* attr_name; 属性名 1291|* ・char* mem; 文字列格納領域 1292|* ・char** var; 文字列(char*)のアドレス 1293|* ・char* retStr; 改行文字("\r\n"や"\n") 1294|*【補足】 1295|*・IniFile_Read_getMultiLine 関数の StrX_Mem を使用するタイプです。 1296|************************************************************************/ 1297|#ifdef USES_STRX 1298|void IniFile_Read_getMultiLineM( IniFile_Read* m, StrX_Mem* mem, 1299| const char* attr_name, char* retStr, char** var ) 1300|{ 1301| *var = StrX_Mem_alloc( mem ); 1302| IniFile_Read_getMultiLine( m, attr_name, retStr, 1303| *var, StrX_Mem_getLeftSize( mem ) ); 1304|} 1305|#endif 1306| 1307| 1308|/*********************************************************************** 1309|* 39. <<< [IniFile_Read_getMultiStr] 複数行を複数の文字列として入力する(StrX_Set) >>> 1310|*【引数】 1311|* ・char* attr_name; 属性名 1312|* ・StrX_Mem* buf; 文字列を格納する領域 1313|* ・StrX_Set* set; 文字列の部分集合 1314|*【補足】 1315|*・set は初期化されます。 1316|*・内部で、StrX_Mem_alloc を呼び出しています。 1317|*・複数行は、初期化ファイル内では、次のように同じ属性が続きます。 1318|* attr = text of line 1 1319|* attr = text of line 2 1320|* attr = text of line 3 1321|************************************************************************/ 1322|#ifdef USES_STRX 1323|#ifdef USES_ARRX 1324|void IniFile_Read_getMultiStr( IniFile_Read* m, StrX_Mem* buf, 1325| const char* attr_name, StrX_Set* set ) 1326|{ 1327| StrX_Set_init1( set, buf ); 1328| IniFile_Read_getMultiStrM( m, attr_name, buf ); 1329| StrX_Set_init2( set, buf ); 1330|} 1331|#endif 1332|#endif 1333| 1334| 1335| 1336|/*********************************************************************** 1337|* 40. <<< [IniFile_Read_getMultiStrM] 複数行を複数の文字列として入力する(StrX_Mem) >>> 1338|*【引数】 1339|* ・char* attr_name; 属性名 1340|* ・StrX_Mem* buf; 文字列を格納する領域 1341|*【補足】 1342|*・IniFile_Read_getMultiStr との違いは、StrX_Set に格納しないこと 1343|* だけです。 1344|************************************************************************/ 1345|#ifdef USES_STRX 1346|#ifdef USES_ARRX 1347|void IniFile_Read_getMultiStrM( IniFile_Read* m, const char* attr_name, 1348| StrX_Mem* buf ) 1349|{ 1350| int i,n; 1351| char* s; 1352| 1353| n = IniFile_Read_getCount( m, attr_name ); 1354| for ( i = 0; i < n; i++ ) { 1355| s = StrX_Mem_alloc( buf ); 1356| if ( (int)StrX_Mem_getLeftSize( buf ) < m->string_sizeof ) { 1357| error2_0( IniFile_Err_FewBuf, "文字列の格納領域が足りません" ); 1358| } 1359| IniFile_Read_getVar( m, attr_name, "s", s ); 1360| } 1361|} 1362|#endif 1363|#endif 1364| 1365| 1366| 1367|/*********************************************************************** 1368|* 41. <<< [IniFile_Read_getMultiStrV] 複数行を複数の文字列として入力する(StrV_Set) >>> 1369|*【引数】 1370|* ・char* attr_name; 属性名 1371|* ・StrV_Mem* buf; 文字列を格納する領域 1372|* ・StrV_Set* set; 文字列の部分集合 1373|*【補足】 1374|*・set は初期化されます。 1375|*・内部で、StrV_Mem_alloc を呼び出しています。 1376|*・複数行は、初期化ファイル内では、次のように同じ属性が続きます。 1377|* attr = text of line 1 1378|* attr = text of line 2 1379|* attr = text of line 3 1380|************************************************************************/ 1381|#ifdef USES_STRV 1382|void IniFile_Read_getMultiStrV( IniFile_Read* m, StrV_Mem* buf, 1383| const char* attr_name, StrV_Set* set ) 1384|{ 1385| int i,n; 1386| char* s; 1387| 1388| StrV_Set_init1( set, buf ); 1389| StrV_Mem_setMax( buf, m->string_sizeof ); 1390| n = IniFile_Read_getCount( m, attr_name ); 1391| for ( i = 0; i < n; i++ ) { 1392| s = StrV_Mem_alloc( buf ); 1393| IniFile_Read_getVar( m, attr_name, "s", s ); 1394| } 1395| StrV_Set_init2( set, buf ); 1396|} 1397|#endif 1398| 1399| 1400|/*********************************************************************** 1401|* 42. <<< [IniFile_Read_getMultiStrAV] 複数行を複数の文字列として入力する(ArrX_Able) >>> 1402|*【引数】 1403|* ・char* attr_name; 属性名 1404|* ・ArrX_Able* set; StrV_AbleElem 型の文字列の集合 1405|*【補足】 1406|*・set は初期化されます。 1407|*・内部で、StrV_Mem_alloc を呼び出しています。 1408|*・複数行は、初期化ファイル内では、次のように同じ属性が続きます。 1409|* attr = text of line 1 1410|* attr = text of line 2 1411|* attr = text of line 3 1412|************************************************************************/ 1413|#ifdef USES_BIGSTACK 1414|#ifdef USES_STRV 1415|void IniFile_Read_getMultiStrAV( IniFile_Read* m, 1416| const char* attr_name, ArrX_Able* set ) 1417|{ 1418| int i,n; 1419| char* s; 1420| StrV_AbleElem* sv; 1421| bool bStack = false; 1422| 1423| c_try { 1424| BigStack_start(); bStack = true; 1425| s = BigStack_alloc( m->string_sizeof ); 1426| n = IniFile_Read_getCount( m, attr_name ); 1427| for ( i = 0; i < n; i++ ) { 1428| sv = ArrX_Able_getFirstDisabled( set, StrV_AbleElem ); 1429| if ( sv == NULL ) error(); 1430| IniFile_Read_getVar( m, attr_name, "s", s ); 1431| StrV_cpy( &sv->s, s ); 1432| ArrX_AbleElem_setAble( sv, true ); 1433| } 1434| } 1435| c_finally { 1436| if ( bStack ) BigStack_end(); 1437| } c_end_finally; 1438|} 1439|#endif 1440|#endif 1441| 1442| 1443|/*********************************************************************** 1444|* 43. <<< [IniFile_Read_getPathes] ファイルパスの集合を入力する >>> 1445|*【引数】 1446|* ・StrX_Mem* mem; 文字列を格納する領域 1447|* ・ArrX_Buf* pmem; char* 型の配列を格納する領域 1448|* ・char* section_name; セクション名 1449|* ・ArrX* arr; ファイル・パス文字列の配列(出力) 1450|*【補足】 1451|*・属性名でなく、セクション名を指定することに注意してください。 1452|* つまり、セクション全体が、ファイルパスの専用領域になります。 1453|*・型リストに関しては、IniFile_Read_getVar2 関数を参照してください。 1454|*・IniFile_Write_putPathes 関数によって出力されたデータを入力できます。 1455|*・取得するパスは、ini ファイルの内容によって相対パスか絶対パスか異なります。 1456|*・ini ファイルは、編集しやすいように、次のような構成になっているとします。 1457|* [uses] 1458|* Folder = . ... フォルダパス 1459|* File = main.c ... ファイル名 1460|* File = main2.c 1461|* Folder = ..\inc 1462|* File = sub1.h 1463|* File = sub2.h 1464|* File = sub3.h 1465|* ただし、Folder 属性は、絶対パスでも構いません。 1466|************************************************************************/ 1467|#ifdef USES_ARRX 1468|#ifdef USES_STRX 1469|void IniFile_Read_getPathes( IniFile_Read* m, StrX_Mem* mem, 1470| ArrX_Buf* pmem, const char* section_name, ArrX* arr ) 1471|{ 1472| int i; 1473| int nFolder; /* Folder 属性の数 */ 1474| long sect_top; /* セクションの先頭のファイルアドレス */ 1475| char** pp = NULL; /* ファイル名(char*型)へのポインタ */ 1476| char** pp_first = NULL; /* pp の先頭 */ 1477| char* buf = m->lineBuf; 1478| 1479| /* セクションを検索する */ 1480| sect_top = IniFile_Read_searchSection( m, section_name, true ); 1481| 1482| /* Folder 属性がいくつあるか数える */ 1483| nFolder = 0; 1484| for(;;) { 1485| fgets( buf, m->lineBuf_sizeof, m->file ); 1486| if ( feof( m->file ) ) 1487| break; 1488| if ( buf[0] == '[' ) 1489| break; 1490| if ( strncmp( buf, "Folder", 6 ) == 0 && 1491| ( *(buf + 6) == ' ' || *(buf + 6) == '=' ) ) 1492| nFolder ++; 1493| } 1494| 1495| /* ファイルパスを入力する */ 1496| fseek( m->file, sect_top, SEEK_SET ); 1497| for ( i = 0; i < nFolder; i++ ) { 1498| static char folder[_MAX_PATH]; 1499| int ii, nFile; 1500| 1501| IniFile_Read_getVar( m, "Folder", "s", folder ); 1502| nFile = IniFile_Read_getCount( m, "File" ); 1503| pp = ArrX_Buf_allocs( pmem, char*, nFile ); 1504| if ( i == 0 ) pp_first = pp; 1505| 1506| for ( ii = 0; ii < nFile; ii++ ) { 1507| IniFile_Read_getVar2( m, mem, "File", "s", pp ); 1508| StrX_toAbsPath( *pp, StrX_Mem_getLeftSize(mem), folder ); 1509| pp++; 1510| } 1511| } 1512| ArrX_init2( arr, pp_first, pp ); 1513|} 1514|#endif 1515|#endif /* USES_ARRX */ 1516| 1517| 1518| 1519|/*********************************************************************** 1520|* 44. <<< [IniFile_Read_getPathesS] ファイルパスの集合を入力する >>> 1521|*【補足】 1522|*・IniFile_Read_getPathes との違いは、ArrX_Buf を使用しないで、 1523|* StrX_Set を初期化することです。 1524|************************************************************************/ 1525|#ifdef USES_ARRX 1526|#ifdef USES_STRX 1527|void IniFile_Read_getPathesS( IniFile_Read* m, StrX_Mem* mem, 1528| const char* section_name, StrX_Set* set ) 1529|{ 1530| static char* bufX[1024]; 1531| ArrX_Buf buf; 1532| ArrX dummy; 1533| 1534| ArrX_Buf_init( &buf, bufX, sizeof(bufX) ); 1535| 1536| StrX_Set_init1( set, mem ); 1537| IniFile_Read_getPathes( m, mem, &buf, section_name, &dummy ); 1538| StrX_Set_init2( set, mem ); 1539|} 1540|#endif 1541|#endif 1542| 1543| 1544|/* 45. <<< ------- 内部用 ------- >>> */ 1545| 1546| 1547| 1548|/*********************************************************************** 1549|* 46. <<< [IniFile_Read_readAttrName] 属性名をチェックする >>> 1550|*【引数】 1551|* ・char* attr_name; 属性名 1552|* ・char* 返り値; 行バッファ中の値の位置 1553|*【補足】 1554|*・内部用です。 1555|*【内部補足】 1556|*・属性名が違っていると、例外を投げます。 1557|*・行頭または空行の行頭にしてから、呼び出します。 1558|*・この関数から返ったとき、ファイルポインタは、属生行の次に移動しています。 1559|************************************************************************/ 1560|char* IniFile_Read_readAttrName( IniFile_Read* m, const char* attr_name ) 1561|{ 1562| char* buf = m->lineBuf; 1563| char* p; 1564| int c; 1565| 1566| /* 空行を飛ばして、属性行を読み込む */ 1567| do { 1568| fgets( buf, m->lineBuf_sizeof, m->file ); 1569| if ( buf[strlen(buf)-1] == '\n' ) 1570| buf[strlen(buf)-1] = '\0'; 1571| 1572| if ( feof( m->file ) ) { 1573| error2_1( IniFile_Err_FewAttr, "属性が少ない", attr_name ); 1574| } 1575| } while ( buf[0] == '\0' ); 1576| 1577| /* 属性名をチェックする */ 1578| while ( *buf == ' ' || *buf == '\t' ) { 1579| if ( *buf == '\0' ) break; 1580| buf++; 1581| } 1582| p = &buf[strlen(attr_name)]; 1583| c = *p; 1584| *p = '\0'; 1585| if ( c != ' ' && c != '=' && c != ':' ) { 1586| error2_3( IniFile_Err_BadAttr, 1587| "属性名が異なる(アプリ=%s, ファイル=%s in %s)", 1588| attr_name, buf, m->path ); 1589| } 1590| if ( stricmp( buf, attr_name ) != 0 ) { 1591| error2_3( IniFile_Err_BadAttr, 1592| "属性名が異なる(アプリ=%s, ファイル=%s in %s)", 1593| attr_name, buf, m->path ); 1594| } 1595| 1596| /* 空白とイコール(コロン)をスキップする */ 1597| p++; 1598| while ( *p == ' ' ) p++; 1599| if ( *p == '=' || *p == ':' ) p++; 1600| while ( *p == ' ' ) p++; 1601| 1602| return p; 1603|} 1604| 1605| 1606| 1607|/*********************************************************************** 1608|* 47. <<< [IniFile_Read_readVar] 属性値を読み込む >>> 1609|*【引数】 1610|* ・char* vars; ファイル行バッファ中の値の位置 1611|* ・char* types; 型リスト 1612|*【補足】 1613|*・内部用です。 1614|*【内部補足】 1615|*・詳細は、IniFile_Read_getVar 関数の解説を参照してください。 1616|************************************************************************/ 1617|#ifdef USES_STRX 1618|void IniFile_Read_readVar( IniFile_Read* m, char* vars, 1619| const char* types, va_list va ) 1620|{ 1621| char* nextVar; 1622| 1623| if ( *types != '\0' ) { 1624| for (;;) { 1625| 1626| /* 値の文字列を作る */ 1627| nextVar = StrX_meltCSV( vars, vars ); 1628| 1629| /* それぞれの型のデフォルト値を設定する(途中) */ 1630| if ( *vars == '\0' ) { 1631| switch( *types ) { 1632| case 's': strcpy( va_arg( va, char* ), "" ); break; 1633| case 'i': *va_arg( va, int* ) = 0; break; 1634| case 'b': *va_arg( va, bool* ) = false; break; 1635| } 1636| } 1637| /* それぞれの型の値を読み込む */ 1638| else { 1639| switch ( *types ) { 1640| case 's': 1641| case 'S': 1642| if ( (int)strlen( vars ) > m->string_sizeof - 1 ) { 1643| strncpy( va_arg( va, char* ), vars, m->string_sizeof - 1 ); 1644| vars[m->string_sizeof - 1] = '\0'; 1645| } 1646| else 1647| strcpy( va_arg( va, char* ), vars ); 1648| break; 1649| case 'i': 1650| case 'I': 1651| *va_arg( va, int* ) = atoi( vars ); 1652| break; 1653| case 'b': 1654| *va_arg( va, bool* ) = ( *vars != '0' ); 1655| break; 1656| case 'x': 1657| sscanf( vars + 2, "%X", va_arg( va, int* ) ); 1658| break; 1659| #ifdef USES_TIMEDATE 1660| case 't': 1661| TimeDate_loadStr( va_arg( va, time_t* ), vars ); 1662| break; 1663| #endif 1664| default: 1665| ASSERT( *types == '-' ); 1666| break; 1667| } 1668| } 1669| 1670| /* 次の項目への準備をする */ 1671| types ++; if ( *types == '\0' ) break; 1672| 1673| if ( nextVar == NULL ) break; 1674| vars = nextVar; 1675| } 1676| 1677| /* それぞれの型のデフォルト値を設定する(末尾) */ 1678| while ( *types != '\0' ) { 1679|char* aa; 1680| switch ( *types ) { 1681| case 's': aa = va_arg( va, char* ); aa[0] = '\0'; break; 1682| case 'i': *va_arg( va, int* ) = 0; break; 1683| case 'b': *va_arg( va, bool* ) = false; break; 1684| } 1685| types ++; 1686| } 1687| } 1688|} 1689|#endif 1690| 1691| 1692|/*********************************************************************** 1693|* 48. <<< [IniFile_Read_readVar2] 属性値を読み込む(StrX_Mem使用) >>> 1694|*【引数】 1695|* ・char* vars; ファイル行バッファ中の値の位置 1696|* ・StrX_Mem* mem; 文字列を格納する領域 1697|* ・char* types; 型リスト 1698|*【補足】 1699|*・内部用です。 1700|*【内部補足】 1701|*・詳細は、IniFile_Read_getVar2 関数の解説を参照してください。 1702|************************************************************************/ 1703|#ifdef USES_STRX 1704|void IniFile_Read_readVar2( IniFile_Read* m, char* vars, 1705| StrX_Mem* mem, const char* types, va_list va ) 1706|{ 1707| char* nextVar; 1708| char** pp; 1709| 1710| if ( *types != '\0' ) { 1711| for (;;) { 1712| 1713| /* 配列に行末までの要素を読み込む */ 1714| #ifdef USES_ARRX 1715| if ( *types == '*' ) { 1716| types++; 1717| IniFile_Read_readVar2_subA( m, vars, mem, types, va ); 1718| return; 1719| } 1720| #endif 1721| 1722| /* 値の文字列を作る */ 1723| nextVar = StrX_meltCSV( vars, vars ); 1724| 1725| /* それぞれの型の値を読み込む */ 1726| switch ( *types ) { 1727| case 's': 1728| case 'S': 1729| pp = va_arg(va, char**); 1730| if ( *vars == '\0' ) { 1731| if ( *types == 'S' ) *pp = StrX_Mem_alloc(mem); 1732| else *pp = NULL; 1733| } 1734| else 1735| IniFile_Read_readVar2_subS( m, vars, pp, mem ); 1736| break; 1737| 1738| case 'i': 1739| if ( *vars != '\0' ) { 1740| *va_arg( va, int* ) = atoi( vars ); 1741| } 1742| break; 1743| case 'b': 1744| if ( *vars != '\0' ) { 1745| *va_arg( va, bool* ) = ( *vars != '0' ); 1746| } 1747| break; 1748| #ifdef USES_TIMEDATE 1749| case 't': 1750| if ( *vars != '\0' ) { 1751| TimeDate_loadStr( va_arg( va, time_t* ), vars ); 1752| } 1753| break; 1754| #endif 1755| default: 1756| ASSERT( *types == '-' ); 1757| break; 1758| } 1759| 1760| /* 次の項目への準備をする */ 1761| types ++; if ( *types == '\0' ) break; 1762| 1763| if ( nextVar == NULL ) break; 1764| vars = nextVar; 1765| } 1766| } 1767|} 1768|#endif 1769| 1770| 1771|/*********************************************************************** 1772|* 49. <<< [IniFile_Read_readVar2_subA] 属性値を配列に読み込む(StrX_Mem使用) >>> 1773|*【補足】 1774|*・内部用です。 1775|*【内部補足】 1776|*・*types は、's' か 'i' のアドレスにしてください。 1777|*・詳細は、IniFile_Read_readVar2 関数を参照してください。 1778|************************************************************************/ 1779|#ifdef USES_ARRX 1780|#ifdef USES_STRX 1781|void IniFile_Read_readVar2_subA( IniFile_Read* m, char* vars, 1782| StrX_Mem* mem, const char* types, va_list va ) 1783|{ 1784| ArrX_Buf* pmem = va_arg( va, ArrX_Buf* ); 1785| ArrX* arr = va_arg( va, ArrX* ); 1786| void** pp; /* pmem から確保した領域のアドレス */ 1787| char* ppX; /* pmem == NULL のときの pp の参照先(ダミー)*/ 1788| void** pp_first; /* 最初の pp */ 1789| char* nextVar; /* 次の値 */ 1790| 1791| 1792| /* 1つも要素が無い場合 */ 1793| if ( StrX_isSpaceStr( vars ) ) { 1794| if ( arr != NULL ) ArrX_init2( arr, NULL, NULL ); 1795| return; 1796| } 1797| 1798| /* 要素がある場合 */ 1799| if ( pmem != NULL ) pp_first = pp = ArrX_Buf_alloc( pmem, void* ); 1800| else pp = &ppX; 1801| for (;;) { 1802| 1803| /* 値の文字列を作る */ 1804| nextVar = StrX_meltCSV( vars, vars ); 1805| 1806| /* それぞれの型の値を読み込む */ 1807| switch ( *types ) { 1808| case 's': 1809| IniFile_Read_readVar2_subS( m, vars, (char**)pp, mem ); 1810| break; 1811| case 'i': 1812| *(int*)pp = atoi( vars ); 1813| break; 1814| case 'b': 1815| *(bool*)pp = ( *vars != '0' ); 1816| break; 1817| #ifdef USES_TIMEDATE 1818| case 't': 1819| TimeDate_loadStr( (time_t*)pp, vars ); 1820| break; 1821| #endif 1822| default: 1823| ASSERT( *types == '-' ); 1824| break; 1825| } 1826| 1827| /* ループ終了判定 */ 1828| if ( nextVar == NULL ) 1829| break; 1830| 1831| /* 次の値を格納する準備をする */ 1832| vars = nextVar; 1833| while ( *vars == ' ' ) vars ++; 1834| if ( pmem != NULL ) 1835| pp = ArrX_Buf_alloc( pmem, void* ); 1836| } 1837| 1838| /* 配列を初期化する */ 1839| pp++; 1840| if ( arr != NULL ) ArrX_init2( arr, pp_first, pp ); 1841|} 1842|#endif 1843|#endif /* USES_ARRX */ 1844| 1845|