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|char* aa;
1640| switch ( *types ) {
1641| case 's':
1642| case 'S':
1643| if ( (int)strlen( vars ) > m->string_sizeof - 1 )
1644| vars[m->string_sizeof - 1] = '\0';
1645|aa = va_arg( va, char* );
1646| strcpy( aa, vars );
1647| break;
1648| case 'i':
1649| case 'I':
1650| *va_arg( va, int* ) = atoi( vars );
1651| break;
1652| case 'b':
1653| *va_arg( va, bool* ) = ( *vars != '0' );
1654| break;
1655| #ifdef USES_TIMEDATE
1656| case 't':
1657| TimeDate_loadStr( va_arg( va, time_t* ), vars );
1658| break;
1659| #endif
1660| default:
1661| ASSERT( *types == '-' );
1662| break;
1663| }
1664| }
1665|
1666| /* 次の項目への準備をする */
1667| types ++; if ( *types == '\0' ) break;
1668|
1669| if ( nextVar == NULL ) break;
1670| vars = nextVar;
1671| }
1672|
1673| /* それぞれの型のデフォルト値を設定する(末尾) */
1674| while ( *types != '\0' ) {
1675|char* aa;
1676| switch ( *types ) {
1677| case 's': aa = va_arg( va, char* ); aa[0] = '\0'; break;
1678| case 'i': *va_arg( va, int* ) = 0; break;
1679| case 'b': *va_arg( va, bool* ) = false; break;
1680| }
1681| types ++;
1682| }
1683| }
1684|}
1685|#endif
1686|
1687|
1688|/***********************************************************************
1689|* 48. <<< [IniFile_Read_readVar2] 属性値を読み込む(StrX_Mem使用) >>>
1690|*【引数】
1691|* ・char* vars; ファイル行バッファ中の値の位置
1692|* ・StrX_Mem* mem; 文字列を格納する領域
1693|* ・char* types; 型リスト
1694|*【補足】
1695|*・内部用です。
1696|*【内部補足】
1697|*・詳細は、IniFile_Read_getVar2 関数の解説を参照してください。
1698|************************************************************************/
1699|#ifdef USES_STRX
1700|void IniFile_Read_readVar2( IniFile_Read* m, char* vars,
1701| StrX_Mem* mem, const char* types, va_list va )
1702|{
1703| char* nextVar;
1704| char** pp;
1705|
1706| if ( *types != '\0' ) {
1707| for (;;) {
1708|
1709| /* 配列に行末までの要素を読み込む */
1710| #ifdef USES_ARRX
1711| if ( *types == '*' ) {
1712| types++;
1713| IniFile_Read_readVar2_subA( m, vars, mem, types, va );
1714| return;
1715| }
1716| #endif
1717|
1718| /* 値の文字列を作る */
1719| nextVar = StrX_meltCSV( vars, vars );
1720|
1721| /* それぞれの型の値を読み込む */
1722| switch ( *types ) {
1723| case 's':
1724| case 'S':
1725| pp = va_arg(va, char**);
1726| if ( *vars == '\0' ) {
1727| if ( *types == 'S' ) *pp = StrX_Mem_alloc(mem);
1728| else *pp = NULL;
1729| }
1730| else
1731| IniFile_Read_readVar2_subS( m, vars, pp, mem );
1732| break;
1733|
1734| case 'i':
1735| if ( *vars != '\0' ) {
1736| *va_arg( va, int* ) = atoi( vars );
1737| }
1738| break;
1739| case 'b':
1740| if ( *vars != '\0' ) {
1741| *va_arg( va, bool* ) = ( *vars != '0' );
1742| }
1743| break;
1744| #ifdef USES_TIMEDATE
1745| case 't':
1746| if ( *vars != '\0' ) {
1747| TimeDate_loadStr( va_arg( va, time_t* ), vars );
1748| }
1749| break;
1750| #endif
1751| default:
1752| ASSERT( *types == '-' );
1753| break;
1754| }
1755|
1756| /* 次の項目への準備をする */
1757| types ++; if ( *types == '\0' ) break;
1758|
1759| if ( nextVar == NULL ) break;
1760| vars = nextVar;
1761| }
1762| }
1763|}
1764|#endif
1765|
1766|
1767|/***********************************************************************
1768|* 49. <<< [IniFile_Read_readVar2_subA] 属性値を配列に読み込む(StrX_Mem使用) >>>
1769|*【補足】
1770|*・内部用です。
1771|*【内部補足】
1772|*・*types は、's' か 'i' のアドレスにしてください。
1773|*・詳細は、IniFile_Read_readVar2 関数を参照してください。
1774|************************************************************************/
1775|#ifdef USES_ARRX
1776|#ifdef USES_STRX
1777|void IniFile_Read_readVar2_subA( IniFile_Read* m, char* vars,
1778| StrX_Mem* mem, const char* types, va_list va )
1779|{
1780| ArrX_Buf* pmem = va_arg( va, ArrX_Buf* );
1781| ArrX* arr = va_arg( va, ArrX* );
1782| void** pp; /* pmem から確保した領域のアドレス */
1783| char* ppX; /* pmem == NULL のときの pp の参照先(ダミー)*/
1784| void** pp_first; /* 最初の pp */
1785| char* nextVar; /* 次の値 */
1786|
1787|
1788| /* 1つも要素が無い場合 */
1789| if ( StrX_isSpaceStr( vars ) ) {
1790| if ( arr != NULL ) ArrX_init2( arr, NULL, NULL );
1791| return;
1792| }
1793|
1794| /* 要素がある場合 */
1795| if ( pmem != NULL ) pp_first = pp = ArrX_Buf_alloc( pmem, void* );
1796| else pp = &ppX;
1797| for (;;) {
1798|
1799| /* 値の文字列を作る */
1800| nextVar = StrX_meltCSV( vars, vars );
1801|
1802| /* それぞれの型の値を読み込む */
1803| switch ( *types ) {
1804| case 's':
1805| IniFile_Read_readVar2_subS( m, vars, (char**)pp, mem );
1806| break;
1807| case 'i':
1808| *(int*)pp = atoi( vars );
1809| break;
1810| case 'b':
1811| *(bool*)pp = ( *vars != '0' );
1812| break;
1813| #ifdef USES_TIMEDATE
1814| case 't':
1815| TimeDate_loadStr( (time_t*)pp, vars );
1816| break;
1817| #endif
1818| default:
1819| ASSERT( *types == '-' );
1820| break;
1821| }
1822|
1823| /* ループ終了判定 */
1824| if ( nextVar == NULL )
1825| break;
1826|
1827| /* 次の値を格納する準備をする */
1828| vars = nextVar;
1829| while ( *vars == ' ' ) vars ++;
1830| if ( pmem != NULL )
1831| pp = ArrX_Buf_alloc( pmem, void* );
1832| }
1833|
1834| /* 配列を初期化する */
1835| pp++;
1836| if ( arr != NULL ) ArrX_init2( arr, pp_first, pp );
1837|}
1838|#endif
1839|#endif /* USES_ARRX */
1840|
1841|