C:\home\SVGCats_src\src\strx.c
1|/************************************************************************** 2| 1. <<< 文字列の拡張 (StrX) >>> 3| 4| 2. <<< 標準ライブラリの簡易ヘルプ >>> 5|・大文字小文字変換 _strlwr, _strupr 6|***************************************************************************/ 7| 8|#include "mixer_precomp.h" /* Auto precompiled header, Look at mixer-... folder */ 9|// #pragma hdrstop 10| 11|#include <string.h> 12|#include <stdio.h> 13|#include <stdlib.h> 14|#include <ctype.h> 15|#if defined(_MSC_VER) && !defined(UNDER_CE) 16| #include <mbctype.h> 17| #include <direct.h> 18|#endif 19| 20|#if defined(_WIN32) && !defined(__BORLANDC__) 21| //#include "windows.h" 22|#endif 23| 24|#if defined(USES_MXP_AUTOINC) 25| #include "strx.ah" /* Auto include header, Look at mixer-... folder */ 26|#endif 27| 28|#if defined(FOR_WIN32) || defined(FOR_DOS32) 29|#include <locale.h> 30|#endif 31| 32|#ifdef FOR_WINCE 33| #define stricmp _stricmp 34| #define strnicmp _strnicmp 35|#endif 36| 37|#ifdef STRX_USES_MALLOC 38|#ifndef USES_STDPLUS 39|#error need StdPlus 40|#endif 41|#endif 42| 43| 44| 45|/*********************************************************************** 46| 3. <<< (_ismbblead) WINCE用ダミー関数 >>> 47|************************************************************************/ 48|#ifdef FOR_WINCE 49|int _ismbblead( unsigned int c ) 50|{ 51| ASSERT(1); 52| return 0; 53|} 54|#endif 55| 56| 57| 58|/*********************************************************************** 59| 4. <<< main の引数を表示する [StrX_printMainArg()] >>> 60|************************************************************************/ 61|#ifndef FOR_WINCE 62|void StrX_printMainArg( int argc, char* argv[] ) 63|{ 64| int i; 65| 66| printf( "argc = %d\n", argc ); 67| for ( i = 0; i < argc; i++ ) 68| printf( "argv[%d] = %s\n", i, argv[i] ); 69|} 70|#endif 71| 72| 73| 74|/*-------------------------------------------------------------------------*/ 75|/* ◆5. <<<< (StrX) char* 型の文字列(コピー・一部コピー・連結) >>>> */ 76|/*-------------------------------------------------------------------------*/ 77| 78| 79| 80|/*********************************************************************** 81| 5-1. <<< [StrX_getNLine] 行数を返す >>> 82|【補足】 83|・改行コードは、Win, Mac, Unix のどれにも対応しています。 84|************************************************************************/ 85|int StrX_getNLine( const char* s ) 86|{ 87| int iLine = 1; 88| 89| for (;;) { 90| s = StrX_strchrs( s, "\n\r" ); 91| if ( s == NULL ) return iLine; 92| if ( *s == '\r' ) { 93| if ( *(s + 1) == '\n' ) s += 2; 94| else s ++; 95| } 96| else { 97| if ( *(s + 1) == '\r' ) s += 2; 98| else s ++; 99| } 100| iLine ++; 101| } 102|} 103| 104| 105| 106|/*********************************************************************** 107| 5-2. <<< [StrX_cpy] 文字列のあふれチェック付き strcpy >>> 108|【引数】 109| ・char* dst; コピー先の文字列格納領域のアドレス(出力) 110| ・char* src; コピー元の文字列格納領域のアドレス(入力) 111| ・int dst_size : dst のメモリサイズ(バイト) 112|【補足】 113|・あふれた分はカットされます。 114|・アドレスが dst < src の場合 memmove 関数を使わなくても正しく移動します。 115|************************************************************************/ 116|char* StrX_cpy( char* dst, const char* src, int dst_size ) 117|{ 118| int src_len = strlen( src ); 119| 120| if ( src_len >= dst_size - 1 ) { 121| if ( dst_size > 0 ) { 122| memcpy( dst, src, dst_size - 1 ); 123| dst[dst_size - 1] = '\0'; 124| } 125| return dst; 126| } 127| else 128| return strcpy( dst, src ); 129|} 130| 131| 132| 133|/*********************************************************************** 134| 5-3. <<< [StrX_ncpy] 文字列のあふれチェック付き strncpy >>> 135|【引数】 136| ・int dst_size : dst(出力)のメモリサイズ(byte) 137|【補足】 138|・あふれた分はカットされます。 139|************************************************************************/ 140|char* StrX_ncpy( char* dst, char* src, int n, int dst_size ) 141|{ 142| int src_len = strlen( src ); 143| int len; 144| 145| len = ( dst_size - 1 < src_len ) ? dst_size - 1 : src_len; 146| if ( n < len ) len = n; 147| 148| strncpy( dst, src, len ); 149| dst[len] = '\0'; 150| 151| return dst; 152|} 153| 154| 155| 156|/*********************************************************************** 157| 5-4. <<< [StrX_cpy1Line] 改行入り文字列の中から指定の行をコピーする >>> 158|【引数】 159| ・char* dst; 行を格納するアドレス 160| ・int dst_size; dst の領域のサイズ 161| ・char* src; 改行入り文字列 162| ・int iLine; 行番号(1以上) 163| ・char* 返り値; dst または NULL(NULL = iLine が全体の行数を超えている) 164|【補足】 165|・src の改行コードは、Win, Mac, Unix のどれにも対応しています。 166|************************************************************************/ 167|char* StrX_cpy1Line( char* dst, int dst_size, const char* src, int iLine ) 168|{ 169| char* p = (char*)src; 170| char* p2; 171| 172| while ( iLine >= 2 ) { 173| p = StrX_strchrs( p, "\n\r" ); 174| if ( p == NULL ) return NULL; 175| if ( *p == '\r' ) { 176| if ( *(p + 1) == '\n' ) p += 2; 177| else p ++; 178| } 179| else { 180| if ( *(p + 1) == '\r' ) p += 2; 181| else p ++; 182| } 183| iLine --; 184| } 185| 186| p2 = StrX_strchrs( p, "\n\r" ); 187| if ( p2 == NULL ) StrX_cpy( dst, p, dst_size ); 188| else StrX_ncpy( dst, p, p2 - p, dst_size ); 189| 190| return dst; 191|} 192| 193| 194| 195|/*********************************************************************** 196| 5-5. <<< [StrX_wordCpy] ワード・コピー、term 文字の直前までコピー >>> 197| src の term 文字の直前までコピーします。 198| 返り値:dec 199|************************************************************************/ 200|void StrX_wordCpy( char* dec, int dec_len, const char* src, char term ) 201|{ 202| char* dec_over = dec + dec_len; 203| 204| while ( dec < dec_over ) { 205| if ( *src == term || *src == '\0' ) { 206| *dec = '\0'; return; 207| } 208| *dec++ = *src++; 209| } 210| *dec = '\0'; 211|} 212| 213| 214| 215|/************************************************************************** 216| 5-6. <<< [StrX_toCSV] CSV 形式の1項目を作る >>> 217|【機能】 218|・必要に応じて "" で囲んだり " 文字を "" にします。 219|【引数】 220| ・int dst_maxLen; 格納できる最大の文字数('\0'除く) 221|【補足】 222|・','や'\n'を出力しないので、別に行ってください。 223|・"" で囲む条件は、文字列中に ',' または '"' がある場合、または、 224| 頭か末尾に空白がある場合です。 225|**************************************************************************/ 226|char* StrX_toCSV( char* dst, const char* src, int dst_maxLen ) 227|{ 228| char* ret = dst; 229| char* dst_over = dst + dst_maxLen; 230| int kakomu; /* "" で囲むか (bool) */ 231| 232| kakomu = ( strchr( src, ',' ) || strchr( src, '"' ) || 233| src[0] == ' ' || src[strlen(src)-1] == ' ' ); 234| 235| if ( kakomu ) { 236| if ( dst < dst_over ) { *dst = '"'; dst ++; } 237| } 238| 239| while ( *src != '\0' && dst < dst_over ) { 240| if ( *src == '"' ) { 241| *dst = '"'; dst ++; 242| if ( dst < dst_over ) { *dst = '"'; dst ++; } 243| } 244| else { 245| *dst = *src; dst ++; 246| } 247| src++; 248| } 249| 250| if ( kakomu ) { 251| if ( dst < dst_over ) { *dst = '"'; dst ++; } 252| } 253| 254| *dst = '\0'; 255| 256| return ret; 257|} 258| 259| 260| 261|/************************************************************************** 262| 5-7. <<< [StrX_meltCSV] CSV 形式の1項目を取り出し、通常の文字列に戻す >>> 263|【引数】 264| ・char* t; 通常の文字列を格納するアドレス 265| ・char* s; CSV 形式の文字列 266| ・char* 返り値; 次(右)の CSV 項目へのアドレス 267|【補足】 268|・"" で囲まない場合、両端の空白を取り除きます。 269|・t の領域サイズは、s と同じかそれ以上にしてください。 270| t は s と同じでも構いません。 271|・(abc,,def)のように、次の CSV 項目の内容が無い場合、 272| 返り値 ret は *ret == NULL です。 273|・(abc)のように、次の CSV 項目が無い場合、返り値 は NULL です。 274|【例】 275|・s = (abc, def) なら t=(abc), ret=( def) 276|・s = ("abc:""def""",ghi) なら t=(abc:"def"), ret=(ghi) 277|・s = ( abc ) なら t=(abc), ret=NULL 278|・プログラミング例 279| p = csv_string; 280| if ( *p != '\0' ) { 281| do { 282| p = StrX_meltCSV( s, p ); 283| : 284| } while ( p != NULL ); 285| } 286|*************************************************************************/ 287|char* StrX_meltCSV( char* t, const char* s ) 288|{ 289| /* 頭の空白を除く */ 290| while ( *s == ' ' ) s++; 291| 292| switch ( *s ) { 293| 294| /* "" で囲まれている場合 */ 295| case '"': 296| s++; 297| while ( *s != '"' || *(s+1) == '"' ) { /* " 文字まで */ 298| if ( *s == *(s+1) && *s == '"' ) s++; /* " 文字 */ 299| *t = *s; t++; s++; 300| if ( *s == '\0' ) break; 301| } 302| *t = '\0'; 303| 304| s++; 305| for (;;) { 306| if ( *s == ',' ) return (char*)s+1; 307| if ( *s == '\0' ) return NULL; 308| s++; 309| } 310| 311| /* 空の項目の場合 */ 312| case ',': 313| *t = '\0'; 314| return (char*)s+1; 315| 316| case '\0': 317| *t = '\0'; 318| return NULL; 319| 320| /* "" で囲まれていない場合 */ 321| default: { 322| char* sp = NULL; /* 最後の連続した空白の先頭 */ 323| 324| while ( *s != ',' && *s != '\0' && *s != '\r' && *s != '\n' ) { /* , 文字まで */ 325| 326| /* sp を設定する */ 327| if ( *s == ' ' ) { 328| if ( sp == NULL ) sp = t; 329| } 330| else sp = NULL; 331| 332| /* コピーする */ 333| *t = *s; t++; s++; 334| } 335| 336| /* 返り値を決定する */ 337| if ( *s == ',' ) s = s + 1; 338| else s = NULL; 339| 340| /* 末尾の空白を取り除く */ 341| if ( sp != NULL ) *sp = '\0'; 342| else *t = '\0'; 343| 344| return (char*)s; 345| } 346| } 347|} 348| 349| 350| 351|/************************************************************************** 352| 5-8. <<< [StrX_cpyToCSymbol] ファイルパスを C 言語のシンボルにする >>> 353|【補足】 354|・ファイル名の部分を、C 言語のシンボルで使えるようにします。 355|・2バイト文字は1バイトずつコードを判定します。 356|・dst と src は、別の文字列領域を指定してください。 357|***************************************************************************/ 358|char* StrX_cpyToCSymbol( char* dst, const char* src ) 359|{ 360| char* p; 361| 362| StrX_cpyFName( dst, src ); 363| StrX_chgExt( dst, "" ); 364| StrX_cutLastOf2( dst, '.' ); 365| 366| if ( isdigit( dst[0] ) ) 367| StrX_ins( dst, "_" ); 368| for ( p = dst; *p != '\0'; p++ ) { 369| if ( ! isalpha( *p ) && ! isdigit( *p ) ) *p = '_'; 370| } 371| 372| return dst; 373|} 374| 375| 376| 377|/************************************************************************** 378| 5-9. <<< [StrX_getCmdWord] スペース区切り& "" 囲みのワードをコピー >>> 379|【引数】 380| ・char* t; 文字列を格納するアドレス 381| ・char* s; コマンド文字列中の解析し始める位置 382| ・char* 返り値; 次(右)のワードのアドレス 383|【補足】 384|・"" で囲まない場合、両端の空白を取り除きます。 385|・t の領域サイズは、s と同じかそれ以上にしてください。 386| t は s と同じでも構いません。 387|・返り値のさす文字が '\0' のとき、次のワードはありません(最後のワードの次) 388|**************************************************************************/ 389|char* StrX_getCmdWord( char* t, const char* s ) 390|{ 391| while ( *s == ' ' ) s++; 392| if ( *s == '\0' ) return (char*)s; 393| 394| /* " " で囲まれている場合、'"' までをワードにする */ 395| if ( *s == '"' ) { 396| s++; 397| while ( *s != '"' ) { 398| if ( *s == '\0' ) 399| { *t = '\0'; return (char*)s; } 400| *t = *s; 401| t++; s++; 402| } 403| *t = '\0'; 404| s++; 405| return (char*)s; 406| } 407| 408| /* " " で囲まれていない場合、' ' までをワードにする */ 409| else { 410| while ( *s != ' ' ) { 411| if ( *s == '\0' ) 412| { *t = '\0'; return (char*)s; } 413| *t = *s; 414| t++; s++; 415| } 416| *t = '\0'; 417| s++; 418| return (char*)s; 419| } 420|} 421| 422| 423| 424|/*********************************************************************** 425| 5-10. <<< [StrX_cat] 文字列のあふれチェック付き strcat >>> 426| ・dst_maxLen : dst(出力)に格納できる最大の文字数(byte) 427| あふれ分はカットされる 428|************************************************************************/ 429|char* StrX_cat( char* dst, const char* add, int dst_maxLen ) 430|{ 431| int dst_len = strlen( dst ); 432| 433| if ( dst_len + (int)strlen( add ) > dst_maxLen ) { 434| memcpy( &dst[dst_len], add, dst_maxLen - dst_len ); 435| dst[dst_maxLen] = '\0'; 436| return dst; 437| } 438| return strcat( dst, add ); 439|} 440| 441| 442| 443|/*********************************************************************** 444| 5-11. <<< [StrX_catR] s2 の記憶領域に s1 + s2 を格納する >>> 445| 格納された s2 も返します 446| 例: char buf[60]; strcpy( buf, "cde" ); なら 447| StrX_catR( "ab", buf, 60 ) == buf == "abcde" 448|************************************************************************/ 449|char* StrX_catR( const char* s1, char* s2, int s2_size ) 450|{ 451| int s1_len = strlen( s1 ); 452| int s2_len = strlen( s2 ); 453| 454| if ( s1_len + s2_len < s2_size ) { 455| memmove( s2 + s1_len, s2, s2_len + 1 ); 456| memcpy( s2, s1, s1_len ); 457| } 458| else { 459| memmove( s2 + s1_len, s2, s2_size - s1_len - 1 ); 460| s2[s2_size - 1] = '\0'; 461| if ( s1_len < s2_size ) 462| memcpy( s2, s1, s1_len ); 463| else 464| memcpy( s2, s1, s2_size - 1 ); 465| } 466| return s2; 467|} 468| 469| 470| 471|/************************************************************************* 472| 5-12. <<< [StrX_cpyWild] ワイルドカードに対応する部分をコピーする >>> 473|【引数】 474| ・char* 返り値; dst と同じ(内容は、コピーされたもの) 475| (その他は例を参考) 476|【補足】 477|・dst の埋め込む部分を '*' ワイルドカードで指定します。 478|(以下は未対応) 479|・'?' ワイルドカードは n 個目の '?' と対応します。対応する '?' がない場合、 480| 何も埋め込まれません。 481|・dst_wild, src_wild のワイルドカード以外の部分が dst, src に対応していない 482| 場合、動作は不明です。 483|【例】 484|・dst_wild="[*]", src="abcdef", src_wild="abc*" ... dst="[def]" 485|(以下は未対応) 486|・dst_wild="[?,?,?]", src="abcdefgh", src_wild="ab?d*g?" ... dst="[c,h,]" 487|**************************************************************************/ 488|char* StrX_cpyWild( char* dst, const char* dst_wild, const char* src, 489| const char* src_wild ) 490|{ 491| char* d; 492| const char* dw; 493| const char* s; 494| const char* src_fst; /* ワイルドカードに対応する src 内の先頭アドレス */ 495| const char* src_lst; /* ワイルドカードに対応する src 内の末尾アドレス */ 496| 497| /* dst_wild の '*'ワイルドカードより前を dst へコピーする */ 498| d = dst; dw = dst_wild; 499| while ( *dw != '*' ) { 500| *d = *dw; 501| if ( *dw == '\0' ) return dst; 502| d++; dw++; 503| } 504| 505| /* ワイルドカードに対応する src 内のアドレス src_fst, src_lst を取得する */ 506| { 507| char* src_wild_aster = strchr( src_wild, '*' ); 508| char* src_wild_zero = strchr( src_wild, '\0' ); 509| char* src_zero = strchr( src, '\0' ); 510| 511| src_fst = src + (src_wild_aster - src_wild); 512| src_lst = src_zero - (src_wild_zero - src_wild_aster); 513| } 514| 515| /* src の '*'ワイルドカードに対応する部分を dst(d) にコピーする */ 516| s = src_fst; 517| while ( s <= src_lst ) { 518| *d = *s; 519| d++; s++; 520| } 521| 522| /* dst_wild の '*'ワイルドカードより後を dst(d) へコピーする */ 523| dw ++; /* skip '*' */ 524| while ( *dw != '\0' ) { 525| *d = *dw; 526| d++; dw++; 527| } 528| *d = '\0'; 529| 530| return dst; 531|} 532| 533| 534| 535|/************************************************************************* 536| 5-13. <<< [StrX_ins] 文字列を挿入する >>> 537|【引数】 538| ・char* dst; 挿入する位置 539| ・char* src; 挿入する文字列 540| ・char* 返り値; dst 541|【補足】 542|・文字列の途中に挿入する場合、次のようにポインタ演算してください。 543| char* str = "abc"; 544| StrX_ins( str+1, "X" ); 545|・領域サイズをチェックするものには対応していません。 546| ヒント=StrX_separateByByteInLine 547|**************************************************************************/ 548|char* StrX_ins( char* dst, const char* src ) 549|{ 550| int len = strlen(src); 551| memmove( dst + len, dst, strlen(dst) + 1 ); 552| memcpy( dst, src, len ); 553| return dst; 554|} 555| 556| 557| 558|/*********************************************************************** 559| 5-14. <<< [StrX_setLast] 末尾の文字が c でないなら追加する >>> 560| 返り値 : 追加した文字列 561|************************************************************************/ 562|#ifndef K_AND_R 563|char* StrX_setLast( char* s, char c ) 564|#else 565|char* StrX_setLast( s, c ) 566| char* s; char c; 567|#endif 568|{ 569| char* p = s; 570| int bLastHit; /* 直前の文字が c かどうか */ 571| 572| while ( *p != '\0' ) { 573| if ( _ismbblead( *p ) ) { p++; bLastHit = 0; } 574| else bLastHit = ( *p == c ); 575| p++; 576| } 577| if ( ! bLastHit ) { *p = c; p++; *p = '\0'; } 578| 579| return s; 580|} 581| 582| 583| 584|/*-------------------------------------------------------------------------*/ 585|/* ◆6. <<<< (StrX) char* 型の文字列(削除) >>>> */ 586|/*-------------------------------------------------------------------------*/ 587| 588| 589| 590|/*********************************************************************** 591| 6-1. <<< [StrX_bs] バックスペース、末尾の 1 バイトを除く >>> 592|【引数】 593| ・char* s; 末尾を除く文字列 594| ・char* 返り値; 除いた文字列 595|************************************************************************/ 596|#ifndef K_AND_R 597|char* StrX_bs( char* s ) 598|#else 599|char* StrX_bs( s ) 600| char* s; 601|#endif 602|{ 603| int len = strlen( s ); 604| 605| s[ len - 1 ] = '\0'; 606| 607| return s; 608|} 609| 610| 611| 612|/*********************************************************************** 613| 6-2. <<< [StrX_bs2] バックスペース、末尾の n バイトを除く >>> 614|【引数】 615| ・char* s; 末尾を除く文字列 616| ・int n; 削除するバイト数 617| ・char* 返り値; 除いた文字列 618|************************************************************************/ 619|#ifndef K_AND_R 620|char* StrX_bs2( char* s, int n ) 621|#else 622|char* StrX_bs2( s, n ) 623| char* s; 624| int n; 625|#endif 626|{ 627| int len = strlen( s ); 628| 629| ASSERT( len - n >= 0 ); 630| 631| s[ len - n ] = '\0'; 632| 633| return s; 634|} 635| 636| 637| 638|/************************************************************************ 639| 6-3. <<< [StrX_del] 文字列中の s の位置から n 文字だけ削除する >>> 640|【引数】 641| ・char* s; 削除を開始する文字列中のアドレス 642| ・int n; 削除するバイト数 643| ・char* 返り値; 除いた文字列 644|*************************************************************************/ 645|void StrX_del( char* s, int n ) 646|{ 647| ASSERT( (unsigned)n <= strlen( s ) ); 648| 649| memmove( s, s+n, strlen(s)-n+1 ); 650|} 651| 652| 653| 654|/*********************************************************************** 655| 6-4. <<< [StrX_trim] 文字列の両端の空白、タブ、改行を取り除く >>> 656|【引数】 657| ・char* s; 両端の空白を削除する文字列 658| ・char* 返り値; 取り除いた文字列 659|************************************************************************/ 660|char* StrX_trim( char* s ) 661|{ 662| char* left; 663| char* right; 664| 665| /* 空白、タブ、改行を除いた、文字列 s の先頭の位置 left を得る */ 666| left = s; 667| while ( StrX_isSpace(*left) ) left ++; 668| 669| /* 空白、タブ、改行を除いた、文字列 s の末尾の位置 right を得る */ 670| right = left + strlen( left ) - 1; 671| while ( StrX_isSpace(*right) && right >= s ) right --; 672| 673| /* 両端の空白、タブ、改行を取り除いた文字列 s に変える */ 674| right[1] = '\0'; 675| memmove( s, left, strlen( left ) + 1 ); 676| 677| return s; 678|} 679| 680| 681| 682|/*********************************************************************** 683| 6-5. <<< [StrX_trim2] 文字列の両端の空白、タブ、改行、'"'を取り除く >>> 684| 返り値 : 取り除いた文字列 685|************************************************************************/ 686|char* StrX_trim2( char* s ) 687|{ 688| char* left; 689| char* right; 690| 691| StrX_trim( s ); 692| 693| /* 空白、タブ、改行を除いた、文字列 s の先頭の位置 left を得る */ 694| left = s; 695| while ( *left == '"' ) left ++; 696| 697| /* 空白、タブ、改行を除いた、文字列 s の末尾の位置 right を得る */ 698| right = left + strlen( left ) - 1; 699| while ( *right == '"' && right >= s ) right --; 700| 701| /* 両端の空白、タブ、改行を取り除いた文字列 s に変える */ 702| right[1] = '\0'; 703| memmove( s, left, strlen( left ) + 1 ); 704| 705| return s; 706|} 707| 708| 709| 710|/*********************************************************************** 711| 6-6. <<< [StrX_cutHtmlTag] 文字列中の HTML タグを取り除く >>> 712|************************************************************************/ 713|void StrX_cutHtmlTag( char* s ) 714|{ 715| char* s2 = s; /* s=コピー元、s2=コピー先 */ 716| 717| while ( *s != '\0' ) { 718| if ( _ismbblead( *s ) ) { 719| *s2 = *s; 720| *(s2 + 1) = *(s + 1); 721| s += 2; s2 += 2; 722| } 723| else { 724| if ( *s == '<' ) { 725| s++; 726| do { 727| while ( _ismbblead( *s ) ) s += 2; 728| s++; 729| } while ( *s != '>' && *s != '\0' ); 730| s++; 731| } 732| else { 733| *s2 = *s; 734| s ++; s2 ++; 735| } 736| } 737| } 738| *s2 = '\0'; 739|} 740| 741| 742| 743|/*********************************************************************** 744| 6-7. <<< [StrX_cutRet] 文字列中のリターン文字とタブ文字を取り除く >>> 745|【引数】 746| ・char* 返り値; s の値 747|【補足】 748|・'\r'と'\n'と'\t' 文字を取り除きます。 749|・行が文の区切りのときに、複数行の1つの文を出力するために使います。 750|************************************************************************/ 751|char* StrX_cutRet( char* s ) 752|{ 753| char* x = s; 754| char* y = s; 755| 756| while ( *x != '\0' ) { 757| if ( *x == '\r' || *x == '\n' || *x == '\t' ); 758| else *y++ = *x; 759| x++; 760| } 761| *y = '\0'; 762| 763| return s; 764|} 765| 766| 767| 768|/*********************************************************************** 769| 6-8. <<< [StrX_cutLastOf] 末尾の文字が c なら取り除く(日本語非対応) >>> 770| 返り値 : 取り除いた文字列 771|************************************************************************/ 772|#ifndef K_AND_R 773|char* StrX_cutLastOf( char* s, char c ) 774|#else 775|char* StrX_cutLastOf( s, c ) 776| char* s; char c; 777|#endif 778|{ 779| int len = strlen( s ); 780| 781| if ( s[ len - 1 ] == c ) { 782| s[ len - 1 ] = '\0'; 783| } 784| 785| return s; 786|} 787| 788| 789| 790|/*********************************************************************** 791| 6-9. <<< [StrX_cutLastOf2] 末尾の文字が c なら取り除く(日本語対応) >>> 792|************************************************************************/ 793|char* StrX_cutLastOf2( char* s, char c ) 794|{ 795| char* p; 796| int f = 1; 797| 798| /* 最後の文字が日本語かどうか判定して結果を f へ */ 799| for ( p = s; *p != '\0'; p++ ) { 800| if ( _ismbblead( *p ) ) { p++; f = 0; } 801| else f = 1; 802| } 803| 804| /* 末尾の文字が c なら取り除く */ 805| if ( f ) { 806| p--; 807| if ( *p == c ) *p = '\0'; 808| } 809| 810| return s; 811|} 812| 813| 814| 815|/*********************************************************************** 816| 6-10. <<< [StrX_cutLastOf_2byteFirst] 末尾の文字が全角文字の最初のバイトなら取り除く >>> 817|************************************************************************/ 818|char* StrX_cutLastOf_2byteFirst( char* s ) 819|{ 820| char* p = strchr( s, '\0' ) - 1; 821| 822| if ( _ismbblead( *p ) ) *p = '\0'; 823| 824| return s; 825|} 826| 827| 828| 829|/*-------------------------------------------------------------------------*/ 830|/* ◆7. <<<< (StrX) char* 型の文字列(検索・参照) >>>> */ 831|/*-------------------------------------------------------------------------*/ 832| 833| 834| 835|/*********************************************************************** 836| 7-1. <<< [StrX_getLast] 末尾の文字を得る >>> 837|************************************************************************/ 838|#ifndef K_AND_R 839|char StrX_getLast( const char* s ) 840|#else 841|char StrX_getLast( s ) 842| const char* s; 843|#endif 844|{ 845| return s[ strlen( s ) - 1 ]; 846|} 847| 848| 849| 850|/*********************************************************************** 851| 7-2. <<< [StrX_strchrs] 複数の文字を OR 検索する >>> 852|【引数】 853| ・char* s; 検索される文字列 854| ・char* key; 検索文字を並べた文字列('\0'は指定できません) 855| ・char* 返り値; 見つかった文字のアドレス(s の中のアドレス) 856|【補足】 857|・key の最初の文字にヒットするほど早く返ってきます。 858|************************************************************************/ 859|char* StrX_strchrs( const char* s, const char* key ) 860|{ 861| for ( ; *s != '\0'; s++ ) { 862| if ( strchr( key, *s ) != NULL ) 863| return (char*)s; 864| } 865| return NULL; 866|} 867| 868| 869| 870|/*********************************************************************** 871| 7-3. <<< [StrX_strchr2] 日本語中の半角文字を検索する >>> 872|【補足】 873| ・全角文字の2バイト目に誤ってヒットしないようになっています。 874|************************************************************************/ 875|char* StrX_strchr2( const char* s, int k ) 876|{ 877| while ( *s != '\0' ) { 878| if ( _ismbblead( *s ) ) { 879| s += 2; 880| } 881| else { 882| if ( *s == k ) 883| return (char*)s; 884| s++; 885| } 886| } 887| return NULL; 888|} 889| 890| 891| 892|/*********************************************************************** 893| 7-4. <<< [StrX_strchrs2] 日本語中の複数の半角文字を OR 検索する >>> 894|【補足】 895|・全角文字の2バイト目に誤ってヒットしない StrX_strchrs です。 896|************************************************************************/ 897|char* StrX_strchrs2( const char* s, const char* key ) 898|{ 899| int i; 900| 901| for ( i = 0; s[i] != '\0'; i++ ) { 902| if ( _ismbblead( s[i] ) ) i++; 903| else { 904| if ( strchr( key, s[i] ) != NULL ) 905| return (char*)s + i; 906| } 907| } 908| return NULL; 909|} 910| 911| 912| 913|/*********************************************************************** 914| 7-5. <<< [StrX_strchrs_not] 複数の文字のどれでもない文字を検索する >>> 915|【引数】 916| ・char* s; 検索される文字列 917| ・char* key; not 検索文字を並べた文字列 918| ・char* 返り値; 見つかった文字のアドレス(s の中のアドレス) 919|************************************************************************/ 920|char* StrX_strchrs_not( const char* s, const char* key ) 921|{ 922| for ( ; *s != '\0'; s++ ) { 923| if ( strchr( key, *s ) == NULL ) 924| return (char*)s; 925| } 926| return NULL; 927|} 928| 929| 930| 931|/*********************************************************************** 932| 7-6. <<< [StrX_RSearchC] 文字を逆順サーチ >>> 933|【補足】 934|・strchr() の検索を文字列の末尾から行ないます。 935|・標準ライブラリに strrchr があります。 936|************************************************************************/ 937|#ifndef K_AND_R 938|char* StrX_RSearchC( const char* s, char key ) 939|#else 940|char* StrX_RSearchC( s, key ) 941| const char* s; char key; 942|#endif 943|{ 944| const char* top = s; 945| 946| s = s + strlen( s ); 947| while ( s >= top ) { 948| if ( *s == key ) 949| return (char*)s; 950| s--; 951| } 952| return NULL; 953|} 954| 955| 956| 957|/*********************************************************************** 958| 7-7. <<< [StrX_RSearchC2] 文字を逆順サーチ(日本語対応) >>> 959|************************************************************************/ 960|char* StrX_RSearchC2( const char* s, int key ) 961|{ 962| const char* ss; 963| int f = 0; 964| 965| for (;;) { 966| ss = StrX_strchr2( s, key ); 967| if ( ss == NULL ) return ( f ? (char*)s - 1 : NULL ); 968| s = ss + 1; 969| f = 1; 970| } 971|} 972| 973| 974| 975|/*********************************************************************** 976| 7-8. <<< [StrX_RSearch] 文字列を逆順サーチ >>> 977|【補足】 978|・strstr() の検索を文字列の末尾から行なう 979|************************************************************************/ 980|#ifndef K_AND_R 981|char* StrX_RSearch( char* s, char* key ) 982|#else 983|char* StrX_RSearch( s, key ) 984| char* s; char* key; 985|#endif 986|{ 987| char* top = s; 988| int len = strlen( key ); 989| 990| s = s + strlen( s ); 991| while ( s >= top ) { 992| if ( strncmp( s, key, len ) == 0 ) 993| return s; 994| s--; 995| } 996| return NULL; 997|} 998| 999| 1000| 1001|/*********************************************************************** 1002| 7-9. <<< [StrX_stristr] 文字列を大文字小文字区別なく検索する >>> 1003|************************************************************************/ 1004|char* StrX_stristr( const char* s, const char* key ) 1005|{ 1006| const char* pS; 1007| const char* pKey; 1008| 1009| while ( *s != '\0' ) { 1010| if ( toupper(*s) == toupper(*key) ) { 1011| pS = s+1; pKey = key+1; 1012| if ( *pKey == '\0' ) return (char*)s; 1013| while ( toupper(*pS) == toupper(*pKey) ) { 1014| pS++; pKey ++; 1015| if ( *pKey == '\0' ) return (char*)s; 1016| } 1017| } 1018| s++; 1019| } 1020| return NULL; 1021|} 1022| 1023| 1024| 1025|/*********************************************************************** 1026| 7-10. <<< [StrX_stristr3] 文字列を大文字小文字区別なく検索する(漢字、連結) >>> 1027|【引数】 1028| ・char* s; 検索される文字列 1029| ・char* key; 検索するキーワード 1030| ・bool bCase; 大文字小文字を区別するかどうか 1031| ・int* hitCount; (入出力)前回の検索で途中までヒットしていたバイト数(→補足) 1032| ・char* 返り値; ヒットした位置(→補足) 1033|【補足】 1034|・連結(複数の文字列領域にまたがったキーワードもヒット)します。 1035| 連結して検索しないときは hitCount = NULL で構いません。 1036|・初めてこの関数を使うときは、*hitCount = 0 としてください。 1037| s に前回の s の続きの文字列領域を指定した場合、 1038| hitCount の変数に格納された値をそのまま使用してください。 1039| ただし、*hitCount は、返り値が NULL だったときのみ設定されます。 1040|・複数の文字列領域にまたがったキーワードがヒットしたときは、s よりも 1041| 前のアドレスが返り値になるので注意してください。 1042|【内部補足】 1043|・前回の文字列領域の最後が日本語文字の1バイト目なら *hitCount == -1 です。 1044|************************************************************************/ 1045|char* StrX_stristr3( const char* s, const char* key, bool bCase, 1046| int* hitCount ) 1047|{ 1048| int hitCount2 = ( hitCount == NULL ? 0 : *hitCount ); 1049| const char* p; 1050| int key_len = strlen( key ); 1051| char* s_overKey = strchr( s, '\0' ) - key_len + 1; 1052| int (*ncmp)( const char*, const char*, size_t n ); 1053| 1054| ncmp = ( bCase ? strncmp : strnicmp ); 1055| 1056| /* 前の文字列領域とまたがったキーワードを検索する */ 1057| while ( hitCount2 > 0 ) { 1058| if ( (*ncmp)( s, key + hitCount2, key_len - hitCount2 ) == 0 ) 1059| return (char*)s - hitCount2; /* Hit! */ 1060| 1061| for ( p = key + 1, hitCount2 --; 1062| hitCount2 > 0; 1063| p++, hitCount2 -- ) { 1064| if ( (*ncmp)( key, p, hitCount2 ) == 0 ) 1065| break; 1066| if ( _ismbblead( *p ) ) { p++, hitCount2 --; } 1067| } 1068| } 1069| 1070| /* 文字列領域に完全に含まれるキーワードを検索する */ 1071| for ( p = s - hitCount2; p < s_overKey; p++ ) { 1072| if ( (*ncmp)( p, key, key_len ) == 0 ) return (char*)p; /* hit! */ 1073| if ( _ismbblead( *p ) ) p++; 1074| } 1075| 1076| /* 次の文字列領域とまたがったキーワードがある可能性を残す */ 1077| for ( hitCount2 = key_len - 1; hitCount2 > 0; hitCount2 --, p++ ) { 1078| if ( (*ncmp)( p, key, hitCount2 ) == 0 ) 1079| break; 1080| if ( _ismbblead( *p ) ) { p++, hitCount2 --; } 1081| } 1082| 1083| if ( hitCount != NULL ) *hitCount = hitCount2; 1084| 1085| return NULL; 1086|} 1087| 1088| 1089| 1090|/*********************************************************************** 1091| 7-11. <<< [StrX_stristr3r] 文字列を大文字小文字区別なく検索する(漢字、逆順) >>> 1092|【引数】 1093| ・char* s; 検索される文字列の先頭 1094| ・int startOffset; 検索を開始する位置 1095| ・char* key; 検索するキーワード 1096| ・bool bCase; 大文字小文字を区別するかどうか 1097| ・int* hitCount; ダミー(NULLを指定してください) 1098| ・char* 返り値; ヒットした位置 1099|************************************************************************/ 1100|char* StrX_stristr3r( const char* s, int startOffset, 1101| const char* key, bool bCase, int* hitCount ) 1102|{ 1103| const char* ss = s-1; 1104| const char* r = NULL; 1105| bool bFound = false; 1106| 1107| for (;;) { 1108| r = StrX_stristr3( ss+1, key, bCase, NULL ); 1109| if ( r == NULL ) return bFound ? (char*)ss : NULL; 1110| 1111| if ( r > s + startOffset ) return bFound ? (char*)ss : NULL; 1112| ss = r; 1113| bFound = true; 1114| } 1115|} 1116| 1117| 1118|/*********************************************************************** 1119| 7-12. <<< [StrX_searchWord] ワードを検索する >>> 1120|【補足】 1121|・英文字、数字、アンダーラインが連続したものをワードとします。 1122|・大文字小文字を区別します。 1123|・日本語には対応していません。 1124|・ワードが見つからない場合、NULL を返します。 1125|【例】 1126|・s="abc defInfo def-info", k="def", 返り値="def-info" の d のアドレス 1127|************************************************************************/ 1128|char* StrX_searchWord( const char* s, const char* k ) 1129|{ 1130| char* p; 1131| int len = strlen( k ); 1132| 1133| for (;;) { 1134| p = strstr( s, k ); 1135| if ( p == NULL ) 1136| break; 1137| if ( ( s == p || StrX_isTerm(*(p-1)) ) && StrX_isTerm(*(p+len)) ) 1138| break; 1139| s = p+1; 1140| } 1141| return p; 1142|} 1143| 1144| 1145| 1146|/*********************************************************************** 1147| 7-13. <<< [StrX_getWordTop] 指定位置のワードの先頭のアドレスを返す >>> 1148|【引数】 1149| ・s : バッファ(文字列)全体の先頭へのアドレス 1150| ・p : ワードのどこかの位置 1151| ・term : ワード区切り文字 1152| 例: s="abc; def; g", p=s+6('e'), term=';' なら返り値=s+4(' ') 1153|************************************************************************/ 1154|char* StrX_getWordTop( char* s, char* p, char term ) 1155|{ 1156| while ( p > s ) { 1157| if ( *p == term ) 1158| return p+1; 1159| p--; 1160| } 1161| return s; 1162|} 1163| 1164| 1165| 1166|/*********************************************************************** 1167| 7-14. <<< [StrX_getCmdParam] コマンドラインのパラメータを取得する >>> 1168|【引数】 1169| ・char* cmdline; パラメータ列の先頭(先頭の空白があってもよい) 1170| ・char* param; パラメータの格納先アドレス 1171| ・int param_size; param のメモリサイズ 1172| ・char* 返り値; 次のパラメータの先頭、無ければ NULL 1173|【補足】 1174|・ダブルクォーテーション("")で囲まれたものは1つのパラメータとします。 1175|【例】 1176|・以下の例では、文字列の境界を[ ]で表示しています。 1177|・cmdline=[file.exe 10 abc], param=[file.exe], 返り値=[10 abc] 1178|・cmdline=[ "10 abc"], param=[10 abc], 返り値=NULL 1179|・cmdline=[ ], param=[], 返り値=NULL 1180|************************************************************************/ 1181|char* StrX_getCmdParam( const char* cmdline, char* param, int param_size ) 1182|{ 1183| const char* c = cmdline; 1184| char* p = param; 1185| char* p_over = param + param_size - 1; 1186| 1187| /* 先頭の空白をスキップする */ 1188| while ( *c == ' ' ) p++; 1189| if ( *c == '\0' ) { param[0] = '\0'; return NULL; } 1190| 1191| /* "" で囲まれたパラメータのとき */ 1192| if ( *c == '\"' ) { 1193| for ( c = c+1; *c != '\0' && *c != '\"' && p < p_over; p++, c++ ) { 1194| if ( _ismbblead(*p) ) 1195| { *p = *c; p++; c++; *p = *c; } 1196| else 1197| *p = *c; 1198| } 1199| c++; 1200| } 1201| 1202| /* "" で囲まれていないパラメータのとき */ 1203| else { 1204| for ( c = c+1; *c != '\0' && *c != ' ' && p < p_over; p++, c++ ) { 1205| if ( _ismbblead(*p) ) 1206| { *p = *c; p++; c++; *p = *c; } 1207| else 1208| *p = *c; 1209| } 1210| } 1211| 1212| *p = '\0'; 1213| 1214| /* 次のパラメータを探す */ 1215| while ( *c == ' ' ) p++; 1216| if ( *c == '\0' ) return NULL; 1217| else return (char*)c; 1218|} 1219| 1220| 1221| 1222|/*********************************************************************** 1223| 7-15. <<< [StrX_getCSV] CSV 形式の指定カラムの文字列を取得する >>> 1224|【引数】 1225| ・char* s; CSV 形式の行 1226| ・int iColumn; カラム番号(1〜) 1227| ・char* out; 文字列を格納するアドレス(s とは違う領域に) 1228| ・int out_size; out のメモリサイズ 1229| ・char* 返り値; out と同じ, iColumn が大きいすぎる場合は NULL 1230|【補足】 1231|・out_size は、s のメモリサイズと同じかそれ以上にしてください。 1232|・iColumn が大きすぎる場合、out には最後の項目が格納されます。 1233|・CSV 形式の行 s が "" の場合、iColumn == 1 でも NULL が返ります。 1234|************************************************************************/ 1235|char* StrX_getCSV( const char* s, int iColumn, char* out, int out_size ) 1236|{ 1237| const char* p = s; 1238| 1239| ASSERT( (unsigned)out_size > strlen(s) ); 1240| ASSERT( iColumn >= 1 ); 1241| 1242| if ( s[0] == '\0' ) return NULL; 1243| 1244| while ( iColumn > 1 ) { 1245| p = StrX_meltCSV( out, p ); 1246| if ( p == NULL ) return NULL; 1247| iColumn --; 1248| } 1249| StrX_meltCSV( out, p ); 1250| 1251| return out; 1252|} 1253| 1254| 1255| 1256|/*********************************************************************** 1257| 7-16. <<< [StrX_findInCSV] CSV 形式の中から一致する文字列を検索する >>> 1258|【引数】 1259| ・char* s; CSV 形式の行 1260| ・char* key; キー文字列 1261| ・bool bCase; 大文字小文字を区別するかどうか 1262| ・char* 返り値; 一致した文字列の項目番号(1〜)、見つからない=-1 1263|************************************************************************/ 1264|int StrX_findInCSV( const char* s, const char* key, bool bCase ) 1265|{ 1266| enum { ss_size = 256 }; 1267| int iCol; 1268| char ss[ss_size]; 1269| 1270| ASSERT( strlen(key) < ss_size ); 1271| 1272| if ( bCase ) { 1273| for ( iCol = 1; ; iCol++ ) { 1274| if ( StrX_getCSV( s, iCol, ss, ss_size ) == NULL ) return -1; 1275| if ( strcmp( ss, key ) == 0 ) return iCol; 1276| } 1277| } 1278| else { 1279| for ( iCol = 1; ; iCol++ ) { 1280| if ( StrX_getCSV( s, iCol, ss, ss_size ) == NULL ) return -1; 1281| if ( stricmp( ss, key ) == 0 ) return iCol; 1282| } 1283| } 1284|} 1285| 1286| 1287| 1288|/*********************************************************************** 1289| 7-17. <<< [StrX_getCSVColumn] CSV 形式の指定位置のカラム番号を取得する >>> 1290|【引数】 1291| ・char* s; CSV 形式の行 1292| ・char* pos; カラム番号を調べる文字の位置 1293| ・char* 返り値; カラム番号(1〜) 1294|************************************************************************/ 1295|int StrX_getCSVColumn( const char* s, const char* pos ) 1296|{ 1297| int iColumn = 0; 1298| const char* p = s; 1299| static char ss[256]; 1300| 1301| while ( p != NULL && pos >= p ) { 1302| p = StrX_meltCSV( ss, p ); 1303| iColumn ++; 1304| } 1305| 1306| return iColumn; 1307|} 1308| 1309| 1310| 1311|/*********************************************************************** 1312| 7-18. <<< [StrX_getCSVNColumn] CSV 形式のカラム数を取得する >>> 1313|【引数】 1314| ・char* s; CSV 形式の行 1315| ・bool bCountSpace; 末尾の空白や空のカラムをカウントするかどうか 1316| ・char* 返り値; カラム数 1317|************************************************************************/ 1318|int StrX_getCSVNColumn( const char* s, bool bCountSpace ) 1319|{ 1320| int iColumn = 0; 1321| const char* p; 1322| int nn = 0; /* 連続した空白カラムの数 */ 1323| static char ss[256]; 1324| 1325| p = s; 1326| while ( p != NULL ) { 1327| p = StrX_meltCSV( ss, p ); 1328| 1329| if ( ! bCountSpace ) { 1330| StrX_trim( ss ); 1331| if ( ss[0] == '\0' ) nn++; else nn=0; 1332| } 1333| iColumn ++; 1334| } 1335| 1336| return iColumn - nn; 1337|} 1338| 1339| 1340| 1341|/*********************************************************************** 1342| 7-19. <<< [StrX_refTopOfLine] 行頭を参照する >>> 1343|【引数】 1344| ・char* src; 改行入り文字列 1345| ・int iLine; 行番号(1以上) 1346| ・char* 返り値; 行頭(src内)または NULL(NULL = iLine が全体の行数を超えている) 1347|【補足】 1348|・src の改行コードは、Win, Mac, Unix のどれにも対応しています。 1349|************************************************************************/ 1350|char* StrX_refTopOfLine( const char* src, int iLine ) 1351|{ 1352| char* p = (char*)src; 1353| 1354| while ( iLine >= 2 ) { 1355| p = StrX_strchrs( p, "\n\r" ); 1356| if ( p == NULL ) return NULL; 1357| if ( *p == '\r' ) { 1358| if ( *(p + 1) == '\n' ) p += 2; 1359| else p ++; 1360| } 1361| else { 1362| if ( *(p + 1) == '\r' ) p += 2; 1363| else p ++; 1364| } 1365| iLine --; 1366| } 1367| 1368| return p; 1369|} 1370| 1371| 1372|/*********************************************************************** 1373| 7-20. <<< [StrX_getILine] 行番号を返す >>> 1374|【引数】 1375| ・char* s; 改行入り文字列 1376| ・char* p; s の中の行番号を取得したい位置 1377| ・int 返り値; 行番号(1〜) 1378|【補足】 1379|・src の改行コードは、Win, Mac, Unix のどれにも対応しています。 1380|************************************************************************/ 1381|int StrX_getILine( const char* s, const char* p ) 1382|{ 1383| char* ps = (char*)s; 1384| int iLine = 0; 1385| 1386| for (;;) { 1387| ps = StrX_strchrs( ps, "\n\r" ); 1388| if ( ps == NULL ) return iLine + 1; 1389| if ( *ps == '\r' ) { 1390| if ( *(ps + 1) == '\n' ) ps += 2; 1391| else ps ++; 1392| } 1393| else { 1394| if ( *(ps + 1) == '\r' ) ps += 2; 1395| else ps ++; 1396| } 1397| iLine ++; 1398| if ( p < ps ) return iLine; 1399| } 1400| 1401| return 0; 1402|} 1403| 1404| 1405|/************************************************************************** 1406| 7-21. <<< [StrX_getCIdent] C 言語の識別子を検索して格納する >>> 1407|【引数】 1408| ・char* src; ワードを含む検索対象の文字列 1409| ・char* ident; 読み込んだ識別子を格納するアドレス 1410| ・size_t ident_sizeof; ident のメモリサイズ 1411| ・char* 返り値; ident の次の src 中の位置 1412|【補足】 1413|・C 言語の識別子が無かったら NULL が返ります。 1414|【例】 1415|・"123_abc-def" なら、ident=="_abc", 返り値==&"-def" 1416|**************************************************************************/ 1417|char* StrX_getCIdent( const char* src, char* ident, int ident_sizeof ) 1418|{ 1419| char* ident_last = ident + ident_sizeof - 1; 1420| 1421| /* s を C言語の識別子の先頭にポイントする */ 1422| while ( (! isalpha( *src ) && *src != '_') || _ismbblead( *src ) ) { 1423| if ( *src == '\0' ) return NULL; 1424| if ( _ismbblead( *src ) ) src++; 1425| src ++; 1426| } 1427| 1428| /* ident に識別子を格納する */ 1429| while ( ident < ident_last ) { 1430| *ident = *src; 1431| ident ++; src ++; 1432| if ( ! isalpha( *src ) && ! isdigit( *src ) && *src != '_' ) 1433| break; 1434| } 1435| 1436| /* ident の最後に '\0' 文字を付ける */ 1437| *ident = '\0'; 1438| 1439| return (char*)src; 1440|} 1441| 1442| 1443| 1444|/************************************************************************** 1445| 7-22. <<< [StrX_getCIdent2] 文字列中の C 言語識別子か漢字を検索して格納する >>> 1446|【引数】 1447| ・char* src; ワードを含む検索対象の文字列 1448| ・char* ident; 読み込んだ識別子を格納するアドレス 1449| ・size_t ident_sizeof; ident のメモリサイズ 1450| ・char* 返り値; src の中の拡張ワードの直後のアドレス 1451|【補足】 1452|・本関数が検索する「ワード」は、C 言語識別子か全角文字(1文字)です。 1453| C 言語識別子と全角文字が連続している場合、別のワードになります。 1454|・拡張ワードが無かったら NULL が返ります。 1455|【例】 1456|・"123_abc-def" なら、ident=="_abc", 返り値=="-def" 1457|・"X123_abc-def" なら、ident=="X123_abc", 返り値=="-def)" 1458|・"*(123_abc-def)" なら、ident=="def", 返り値==")" 1459|・" word next " なら、ident=="word", 返り値==" next" 1460|・"漢字kan2、ok" なら、ident=="漢", 返り値=="字kan2、ok" 1461|**************************************************************************/ 1462|char* StrX_getCIdent2( const char* src, char* ident, int ident_sizeof ) 1463|{ 1464| char* ident_last = ident + ident_sizeof - 1; 1465| 1466| /* s をワードの先頭にポイントする */ 1467| while ( ! isalpha( *src ) && *src != '_' && ! _ismbblead( *src ) ) { 1468| if ( *src == '\0' ) return NULL; 1469| src ++; 1470| } 1471| 1472| /* ident に C 言語識別子を格納する */ 1473| if ( isalpha( *src ) || *src == '_' ) { 1474| 1475| while ( ident < ident_last ) { 1476| *ident = *src; 1477| ident ++; src ++; 1478| if ( ! isalpha( *src ) && ! isdigit( *src ) && *src != '_' ) 1479| break; 1480| } 1481| *ident = '\0'; 1482| } 1483| 1484| /* ident に漢字を格納する */ 1485| else { 1486| if ( ident + 2 <= ident_last ) { 1487| *ident++ = *src++; 1488| *ident++ = *src++; 1489| *ident = '\0'; 1490| } 1491| } 1492| 1493| return (char*)src; 1494|} 1495| 1496| 1497| 1498|/************************************************************************** 1499| 7-23. <<< [StrX_getToken] 文字列中のトークンか漢字を検索して格納する >>> 1500|【引数】 1501| ・char* src; ワードを含む検索対象の文字列 1502| ・char* token; 読み込んだ識別子を格納するアドレス 1503| ・size_t token_sizeof; token のメモリサイズ 1504| ・char* 返り値; src の中の拡張ワードの直後のアドレス 1505|【補足】 1506|・非トークンは、空白、タブ、改行、制御文字(0x01〜0x1F)です。 1507|・複数のトークンの取得は、StrX_getIdiom2 関数を使います。 1508|【例】 1509|・" word next " なら、token=="word", 返り値==" next"(トークン) 1510|・"123_abc-def" なら、token=="123", 返り値=="_abc-def"(数字) 1511|・" 0x123_abc-def" なら、token=="0x123", 返り値=="_abc-def"(16進数) 1512|・"\nX123_abc-def" なら、token=="X123_abc", 返り値=="-def)"(識別子) 1513|・"*(123_abc-def)" なら、token=="*", 返り値=="(123_abc-def)"(記号) 1514|・" 漢字kan2、ok" なら、token=="漢", 返り値=="字kan2、ok"(漢字) 1515|**************************************************************************/ 1516|char* StrX_getToken( const char* src, char* token, int token_sizeof ) 1517|{ 1518| char* token_last = token + token_sizeof - 1; 1519| 1520| /* s をトークンの先頭にポイントする */ 1521| while ( *src <= ' ' && *src > '\0' ) { 1522| src ++; 1523| } 1524| if ( *src == '\0' ) return NULL; 1525| 1526| 1527| /* token にトークンを格納する */ 1528| if ( src[0] == '0' && src[1] == 'x' ) { /* 16進数 */ 1529| if ( token + 2 <= token_last ) { 1530| token[0] = '0'; token[1] = 'x'; 1531| src += 2; 1532| while ( token < token_last && isdigit( *src ) ) { 1533| *token = *src; 1534| token ++; src ++; 1535| } 1536| *token = '\0'; 1537| } 1538| } 1539| else if ( isdigit( *src ) ) { /* 数値 */ 1540| if ( token + 1 <= token_last ) { 1541| do { 1542| *token = *src; 1543| token ++; src ++; 1544| } while ( token < token_last && isdigit( *src ) ); 1545| *token = '\0'; 1546| } 1547| } 1548| else if ( _ismbblead( *src ) ) { /* 漢字 */ 1549| if ( token + 2 <= token_last ) { 1550| *token++ = *src++; 1551| *token++ = *src++; 1552| *token = '\0'; 1553| } 1554| } 1555| else if ( isalpha( *src ) || *src == '_' ) { /* C言語識別子 */ 1556| while ( token < token_last ) { 1557| *token = *src; 1558| token ++; src ++; 1559| if ( ! isalpha( *src ) && ! isdigit( *src ) && *src != '_' ) 1560| break; 1561| } 1562| *token = '\0'; 1563| } 1564| else { /* 記号 */ 1565| if ( token + 1 <= token_last ) { 1566| *token = *src; 1567| token ++; src ++; 1568| *token = '\0'; 1569| } 1570| } 1571| 1572| return (char*)src; 1573|} 1574| 1575| 1576| 1577|/*********************************************************************** 1578| 7-24. <<< [StrX_getCSSValueOfInt] CSSのパラメータの値を整数型で取得する >>> 1579|【引数】 1580| ・char* css; CSSのパラメータ文の列 1581| ・char* attr_name; 属性の名前 1582| ・int* pValue; 属性の値を格納するアドレス 1583| ・bool 返り値; 指定の名前の属性があったかどうか 1584|【補足】 1585|・CSS は、Cascading Style Sheet の略です。 1586|・CSS の例:"fill:rgb(192,192,255);stroke:rgb(0,0,128);stroke-width:1" 1587|・CSS は、属性名と値の間に':', 文と文の間に';' を記述します。 1588|・指定の名前の属性がなかったら *pValue の値は変わりません。 1589|************************************************************************/ 1590|bool StrX_getCSSValueOfInt( const char* css, const char* attr_name, 1591| int* pValue ) 1592|{ 1593| bool ret; 1594| char str[16]; 1595| 1596| ret = StrX_getCSSValueOfStr( css, attr_name, str, sizeof(str) ); 1597| if ( ret ) *pValue = atoi( str ); 1598| 1599| return ret; 1600|} 1601| 1602| 1603| 1604|/*********************************************************************** 1605| 7-25. <<< [StrX_getCSSValueOfDouble] CSSのパラメータの値を倍精度浮動小数型で取得する >>> 1606|【引数】 1607| ・char* css; CSSのパラメータ文の列 1608| ・char* attr_name; 属性の名前 1609| ・double* pValue; 属性の値を格納するアドレス 1610| ・bool 返り値; 指定の名前の属性があったかどうか 1611|【補足】 1612|・StrX_getCSSValueOfDouble の倍精度浮動小数版です。 1613|************************************************************************/ 1614|#ifdef FOR_WIN32 1615|bool StrX_getCSSValueOfDouble( const char* css, const char* attr_name, 1616| double* pValue ) 1617|{ 1618| bool ret; 1619| char str[16]; 1620| 1621| ret = StrX_getCSSValueOfStr( css, attr_name, str, sizeof(str) ); 1622| if ( ret ) *pValue = atof( str ); 1623| 1624| return ret; 1625|} 1626|#endif 1627| 1628| 1629| 1630|/*********************************************************************** 1631| 7-26. <<< [StrX_getCSSValueOfStr] CSSのパラメータの値を文字列で取得する >>> 1632|【引数】 1633| ・char* css; CSSのパラメータ文の列 1634| ・char* attr_name; 属性の名前 1635| ・char* str; 属性の値を格納するアドレス 1636| ・int str_size; str のサイズ(バイト) 1637| ・bool 返り値; 指定の名前の属性があったかどうか 1638|【補足】 1639|・StrX_getCSSValueOfInt の文字列版です。 1640|************************************************************************/ 1641|bool StrX_getCSSValueOfStr( const char* css, const char* attr_name, 1642| char* str, int str_size ) 1643|{ 1644| char* p = (char*)css; 1645| char* p2; 1646| int attr_name_len = strlen( attr_name ); 1647| 1648| for (;;) { 1649| while ( isspace( *p ) ) p++; 1650| if ( strnicmp( p, attr_name, attr_name_len ) != 0 ) goto next_param; 1651| 1652| p += attr_name_len; 1653| while ( isspace( *p ) ) p++; 1654| if ( *p != ':' ) goto next_param; 1655| 1656| p++; 1657| while ( isspace( *p ) ) p++; 1658| p2 = p; 1659| while ( *p2 != ';' && *p2 != '\0' ) p2++; 1660| do { 1661| p2--; 1662| } while ( isspace( *p2 ) ); 1663| 1664| p2 ++; 1665| if ( p2 - p >= str_size ) /* p2 - p > str_size - 1 */ 1666| p2 = p + str_size - 1; 1667| strncpy( str, p, p2 - p ); 1668| str[ p2 - p ] = '\0'; 1669| return true; 1670| 1671| next_param: 1672| while ( *p != ';' ) { 1673| if ( *p == '\0' ) return false; 1674| p++; 1675| } 1676| p++; 1677| } 1678|} 1679| 1680| 1681| 1682|/*********************************************************************** 1683| 7-27. <<< [StrX_getCSSValueOfColor] CSSのパラメータの値を色で取得する >>> 1684|【引数】 1685| ・char* css; CSSのパラメータ文の列 1686| ・char* attr_name; 属性の名前 1687| ・Color_WinRGB* pColor; 属性の値を格納するアドレス 1688| ・bool 返り値; 指定の名前の属性があったかどうか 1689|【補足】 1690|・StrX_getCSSValueOfInt の色指定版です。 1691|・色は、次のフォーマットで指定します。"rgb(R,G,B)", "rgb(192,192,255)" 1692|************************************************************************/ 1693|#ifdef USES_COLOR 1694|bool StrX_getCSSValueOfColor( const char* css, const char* attr_name, 1695| Color_WinRGB* pColor ) 1696|{ 1697| bool ret; 1698| char str[32]; 1699| 1700| ret = StrX_getCSSValueOfStr( css, attr_name, str, sizeof(str) ); 1701| if ( ret ) { 1702| *pColor = StrX_getColorValue( str ); 1703| } 1704| 1705| return ret; 1706|} 1707|#endif 1708| 1709| 1710| 1711|/*********************************************************************** 1712| 7-28. <<< [StrX_getNumOfKWord] 文字列の中にキーワードがいくつあるか数える >>> 1713|【引数】 1714| ・char* s; 検索対象になる文字列 1715| ・char* kword; カウントするキーワード 1716| ・bool bCase; 大文字小文字を区別するかどうか 1717| ・int 返り値; キーワードの数 1718|************************************************************************/ 1719|int StrX_getNumOfKWord( const char* s, const char* kword, bool bCase ) 1720|{ 1721| const char* p; 1722| int n = 0; 1723| int kword_len = strlen( kword ); 1724| 1725| p = s; 1726| while ( (p = StrX_stristr3( p, kword, bCase, NULL )) != NULL ) { 1727| n++; 1728| p += kword_len; 1729| } 1730| 1731| return n; 1732|} 1733| 1734| 1735| 1736|/*********************************************************************** 1737| 7-29. <<< [StrX_getSVGPoints] SVG の polygon の points 属性を解析する >>> 1738|【引数】 1739| ・char* points; SVG の polygon の points 属性 1740| ・int* xs, ys; (出力)座標の配列 1741| ・int n; xs, ys の最大可能要素数 1742| ・bool 返り値; 頂点数 1743|【補足】 1744|・points の例:"10,10 20,20 30,30" ... 3頂点 1745|・points が n より多い頂点数のとき、n 個の頂点まで xs, ys に格納され、 1746| 返り値は、points に格納されている頂点数になります。 1747|************************************************************************/ 1748|int StrX_getSVGPoints( const char* points, int* xs, int* ys, int n ) 1749|{ 1750| const char* p = points; 1751| int np = 0; 1752| 1753| while ( isdigit( *p ) ) { 1754| if ( np < n ) *xs = atoi( p ); 1755| p = strchr( p, ',' ); if ( p == NULL ) break; 1756| p = StrX_strchrs_not( p, " \t\r\n" ); if ( p == NULL ) break; 1757| if ( np < n ) *ys = atoi( p+1 ); 1758| p = StrX_strchrs( p, " \t\r\n" ); 1759| xs++; ys++; np++; 1760| if ( p == NULL ) break; 1761| p = StrX_strchrs_not( p, " \t\r\n" ); 1762| if ( p == NULL ) break; 1763| } 1764| 1765| return np; 1766|} 1767| 1768| 1769| 1770|/************************************************************************** 1771| 7-30. <<< [StrX_getIdiom2] 文字列中のイディオムを検索して指定ワード数まで格納する >>> 1772|【引数】 1773| ・char* src; イディオムを含む検索対象の文字列 1774| ・int mWord; 最大のワード数 1775| ・int* nWord; (出力)格納したワード数 1776| ・char* idiom; イディオムを格納するアドレス 1777| ・int idiom_size; idiom のメモリサイズ 1778| ・int 返り値; src 中のイディオムの直後のアドレス 1779|【補足】 1780|・ここで言う「イディオム」は、英熟語だけでなく、漢字(2バイト文字)文字列も 1781| 含みます。イディオムを構成するワードについては、StrX_getToken 1782| 関数を参照してください。 1783|・半角空白文字は、イディオムの区切りにはなりません。 1784|・半角文字と全角文字が混ざったものも1つのイディオムになります。 1785|**************************************************************************/ 1786|char* StrX_getIdiom2( const char* src, int mWord, int* pnWord, 1787| char* idiom, int idiom_size ) 1788|{ 1789| int n; 1790| int nWord = 0; 1791| 1792| while ( idiom_size > 0 && nWord < mWord ) { 1793| 1794| /* 1ワード格納する */ 1795| src = StrX_getToken( src, idiom, idiom_size ); 1796| if ( src == NULL ) { 1797| break; 1798| } 1799| nWord ++; 1800| n = strlen( idiom ); idiom += n; idiom_size -= n; 1801| 1802| /* 次のイディオムへ */ 1803| if ( *src == ' ' ) { 1804| if ( idiom_size == 0 ) break; 1805| src ++; 1806| *idiom = ' '; idiom ++; 1807| idiom_size --; 1808| } 1809| else if ( *src >= '\0' && *src < ' ' ) 1810| break; 1811| } 1812| 1813| /* ワードが取得できなかったとき、末尾に加えた */ 1814| /* ワードの区切り空白文字をカットする */ 1815| if ( nWord >= 1 ) { 1816| do { 1817| idiom --; 1818| } while ( *idiom == ' ' ); 1819| *( idiom + 1 ) = '\0'; 1820| } 1821| *pnWord = nWord; 1822| 1823| return (char*)src; 1824|} 1825| 1826| 1827| 1828|/************************************************************************** 1829| 7-31. <<< [StrX_searchInArr] 文字列配列の中から検索する >>> 1830|【引数】 1831| ・char* s; 検索する文字列 1832| ・char** arr; 文字列配列の先頭アドレス(char* [] のアドレス) 1833| ・int arr_n; 配列 arr の要素数 1834| ・char** 返り値; 見つかった文字列へのアドレス(arr 配列内), NULL=ない 1835|***************************************************************************/ 1836|#if 0 1837|char** StrX_searchInArr( const char* s, char** arr, int arr_n ) 1838|{ 1839| while ( arr_n > 0 ) { 1840| if ( strcmp( s, *arr ) == 0 ) return arr; 1841| arr ++; 1842| arr_n --; 1843| } 1844| return NULL; 1845|} 1846|#endif 1847| 1848| 1849| 1850|/************************************************************************** 1851| 7-32. <<< [StrX_searchInArr2] 文字列配列の中から検索する >>> 1852|【引数】 1853| ・char* s; 検索する文字列 1854| ・char** arr; 文字列配列の先頭アドレス(char* [] のアドレス) 1855| ・int arr_size; ポインタ配列 arr のメモリサイズ 1856| ・char** 返り値; 見つかった文字列へのアドレス(arr 配列内), NULL=ない 1857|***************************************************************************/ 1858|char** StrX_searchInArr2( const char* s, const char** arr, int arr_size ) 1859|{ 1860| const char** arr_over = (const char**)( (const char*)arr + arr_size ); 1861| ASSERT( arr_size > 0 ); 1862| 1863| do { 1864| if ( strcmp( s, *arr ) == 0 ) return (char**)arr; 1865| arr ++; 1866| } while ( arr < arr_over ); 1867| 1868| return NULL; 1869|} 1870| 1871| 1872| 1873|/*-------------------------------------------------------------------------*/ 1874|/* ◆8. <<<< (StrX) char* 型の文字列(置換・文字コード変換) >>>> */ 1875|/*-------------------------------------------------------------------------*/ 1876| 1877| 1878| 1879|/*********************************************************************** 1880| 8-1. <<< [StrX_rep1] 1文字同士を置換する >>> 1881|【引数】 1882| ・char* s; 置換される文字列 1883| ・char f; 置換前の文字 1884| ・char t; 置換後の文字 1885| ・char* 返り値; s と同じ 1886|【補足】 1887|・2バイト文字の場合、StrX_rep1b を用いてください。 1888|************************************************************************/ 1889|char* StrX_rep1( char* s, char f, char t ) 1890|{ 1891| char* ret = s; 1892| 1893| while ( *s != '\0' ) { 1894| if ( *s == f ) *s = t; 1895| s++; 1896| } 1897| 1898| return ret; 1899|} 1900| 1901| 1902| 1903|/*********************************************************************** 1904| 8-2. <<< [StrX_rep1b] 1文字同士を置換する(2バイト文字対応)>>> 1905|【引数】 1906| ・char* s; 置換される文字列 1907| ・char f; 置換前の文字 1908| ・char t; 置換後の文字 1909| ・char* 返り値; s と同じ 1910|************************************************************************/ 1911|char* StrX_rep1b( char* s, char f, char t ) 1912|{ 1913| char* ret = s; 1914| 1915| while ( *s != '\0' ) { 1916| if ( _ismbblead( *s ) ) s++; 1917| else if ( *s == f ) *s = t; 1918| s++; 1919| } 1920| 1921| return ret; 1922|} 1923| 1924| 1925| 1926|/*********************************************************************** 1927| 8-3. <<< [StrX_rep] 文字列同士を置換する >>> 1928|【引数】 1929| ・char* s; 内容を置換する文字列 1930| ・int s_sizeof; s のメモリサイズ 1931| ・char* f; 置換前の文字列 1932| ・char* t; 置換後の文字列 1933| ・char* 返り値; s と同じ 1934|************************************************************************/ 1935|char* StrX_rep( char* s, int s_sizeof, const char* f, const char* t ) 1936|{ 1937| int f_len = strlen( f ); 1938| int t_len = strlen( t ); 1939| int diff = t_len - f_len; /* 文字列長の差(増えるなら+)*/ 1940| int left = s_sizeof - strlen(s) - 1; /* 残りメモリ・サイズ */ 1941| char* p = s; 1942| char* p2; 1943| int move_len; 1944| 1945| while ( *p != '\0' ) { 1946| if ( strncmp( p, f, f_len ) == 0 ) { /* 置換する文字列を見つけたら */ 1947| 1948| /* 置換する文字より後の文字をスクロールする */ 1949| p2 = p + f_len; 1950| move_len = strlen(p2) + 1; 1951| if ( left < diff ) { /* s のメモリ領域を超える場合 */ 1952| s[s_sizeof - 1] = '\0'; 1953| move_len += left - diff - 1; 1954| } 1955| if ( move_len > 0 ) 1956| memmove( p2 + diff, p2, move_len ); 1957| left -= diff; 1958| 1959| /* 文字列を置換する */ 1960| if ( (p - s) + t_len < s_sizeof ) { 1961| memcpy( p, t, t_len ); 1962| p += t_len; 1963| } 1964| else 1965| break; 1966| } 1967| else 1968| p++; 1969| } 1970| return s; 1971|} 1972| 1973| 1974| 1975|/*********************************************************************** 1976| 8-4. <<< [StrX_repi] 数値を指定して置換する >>> 1977|【引数】 1978| ・char* s; 置換される文字列 1979| ・int s_sizeof; s のメモリサイズ 1980| ・char* f; 置換前の文字列 1981| ・int t; 置換後の文字列にする数値 1982| ・char* 返り値; s と同じ 1983|************************************************************************/ 1984|char* StrX_repi( char* s, int s_sizeof, const char* f, int t ) 1985|{ 1986| static char num[20]; 1987| 1988| sprintf( num, "%d", t ); 1989| return StrX_rep( s, s_sizeof, f, num ); 1990|} 1991| 1992| 1993| 1994|/*********************************************************************** 1995| 8-5. <<< [StrX_repEx] 文字列を複数項目の文字列に置換する >>> 1996|【引数】 1997| ・char* s; 内容を置換する文字列, 区切り文字は CSV形式 1998| ・int s_sizeof; s のメモリサイズ 1999| ・char* f; 置換前の文字列(区切り文字の指定位置に %i を指定) 2000| ・char* t; 置換後の文字列の集合(CSV 形式) 2001| ・StrX_ConvFunc term_conv_func; 区切り文字変換関数(→補足、NULL可) 2002| ・void* obj; term_conv_func の第1引数 2003| ・char* work; ワーク領域 2004| ・int work_size; work のメモリサイズ(→補足) 2005| ・char* 返り値; s と同じ, NULL=s 中の f がおかしい 2006|【補足】 2007|・term_conv_func は、スキャンした区切り文字を変換する関数です。 2008| たとえば、区切り文字に変数名を指定することができるようになります。 2009| NULL にすると、変換関数を呼び出しません(変換しません)。 2010| term_conv_func の関数の型は次のとおりです。 2011| void term_conv_func( char* term, int term_size ); 2012|・work_size は、(f の文字数+1) * 2 + (置換後の CSV 文字列の項目の 2013| うち、最大の文字数 + 1)が必要です。不足したときはエラーになります。 2014|【例】 2015| StrX_repEx( "zzzz$(\"; \")zzzz", 256, "$(%i)", "abc,123" ); 2016| 置換後... "zzzzabc; 123zzzz" 2017|************************************************************************/ 2018|char* StrX_repEx( char* s, int s_sizeof, const char* f, const char* t, 2019| StrX_ConvFunc term_conv_func, void* obj, char* work, int work_size ) 2020|{ 2021| char* key1; /* f の %1 以前の文字列 */ 2022| int key_size; 2023| int key1_len; 2024| char* key2; /* f の %1 以後の文字列 */ 2025| int key2_len; 2026| char* t_elem; /* 置換後の1項目の文字列 */ 2027| int t_elem_size; 2028| char* term; /* 区切り文字 */ 2029| int term_size; 2030| 2031| ASSERT( ! ( f[0] == '%' && f[1] == 'i' ) ); 2032| 2033| key1 = work; 2034| key_size = strlen( f ) + 1; 2035| work += key_size; 2036| key2 = work; work += key_size; 2037| term = work; work += key_size; 2038| term_size = key_size; 2039| t_elem = work; 2040| t_elem_size = work_size - 3 * key_size; 2041| 2042| { 2043| char* kp; /* key's pointer */ 2044| const char* fp1; /* f's pointer 1 */ 2045| const char* fp2; /* f's pointer 2 */ 2046| 2047| /* f の %1 より前の文字列を検索文字列 key1 とする */ 2048| kp = key1; 2049| fp1 = f; 2050| for (;;) { 2051| fp2 = StrX_strchr2( fp1, '%' ); 2052| ASSERT( fp2 != NULL ); 2053| strncpy( kp, fp1, fp2 - fp1 ); 2054| 2055| kp += fp2 - fp1; 2056| if ( *(fp2 + 1) != '%' ) break; 2057| *kp = '%'; 2058| kp++; 2059| fp1 = fp2 + 2; 2060| } 2061| ASSERT( *(fp2 + 1) == 'i' ); 2062| *kp = '\0'; 2063| key1_len = kp - key1; 2064| 2065| /* f の %1 より後の文字列を検索文字列 key2 とする */ 2066| kp = key2; 2067| fp1 = fp2 + 2; 2068| while ( *fp1 != '\0' ) { 2069| if ( *fp1 == '%' && *(fp1 + 1) == '%' ) fp1++; 2070| *kp = *fp1; 2071| kp++; fp1++; 2072| } 2073| *kp = '\0'; 2074| key2_len = kp - key2; 2075| } 2076| 2077| /* 置換を行う */ 2078| { 2079| int left = s_sizeof - strlen(s) - 1; /* 残りメモリ・サイズ */ 2080| int term_len; 2081| char* sp; /* s's pointer */ 2082| char* sp2; 2083| int zeroCh; 2084| int diff; 2085| int move_len; 2086| int i; 2087| 2088| sp = s; 2089| while ( *sp != '\0' ) { 2090| if ( strncmp( sp, key1, key1_len ) == 0 ) { /* 検索文字列を見つけたら */ 2091| 2092| /* 区切り文字を term に代入する */ 2093| sp2 = strstr( sp, key2 ); if ( sp2 == NULL ) return NULL; 2094| term_len = (sp2 - sp) - key1_len; 2095| if ( term_len >= term_size ) term_len = term_size - 1; 2096| strncpy( term, sp + key1_len, term_len ); 2097| *( term + term_len ) = '\0'; 2098| StrX_meltCSV( term, term ); 2099| if ( term_conv_func != NULL ) 2100| term_conv_func( obj, term, term_size ); 2101| term_len = strlen( term ); 2102| 2103| /* 置換後の文字列の長さを diff に代入する */ 2104| diff = 0; 2105| for ( i = 1; ; i++ ) { 2106| if ( StrX_getCSV( t, i, t_elem, t_elem_size ) == NULL ) 2107| break; 2108| if ( i >= 2 ) diff += term_len; 2109| diff += strlen( t_elem ); 2110| } 2111| 2112| /* 置換する文字より後の文字をスクロールする */ 2113| sp2 += key2_len; 2114| diff -= sp2 - sp; 2115| move_len = strlen(sp2) + 1; 2116| if ( left < diff ) { /* s のメモリ領域を超える場合 */ 2117| s[s_sizeof - 1] = '\0'; 2118| move_len += left - diff - 1; 2119| } 2120| memmove( sp2 + diff, sp2, move_len ); 2121| left -= diff; 2122| sp2 += diff; 2123| zeroCh = *sp2; 2124| 2125| /* 文字列を置換する */ 2126| for ( i = 1; ; i++ ) { 2127| if ( StrX_getCSV( t, i, t_elem, t_elem_size ) == NULL ) 2128| break; 2129| if ( i >= 2 ) 2130| { strncpy( sp, term, term_len ); sp += term_len; } 2131| strcpy( sp, t_elem ); 2132| sp = strchr( sp, '\0' ); 2133| } 2134| *sp = zeroCh; 2135| } 2136| else 2137| sp++; 2138| } 2139| } 2140| return s; 2141|} 2142| 2143| 2144| 2145|/*********************************************************************** 2146| 8-6. <<< [StrX_repSharp] #を数字に置換する >>> 2147|【引数】 2148| ・char* s; #を含んだ文字列 2149| ・int s_sizeof; s のメモリサイズ 2150| ・int n; #から置き換える数字 2151| ・char* 返り値; s と同じ 2152|【補足】 2153|・例:s="image##.jpg", n=4 のとき s="image04.jpg" 2154|・# を置換した文字列が s_sizeof より大きくなるときは、NULLを返します。 2155|************************************************************************/ 2156|char* StrX_repSharp( char* s, int s_sizeof, int n ) 2157|{ 2158| int nSharp; 2159| char* pSharp; 2160| char* pSharp2; 2161| char format[16]; 2162| char num_s[16]; 2163| 2164| pSharp = StrX_strchr2( s, '#' ); 2165| if ( pSharp == NULL ) return s; 2166| pSharp2 = pSharp; 2167| while( *pSharp2 == '#' ) pSharp2++; 2168| nSharp = pSharp2 - pSharp; 2169| 2170| if ( (int)strlen( s ) + 13 - nSharp > s_sizeof ) return NULL; 2171| 2172| sprintf( format, "%%0%dd", nSharp ); 2173| sprintf( num_s, format, n ); 2174| StrX_del( pSharp, nSharp ); 2175| StrX_ins( pSharp, num_s ); 2176| 2177| return s; 2178|} 2179| 2180| 2181| 2182|/********************************************************************* 2183| 8-7. <<< [StrX_sjis2jis] JIS外字コードへの変換 >>> 2184| 作成日 1995.12.28 2185| 関数名 sjistojis 2186| 機能 拡張シフトJISコード→JIS外字コードへの変換 2187| 引数 int code シフトJISコード 2188| 返り値 JISコード 2189| ※半角コード、記号コードは同じコードを返す 2190|*********************************************************************/ 2191|unsigned short StrX_sjis2jis( unsigned short code ) 2192|{ 2193| register unsigned char ah, al; 2194| register unsigned short ax; 2195| ah = (unsigned char)(code >> 8); 2196| al = (unsigned char)(code & 0xff); 2197| ah = ah +ah; 2198| al -= 0x1f; 2199| if( !(al & 0x80) ) { 2200| if( al <= 0x5f && al >= 0x21 ) { 2201| al++; 2202| } 2203| al += 0xde; 2204| } 2205| ax = ( ah << 8 ) + al; 2206| ax = ax + 0x1fa1; 2207| ax = ax & 0x7f7f; 2208| return (ax); 2209|} 2210| 2211| 2212| 2213|/************************************************************************ 2214| 8-8. <<< [StrX_getCodeT] 漢字コードの種類を返す >>> 2215|【引数】 2216| ・const unsigned char* s; 漢字コードの種類を判定する文字列の先頭アドレス 2217| ・int 返り値; 漢字コードの種類(StrX_CodeT型) 2218|【機能】 2219|・文字列 s の漢字コードの種類を返します。 2220|【補足】 2221|・返り値は、StrX_Ascii, StrX_Jis, StrX_ShiftJis, StrX_Euc のうちどれかが 2222| 返ります。 2223|・作成日:97.12.27 2224|*************************************************************************/ 2225|int StrX_getCodeT( const unsigned char* s ) 2226|{ 2227| while ( *s != '\0' ) { 2228| 2229| if ( *s == StrX_ESC ) { 2230| if ( *(s+1) == '$' && 2231| ( *(s+2)=='@' || *(s+2)=='B' ) ) 2232| return StrX_Jis; 2233| 2234| if ( *(s+1) == '(' && *(s+2)=='I' ) 2235| return StrX_Euc; 2236| } 2237| else if ( *s == 0x8E ) { 2238| if ( 0x40 <= *(s+1) && *(s+1) <= 0xEC && *(s+1) != 0x7F ) 2239| return StrX_ShiftJis; 2240| else 2241| return StrX_Euc; 2242| } 2243| else if ( 0x80 <= *s && *s <= 0x9F ) 2244| return StrX_ShiftJis; 2245| 2246| else if ( 0xA0 <= *s ) 2247| return StrX_Euc; 2248| 2249| s++; 2250| } 2251| return StrX_Ascii; 2252|} 2253| 2254| 2255| 2256|/************************************************************************ 2257| 8-9. <<< [StrX_toSJIS] 任意の漢字コードを shift JIS に変換する >>> 2258|【引数】 2259| ・char* out; shift JIS の文字列を格納するアドレス 2260| ・const char* in; 任意の漢字コードの文字列 2261| ・char* 返り値; out と同じ 2262|【補足】 2263|・out の領域は、in と同じかそれ以上のサイズにします。 2264|*************************************************************************/ 2265|char* StrX_toSJIS( char* out, const char* in ) 2266|{ 2267| bool bSISO = false, bKanji = false; 2268| 2269| switch ( StrX_getCodeT( (const unsigned char*)in ) ) { 2270| case StrX_Ascii: 2271| case StrX_ShiftJis: 2272| strcpy( out, in ); 2273| break; 2274| case StrX_Jis: 2275| StrX_jis2sjis( (unsigned char*)out, (const unsigned char*)in, 2276| &bSISO, &bKanji ); 2277| break; 2278| case StrX_Euc: 2279| StrX_euc2sjis( (unsigned char*)out, (const unsigned char*)in, 2280| &bSISO ); 2281| break; 2282| } 2283| return out; 2284|} 2285| 2286| 2287| 2288|/************************************************************************ 2289| 8-10. <<< [StrX_jis2sjis] JIS 漢字コードを shift JIS に変換する >>> 2290|【引数】 2291| ・unsigned char* out; shift JIS 漢字コードの文字列を格納する先頭アドレス 2292| ・unsigned char* in; JIS 漢字コードの文字列 2293| ・bool* bSISO; SI/SO 状態(入出力), SI から SO の間なら true 2294| ・bool* bKanji; 漢字 IN/OUT 状態(入出力), 漢字なら true 2295| ・int 返り値; in の未処理バイト数 2296|【機能】 2297|・JIS コードの文字列 in を shift JIS コードに変換した文字列を out に 2298| 格納します。 2299|【補足】 2300|・out の領域は、in と同じかそれ以上のサイズにします。 2301|・返り値は、in の末尾に、漢字 IN/OUT コードの一部や、2バイトコードの 2302| 一部があるときに、0 より大きい値が返ります。 2303|・bSISO, bKanji は、どちらも false から始めます。 2304|・作成日:97.12.27 2305|*************************************************************************/ 2306|int StrX_jis2sjis( unsigned char* out, const unsigned char* in, 2307| bool* bSISO, bool* bKanji ) 2308|{ 2309| unsigned char in0, in1, in2; 2310| const unsigned char* prev_in; 2311| 2312| /* EUC 文字列の上を in が走査しながら変換する */ 2313| while ( *in != '\0' ) { 2314| 2315| /* SI/SO, 漢字 IN/OUT コードを続けて処理する */ 2316| do { 2317| prev_in = in; 2318| 2319| /* in のシフトビットを取り除いたものを in0〜in2 へ取得する */ 2320| in0 = in[0] & 0x7F; in1 = in[1] & 0x7F; in2 = in[2] & 0x7F; 2321| 2322| switch ( in0 ) { 2323| 2324| /* SI/SO コードを処理する */ 2325| case StrX_SI: *bSISO = true; *bKanji = false; in++; break; 2326| case StrX_SO: *bSISO = false; *bKanji = false; in++; break; 2327| 2328| /* 漢字 IN/OUT コードを処理する */ 2329| case StrX_ESC: 2330| if ( in1 == '$' ) { 2331| if ( in2=='@' || in2=='B' ) 2332| { *bSISO = false; *bKanji = true; in+=3; } 2333| else if ( in[2] == '\0' ) 2334| { *out = '\0'; return 2; } 2335| } 2336| else if ( in1 == '(' ) { 2337| if ( in2 == 'H' || in2 == 'B' || in2 == 'J' ) 2338| { *bSISO = false; *bKanji = false; in+=3; } 2339| else if ( in2 == 'I' ) 2340| { *bSISO = true; *bKanji = false; in+=3; } 2341| else if ( in[2] == '\0' ) 2342| { *out = '\0'; return 2; } 2343| } 2344| else if ( in[1] == '\0' ) 2345| { *out = '\0'; return 1; } 2346| 2347| break; 2348| } 2349| } while ( in != prev_in ); 2350| 2351| /* 1バイト出力 */ 2352| if ( ! *bKanji ) { 2353| if ( *bSISO && ( in0 > 0x20 && in0 < 0x60 ) ) 2354| *out = in0 | 0x80; 2355| else *out = in0; 2356| in ++; out ++; 2357| } 2358| else if ( in0 < 0x21 || in0 > 0x7e ) 2359| { *out = in0; in++; out++; } 2360| 2361| /* 2バイト出力 */ 2362| else { 2363| unsigned char preCode, postCode; 2364| unsigned int code; 2365| 2366| if ( in[1] == '\0' ) 2367| { *out = '\0'; return 1; } 2368| 2369| code = ( (in0 - 0x21)* 0x5E ) + in1 - 0x21; 2370| preCode = code / 0xBC + 0x81; if ( preCode > 0x9F ) preCode += 0x40; 2371| postCode = code % 0xBC + 0x40; if ( postCode > 0x7E ) postCode ++; 2372| 2373| *out = preCode; out++; *out = postCode; out++; 2374| in +=2; 2375| } 2376| } 2377| 2378| *out = '\0'; 2379| return 0; 2380|} 2381| 2382| 2383| 2384|/*************************************************************************** 2385| 8-11. <<< [StrX_euc2sjis] EUC 漢字コードを shift JIS 変換する >>> 2386|【引数】 2387| ・unsigned char* out; shift JIS 漢字コードの文字列を格納する先頭アドレス 2388| ・unsigned char* in; EUC 漢字コードの文字列 2389| ・bool* bSISO; SI/SO 状態(入出力), SI から SO の間なら true 2390| ・int 返り値; in の未処理バイト数 2391|【機能】 2392|・EUC コードの文字列 in を shift JIS コードに変換した文字列を out に 2393| 格納します。 2394|【補足】 2395|・out の領域は、in と同じかそれ以上のサイズにします。 2396|・返り値は、in の末尾に、漢字 IN/OUT コードの一部や、2バイトコードの 2397| 一部や 0x8E コードがあるときに、0 より大きい値が返ります。 2398|・bSISO は、false から始めます。 2399|・作成日:97.12.27 2400|***************************************************************************/ 2401|int StrX_euc2sjis( unsigned char* out, const unsigned char* in, 2402| bool* bSISO ) 2403|{ 2404| unsigned char in0, in1, in2; 2405| const unsigned char* prev_in; 2406| 2407| /* EUC 文字列の上を in が走査しながら変換する */ 2408| while ( *in != '\0' ) { 2409| 2410| /* SI/SO, 漢字 IN/OUT コードを続けて処理する */ 2411| do { 2412| prev_in = in; 2413| in0 = in[0]; in1 = in[1]; in2 = in[2]; 2414| 2415| switch ( in0 ) { 2416| 2417| /* SI/SO コードを処理する */ 2418| case StrX_SI: *bSISO = true; in++; break; 2419| case StrX_SO: *bSISO = false; in++; break; 2420| 2421| /* 漢字 IN/OUT コードを処理する */ 2422| case StrX_ESC: 2423| if ( in1 == '(' ) { /* '(' = 0x28 */ 2424| if ( in2 == 'I' ) { *bSISO = true; in +=3; } 2425| else if ( in2 == 'J' ) { *bSISO = false; in +=3; } 2426| else if ( in2 == '\0' ) 2427| { *out = '\0'; return 2; } 2428| } 2429| else if ( in1 == '\0' ) 2430| { *out = '\0'; return 1; } 2431| break; 2432| } 2433| } while ( in != prev_in ); 2434| 2435| /* 0x8E コードの処理 */ 2436| if ( in0 == 0x8E && (in1 > 0xA0 && in1 < 0xE0) ) 2437| in++; 2438| else if ( in0 == 0x8E && in1 == '\0' ) 2439| { *out = '\0'; return 1; } 2440| 2441| /* 1バイト出力 */ 2442| else if ( *bSISO && in0 < 0x80 ) { 2443| if ( in0 > 0x20 && in0 < 0x60 ) 2444| { *out = in0 | 0x80; out++; in++; } 2445| else 2446| { *out = in0; out++; in++; } 2447| } 2448| else if ( in0 < 0xA1 || in0 > 0xFE ) 2449| { *out = in0 & 0x7F; out++; in++; } 2450| 2451| /* 2バイト出力 */ 2452| else { 2453| unsigned char preCode, postCode; 2454| unsigned int code; 2455| unsigned char in0x = in0 & 0x7F; 2456| unsigned char in1x = in1 & 0x7F; 2457| 2458| if ( in1 == '\0' ) 2459| { *out = '\0'; return 1; } 2460| 2461| code = ( (in0x - 0x21)* 0x5E ) + in1x - 0x21; 2462| preCode = code / 0xBC + 0x81; if ( preCode > 0x9F ) preCode += 0x40; 2463| postCode = code % 0xBC + 0x40; if ( postCode > 0x7E ) postCode ++; 2464| 2465| *out = preCode; out++; *out = postCode; out++; 2466| in +=2; 2467| } 2468| } 2469| 2470| *out = '\0'; 2471| return 0; 2472|} 2473| 2474| 2475| 2476|/************************************************************************* 2477| 8-12. <<< [StrX_getJisIO] JIS 漢字 IN/OUT コードを判定する >>> 2478|【引数】 2479| ・char* s; JIS 漢字 IN/OUT コードか判定する文字の先頭アドレス 2480| ・int 返り値; 漢字 IN/OUT コードかどうかの判定(StrX_CodeT型) 2481|【補足】 2482|・返り値は、漢字 IN の場合 StrX_JisIn,漢字 OUT の場合 StrX_JisOut, 2483| その他の場合、0 です。 2484|・漢字 IN コードは、3バイトです。 2485|・漢字 OUT コードは、3バイトです。 2486|**************************************************************************/ 2487|int StrX_getJisIOType( const char* s ) 2488|{ 2489| if ( *s == StrX_ESC ) { 2490| s++; 2491| if ( *s == '$' ) { 2492| s++; 2493| if ( *s == '@' || *s == 'B' ) 2494| return StrX_JisIn; 2495| } 2496| else if ( *s == '(' ) { 2497| s++; 2498| if ( *s == 'H' || *s == 'B' || *s == 'J' || *s == 'I' ) 2499| return StrX_JisOut; 2500| } 2501| } 2502| return 0; 2503|} 2504| 2505| 2506| 2507|/*************************************************************************** 2508| 8-13. <<< [StrX_sjis2unicode] shift JIS 漢字コードを UNICODE へ変換する >>> 2509|【引数】 2510| ・unsigned short* unicodeStr; (出力)UNICODE 漢字コードの文字列を格納する先頭アドレス 2511| ・unsigned char* shiftJisStr; shift JIS 漢字コードの文字列 2512| ・int unicodeStr_size; unicodeStr の領域のメモリサイズ(バイト) 2513|【補足】 2514|・unicodeStr_size は、shiftJisStr の文字数またはバイト数の2倍あれば十分です。 2515|・shiftJisStr の最後が、2バイト文字の1バイト目で終わらないように注意してください。 2516|***************************************************************************/ 2517|#if defined(FOR_WIN32) || defined(FOR_DOS32) 2518|void StrX_sjis2unicode( unsigned short* unicodeStr, const char* shiftJisStr, 2519| int unicodeStr_size ) 2520|{ 2521| setlocale(LC_ALL, "Japanese"); 2522| MultiByteToWideChar( CP_OEMCP, MB_PRECOMPOSED, shiftJisStr, -1, 2523| unicodeStr, unicodeStr_size ); 2524|} 2525|#endif 2526| 2527| 2528| 2529|/*************************************************************************** 2530| 8-14. <<< [StrX_unicode2sjis] UNICODE 漢字コードを shift JIS へ変換する >>> 2531|【引数】 2532| ・unsigned char* shiftJisStr; (出力)shift JIS 漢字コードの文字列 2533| ・unsigned short* unicodeStr; UNICODE 漢字コードの文字列を格納する先頭アドレス 2534| ・int shiftJisStr_size; shiftJisStr の領域のメモリサイズ(バイト) 2535|【補足】 2536|・shiftJisStr_size は、unicodeStr と同じバイト数だけあれば十分です。 2537|・unicodeStr の最後が、文字の1バイト目で終わらないように注意してください。 2538|***************************************************************************/ 2539|#if defined(FOR_WIN32) || defined(FOR_DOS32) 2540|void StrX_unicode2sjis( unsigned char* shiftJisStr, const unsigned short* unicodeStr, 2541| int shiftJisStr_size ) 2542|{ 2543| setlocale(LC_ALL, "Japanese"); 2544| WideCharToMultiByte( CP_OEMCP, 0, unicodeStr, -1, 2545| shiftJisStr, shiftJisStr_size, NULL, NULL ); 2546|} 2547|#endif 2548| 2549| 2550| 2551|/*************************************************************************** 2552| 8-15. <<< [StrX_convIdxEdit2SJis] EditBox のインデックスを Shift JIS のものへ変換する >>> 2553|【引数】 2554| ・char* sjis_str; 対象となる文字列(Shift JIS) 2555| ・int uniIdx; EditBox でのインデックス 2556| ・short* work; ワーク領域。(sjis_str の文字数+1)の4倍以上のサイズが必要 2557| ・int work_size; work のサイズ(バイト) 2558| ・int 返り値; Shift JIS でのインデックス 2559|【補足】 2560|・"ABCあいう" の "い" のインデックスは、EditBox の場合 4、Shift JIS の場合 5です。 2561|・EditBox の改行は "\r\n" でも1文字分でカウントされます。 2562|***************************************************************************/ 2563|#if defined(FOR_WIN32) || defined(FOR_DOS32) 2564|int StrX_convIdxEdit2SJis( const char* sjis_str, int editIdx, unsigned short* work, 2565| int work_size ) 2566|{ 2567| unsigned short* work1; 2568| unsigned char* work2 = (unsigned char*)(work + work_size / 4); 2569| int nShort; 2570| int sjisIdx; 2571| int len; 2572| int plus; 2573| unsigned short c; 2574| 2575| StrX_sjis2unicode( work, sjis_str, work_size / 2 ); 2576| 2577| work1 = work; 2578| c = work1[editIdx]; 2579| work1[editIdx] = 0; 2580| 2581| sjisIdx = 0; 2582| for (;;) { 2583| plus = 0; 2584| if ( work1[editIdx - 1] == '\r' && c == '\n' ) { 2585| work1[editIdx] = c; 2586| editIdx ++; 2587| c = work1[editIdx]; 2588| work1[editIdx] = 0; 2589| plus = 1; 2590| } 2591| StrX_unicode2sjis( work2, work1, work_size / 2); 2592| 2593| nShort = StrX_getNumOfKWord( work2, "\r\n", true ); 2594| StrX_rep( work2, work_size, "\r\n", "\n" ); 2595| nShort += StrX_getNumOfKWord( work2, "\r", true ); 2596| StrX_rep( work2, work_size, "\r", "" ); 2597| 2598| len = strlen( work2 ); 2599| sjisIdx += len + nShort; 2600| 2601| if ( nShort <= plus ) break; 2602| if ( len == 0 ) { sjisIdx += nShort; break; } 2603| 2604| work1[editIdx] = c; 2605| work1 = work1 + editIdx; 2606| editIdx = nShort - plus; 2607| c = work1[editIdx]; 2608| work1[editIdx] = 0; 2609| } 2610| 2611| return sjisIdx; 2612|} 2613|#endif 2614| 2615| 2616| 2617|/*************************************************************************** 2618| 8-16. <<< [StrX_convSJis2IdxEdit] EditBox のインデックスへ Shift JIS のものから変換する >>> 2619|***************************************************************************/ 2620|#if defined(FOR_WIN32) || defined(FOR_DOS32) 2621|int StrX_convSJis2IdxEdit( const char* sjis_str, int sjisIdx ) 2622|{ 2623| char* s = (char*)sjis_str; 2624| int editIdx = 0; 2625| 2626| while ( sjisIdx > 0 ) { 2627| if ( _ismbblead( *s ) ) { 2628| editIdx++; sjisIdx-=2; s += 2; 2629| } 2630| else if ( *s == '\r' ) { 2631| if ( *(s+1) == '\n' ) { 2632| editIdx++; sjisIdx-=2; s += 2; 2633| } 2634| else { 2635| editIdx++; sjisIdx--; s ++; 2636| } 2637| } 2638| else if ( *s == '\n' ) { 2639| if ( *(s+1) == '\r' ) { 2640| editIdx++; sjisIdx-=2; s += 2; 2641| } 2642| else { 2643| editIdx++; sjisIdx--; s ++; 2644| } 2645| } 2646| else { 2647| editIdx++; sjisIdx--; s ++; 2648| } 2649| } 2650| 2651| return editIdx; 2652|} 2653|#endif 2654| 2655| 2656| 2657|/************************************************************************* 2658| 8-17. <<< [StrX_getHash] ハッシュ値を返す(大文字小文字を区別する) >>> 2659|【引数】 2660| ・char* s; ハッシュする文字列 2661| ・int width; ハッシュ値の幅 2662| ・int 返り値; ハッシュ値 2663|【補足】 2664|・返り値は、0〜(width-1) の範囲の整数です。 2665|・ハッシュ値は次のように用います。 2666| ・ハッシュテーブルに追加するとき 2667| int hash = StrX_getHash( obj->str, 100 ); // ハッシュ値を求めて 2668| Container_add( con[hash], obj ); // ハッシュ値番目のコンテナに入れる 2669| ・ハッシュテーブルから検索するとき 2670| int hash = StrX_getHash( obj->str, 100 ); // ハッシュ値を求めて 2671| Container_search( con[hash], key ); // ハッシュ値番目のコンテナを探す 2672|**************************************************************************/ 2673|int StrX_getHash( const char* s, int width ) 2674|{ 2675| unsigned int hash = 0; 2676| int i = 0; /* (-1)文字目 */ 2677| 2678| while ( s[i] != '\0' ) { 2679| hash += (int)(unsigned char)(s[i]) * (i+1); 2680| i++; 2681| } 2682| 2683| return hash % width; 2684|} 2685| 2686| 2687| 2688|/************************************************************************* 2689| 8-18. <<< [StrX_getHashI] ハッシュ値を返す(大文字小文字を区別しない) >>> 2690|【引数】 2691| ・char* s; ハッシュする文字列 2692| ・int width; ハッシュ値の幅 2693| ・int 返り値; ハッシュ値 2694|【補足】 2695|・大文字小文字の違いがあっても同じハッシュ値を返す StrX_getHash() です。 2696|**************************************************************************/ 2697|int StrX_getHashI( const char* s, int width ) 2698|{ 2699| unsigned int hash = 0; 2700| int i = 0; /* (-1)文字目 */ 2701| int c; 2702| 2703| while ( s[i] != '\0' ) { 2704| c = s[i]; 2705| if ( c <= 'Z' && c >= 'A' ) c += 0x20; 2706| hash += c * (i+1); 2707| i++; 2708| } 2709| 2710| return hash % width; 2711|} 2712| 2713| 2714| 2715|/************************************************************************* 2716| 8-19. <<< [StrX_toHtmlTxt] HTML 用のテキストに変換する >>> 2717|【引数】 2718| ・char* src; 元テキスト 2719| ・char* dst; HTML テキストを格納する領域の先頭アドレス 2720| ・int dst_size; dst の領域のサイズ 2721| ・char* 返り値; dst 2722|【補足】 2723|・HTML タグ文字である '<', '>', '&' を "<", ">", "&" に変換します。 2724|・src と dst は別の領域にしてください。 2725|・dst の領域を越える場合、残りは切り捨てます。 2726| その際でも、"<", ">", "&" の一部が残らないようになります。 2727|**************************************************************************/ 2728|char* StrX_toHtmlTxt( const char* src, char* dst, int dst_size ) 2729|{ 2730| char* dst_first = dst; 2731| char* dst_over = dst + dst_size; 2732| 2733| ASSERT( src < dst || src >= dst_over ); 2734| 2735| while ( *src != '\0' ) { 2736| switch ( *src ) { 2737| case '<': 2738| if ( dst + 4 >= dst_over ) goto exit_for; 2739| *dst = '&'; dst++; *dst = 'l'; dst++; 2740| *dst = 't'; dst++; *dst = ';'; dst++; 2741| break; 2742| case '>': 2743| if ( dst + 4 >= dst_over ) goto exit_for; 2744| *dst = '&'; dst++; *dst = 'g'; dst++; 2745| *dst = 't'; dst++; *dst = ';'; dst++; 2746| break; 2747| case '&': 2748| if ( dst + 5 >= dst_over ) goto exit_for; 2749| *dst = '&'; dst++; *dst = 'a'; dst++; 2750| *dst = 'm'; dst++; *dst = 'p'; dst++; 2751| *dst = ';'; dst++; 2752| break; 2753| default: 2754| if ( dst + 1 >= dst_over ) goto exit_for; 2755| if ( _ismbblead( *src ) ) 2756| { *dst = *src; dst++; src++; } 2757| *dst = *src; dst++; 2758| break; 2759| } 2760| src ++; 2761| } 2762|exit_for: 2763| *dst ='\0'; 2764| 2765| return dst_first; 2766|} 2767| 2768| 2769| 2770|/************************************************************************* 2771| 8-20. <<< [StrX_resumeFromHtmlTxt] HTML 用のテキストを元のテキストに戻す >>> 2772|【引数】 2773| ・char* src; HTML テキスト 2774| ・char* dst; 通常のテキストを格納する領域の先頭アドレス 2775| ・int dst_size; dst の領域のサイズ 2776| ・char* 返り値; dst 2777|【補足】 2778|・"<", ">", "&" を '<', '>', '&' に戻します。 2779|・src と dst は同じ領域アドレスでも構いません。 2780|**************************************************************************/ 2781|char* StrX_resumeFromHtmlTxt( const char* src, char* dst, int dst_size ) 2782|{ 2783| char* dst_first = dst; 2784| char* dst_over = dst + dst_size; 2785| 2786| ASSERT( src < dst || src >= dst_over || src == dst ); 2787| 2788| while ( *src != '\0' && dst < dst_over ) { 2789| if ( *src == '&' ) { 2790| if ( strncmp( src + 1, "lt;", 3 ) == 0 ) { 2791| *dst = '<'; 2792| src += 4; dst++; 2793| } 2794| else if ( strncmp( src + 1, "gt;", 3 ) == 0 ) { 2795| *dst = '>'; 2796| src += 4; dst++; 2797| } 2798| else if ( strncmp( src + 1, "amp;", 4 ) == 0 ) { 2799| *dst = '&'; 2800| src += 5; dst++; 2801| } 2802| else { 2803| *dst = *src; 2804| src ++; dst++; 2805| } 2806| } 2807| else { 2808| *dst = *src; 2809| src ++; dst++; 2810| } 2811| } 2812| *dst ='\0'; 2813| 2814| return dst_first; 2815|} 2816| 2817| 2818| 2819|/************************************************************************* 2820| 8-21. <<< [StrX_cpyLower] 文字列を小文字にする >>> 2821|【引数】 2822| ・char* dst; 小文字にした文字列を格納する領域 2823| ・char* src; 元テキスト(dst と同じでもOK) 2824|**************************************************************************/ 2825|void StrX_cpyLower( char* dst, const char* src ) 2826|{ 2827| while ( *src != '\0' ) { 2828| if ( _ismbblead( *src ) ) { 2829| *dst = *src; dst++; src++; 2830| *dst = *src; 2831| } 2832| else if ( isupper( *src ) ) { 2833| *dst = tolower( *src ); 2834| } 2835| else { 2836| *dst = *src; 2837| } 2838| dst++; src++; 2839| } 2840| *dst = '\0'; 2841|} 2842| 2843| 2844| 2845|/************************************************************************* 2846| 8-22. <<< [StrX_cpyUpper] 文字列を大文字にする >>> 2847|【引数】 2848| ・char* dst; 大文字にした文字列を格納する領域 2849| ・char* src; 元テキスト(dst と同じでもOK) 2850|**************************************************************************/ 2851|void StrX_cpyUpper( char* dst, const char* src ) 2852|{ 2853| while ( *src != '\0' ) { 2854| if ( _ismbblead( *src ) ) { 2855| *dst = *src; dst++; src++; 2856| *dst = *src; 2857| } 2858| else if ( islower( *src ) ) { 2859| *dst = toupper( *src ); 2860| } 2861| else { 2862| *dst = *src; 2863| } 2864| dst++; src++; 2865| } 2866| *dst = '\0'; 2867|} 2868| 2869| 2870| 2871|/*********************************************************************** 2872| 8-23. <<< [StrX_getTableXY] 表計算での位置表記から X,Y 座標値を得る >>> 2873|【引数】 2874| ・char* xy; 表計算アプリでの位置表記 2875| ・int* x, y; (出力)X,Y 座標値 2876|【補足】 2877|・例:"A1"... *x=1, *y=1, "AB712"... *x=28, *y=712 2878|************************************************************************/ 2879|void StrX_getTableXY( const char* xy, int* x, int* y ) 2880|{ 2881| *x = 0; 2882| for (;;) { 2883| if ( *xy >= 'A' && *xy <= 'Z' ) *x = *x * 26 + *xy - 'A' + 1; 2884| else if ( *xy >= 'a' && *xy <= 'z' ) *x = *x * 26 + *xy - 'a' + 1; 2885| else break; 2886| xy++; 2887| } 2888| *y = atoi( xy ); 2889|} 2890| 2891| 2892| 2893|/*********************************************************************** 2894| 8-24. <<< [StrX_separateByByteInLine] 1行の中のバイト数を制限するために改行を入れる >>> 2895|【引数】 2896| ・char* s; 変更する文字列 2897| ・int s_size; s のメモリ領域サイズ(バイト) 2898| ・int nByteInLine; 1行の中の最大バイト数(改行文字を含む) 2899| ・char* retStr; 入れる改行文字("\r\n", "\n" など) 2900|************************************************************************/ 2901|void StrX_separateByByteInLine( char* s, int s_size, int mByteInLine, 2902| const char* retStr ) 2903|{ 2904| char* p; 2905| char* r; 2906| int n; 2907| int space = s_size - strlen( s ) - 1; 2908| int retStr_len = strlen( retStr ); 2909| 2910| p = s; 2911| for (;;) { 2912| r = strstr( p, retStr ); 2913| if ( r == NULL ) { 2914| n = strlen( p ); 2915| if ( n < mByteInLine - 1 ) return; 2916| } 2917| else { 2918| if ( r <= p + mByteInLine - retStr_len ) 2919| { p = r + retStr_len; continue; } 2920| } 2921| 2922| /* 行を分割する */ 2923| if ( space <= retStr_len - 1 ) { 2924| memcpy( p + mByteInLine, p + mByteInLine - retStr_len, 2925| ( s + s_size ) - ( p + mByteInLine ) - 1 ); 2926| s[s_size - 1] = '\0'; 2927| strcpy( p + mByteInLine - retStr_len, retStr ); 2928| } 2929| else { 2930| StrX_ins( p + mByteInLine - retStr_len, retStr ); 2931| space -= retStr_len; 2932| } 2933| p += mByteInLine; 2934| } 2935|} 2936| 2937| 2938| 2939|/*********************************************************************** 2940| 8-25. <<< [StrX_encodeBase64] バイナリデータを base64 のテキストに変換する >>> 2941|【引数】 2942| ・char* base64; base64 を格納するアドレス(サイズは、StrX_getEncodedSizeOfBase64 から) 2943| ・void* bin; 変換するバイナリデータ 2944| ・int bin_size; バイナリデータのサイズ 2945| ・char* retCh; base64 に格納する改行文字(Windows なら "\r\n") 2946|【補足】 2947|・この関数で得られる base64 のテキストは、ワイド文字列ではありません。 2948|・変換を複数回に分けるときは、bin のサイズが StrX_unitOfBase64 の倍数に 2949| なるように分けてください。 2950|************************************************************************/ 2951|void StrX_encodeBase64( char* base64, void* bin, int bin_size, const char* retCh ) 2952|{ 2953| static char table[] = { 2954| 'A','B','C','D','E','F','G','H', 'I','J','K','L','M','N','O','P', 2955| 'Q','R','S','T','U','V','W','X', 'Y','Z','a','b','c','d','e','f', 2956| 'g','h','i','j','k','l','m','n', 'o','p','q','r','s','t','u','v', 2957| 'w','x','y','z','0','1','2','3', '4','5','6','7','8','9','+','/' 2958| }; 2959| 2960| 2961| unsigned char* p; 2962| unsigned char* p_over3 = (unsigned char*)bin + ( bin_size - (bin_size % 3) ); 2963| unsigned char* p_over = (unsigned char*)bin + bin_size; 2964| char* t; 2965| char* lineTop; 2966| 2967| 2968| t = base64; 2969| lineTop = t; 2970| 2971| 2972| /* 3バイトごとに変換する */ 2973| for ( p = (unsigned char*)bin; p < p_over3; p += 3 ) { 2974| 2975| /* p を上位から 6ビットずつ取り出して、table で変換し、t に格納する */ 2976| *t = table[ *p >> 2 ]; 2977| *(t + 1) = table[ ( (*p << 4) | (*(p+1) >> 4) ) & 0x3F ]; 2978| *(t + 2) = table[ ( (*(p+1) << 2) | (*(p+2) >> 6) ) & 0x3F ]; 2979| *(t + 3) = table[ *(p+2) & 0x3F ]; 2980| t += 4; 2981| 2982| /* t は、76文字ごとに改行を入れる */ 2983| if ( t - lineTop == 76 ) { 2984| strcpy( t, retCh ); 2985| t = strchr( t, '\0' ); 2986| lineTop = t; 2987| } 2988| } 2989| 2990| 2991| /* のこりの 1バイトか 2バイトを変換し、文字列の終端文字を付ける */ 2992| if ( p_over - p_over3 == 0 ) { 2993| *t = '\0'; 2994| } 2995| else if ( p_over - p_over3 == 1 ) { 2996| *t = table[ *p >> 2 ]; 2997| *(t + 1) = table[ ( *p << 4 ) & 0x3F ]; 2998| *(t + 2) = '='; 2999| *(t + 3) = '='; 3000| *(t + 4) = '\0'; 3001| } 3002| else { 3003| *t = table[ *p >> 2 ]; 3004| *(t + 1) = table[ ( (*p << 4) | (*(p+1) >> 4) ) & 0x3F ]; 3005| *(t + 2) = table[ ( *(p+1) << 2 ) & 0x3F ]; 3006| *(t + 3) = '='; 3007| *(t + 4) = '\0'; 3008| } 3009|} 3010| 3011| 3012| 3013|/*********************************************************************** 3014| 8-26. <<< [StrX_decodeBase64] base64 のテキストからバイナリデータに変換する >>> 3015|【引数】 3016| ・char* base64; base64 のテキスト(終端文字 '\0' があること) 3017| ・void* bin; バイナリデータを格納するアドレス(サイズは、StrX_getDecodedSizeOfBase64 から) 3018| ・int 返り値; 変換してできたバイナリデータのサイズ(→補足) 3019|【補足】 3020|・行頭に空白やタブがあっても構いません。 3021|・返り値は、StrX_getDecodedSizeOfBase64 の返り値より小さくなることがあります。 3022|・エラーがあったときは、base64 のエラーのあったオフセットのマイナスの値を返します。 3023|・変換を複数回に分けるときは、base64 のテキストを行単位(複数行可能)に分けてください。 3024|・base64に1行分を指定した場合、返り値が StrX_unitOfBase64 より小さかったら、 3025| そこで base64 で使われない文字が検出されたことを示します。 3026|************************************************************************/ 3027|int StrX_decodeBase64( const char* base64, void* bin ) 3028|{ 3029| #define E 0x7F 3030| static char table[] = { 3031| E, E, E, E, E, E, E, E, /* 0x20: '+','/' */ 3032| E, E, E, 0x3E, E, E, E, 0x3F, 3033| 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, /* 0x30: '0'..'9','=' */ 3034| 0x3C, 0x3D, E, E, E, E, E, E, 3035| E, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* 0x40: 'A'..'O' */ 3036| 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 3037| 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* 0x50: 'P'..'Z' */ 3038| 0x17, 0x18, 0x19, E, E, E, E, E, 3039| E, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, /* 0x60: 'a'..'o' */ 3040| 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 3041| 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, /* 0x70: 'p'..'z' */ 3042| 0x31, 0x32, 0x33, E, E, E, E, E, 3043| }; 3044| 3045| 3046| unsigned char* t; 3047| unsigned char t0, t1, t2, t3; 3048| unsigned char* p; 3049| 3050| p = (unsigned char*)bin; 3051| 3052| for ( t = (unsigned char*)base64; *t != '\0'; t += 4 ) { 3053| while ( (*t <= ' ' || *t == '=') && *t != '\0' ) t++; /* 改行などをスキップする */ 3054| if ( *t == '\0' ) break; 3055| if ( *(t+1) == '\0' || *(t+2) == '\0' || *(t+3) == '\0' ) 3056| return (unsigned char*)base64 - t; /* エラー */ 3057| 3058| 3059| 3060| t0 = table[ *t - 0x20 ]; 3061| if ( t0 == E ) break; 3062| 3063| t1 = table[ *(t+1) - 0x20 ]; 3064| t2 = table[ *(t+2) - 0x20 ]; 3065| t3 = table[ *(t+3) - 0x20 ]; 3066| 3067| *p = (t0 << 2) | (t1 >> 4); 3068| *(p+1) = (t1 << 4) | (t2 >> 2); 3069| *(p+2) = (t2 << 6) | t3; 3070| p += 3; 3071| } 3072| 3073| if ( p == (unsigned char*)bin ) return 0; /* *(t-2) のアクセスエラー回避 */ 3074| else if ( *(t-2) == '=' ) return ( p - (unsigned char*)bin ) - 2; 3075| else if ( *(t-1) == '=' ) return ( p - (unsigned char*)bin ) - 1; 3076| else return p - (unsigned char*)bin; 3077| 3078| #undef E 3079|} 3080| 3081| 3082| 3083| 3084|/*********************************************************************** 3085| 8-27. <<< [StrX_getEncodedSizeOfBase64] StrX_encodeBase64 に必要なサイズを返す >>> 3086|【引数】 3087| ・int bin_size; バイナリデータのサイズ 3088| ・char* retCh; base64 に格納する改行文字(Windows なら "\r\n") 3089|************************************************************************/ 3090|int StrX_getEncodedSizeOfBase64( int bin_size, const char* retCh ) 3091|{ 3092| return ( bin_size / 57 ) * ( 76 + strlen( retCh ) ) + 3093| ( ( bin_size % 57 + 2 ) / 3 ) * 4 + 1; 3094|} 3095| 3096| 3097| 3098|/*********************************************************************** 3099| 8-28. <<< [StrX_getDecodedSizeOfBase64] StrX_decodeBase64 に必要なサイズを返す >>> 3100|【引数】 3101| ・int base64_strlen; base64 のテキストの長さ(バイト。終端文字 '\0' は含まない) 3102|【補足】 3103|・base64_strlen のテキストには、改行文字が含まれていても構いません。 3104|・改行文字がどの種類の場合でも対応できるサイズを返すので、変換後のバイナリのサイズより 3105| 大きくなることがあります。 3106|************************************************************************/ 3107|int StrX_getDecodedSizeOfBase64( int base64_strlen ) 3108|{ 3109| return ( base64_strlen / 77 ) * 57 + ( ( base64_strlen % 77 ) / 4 ) * 3; 3110|} 3111| 3112| 3113| 3114|/*-------------------------------------------------------------------------*/ 3115|/* ◆9. <<<< (StrX) char* 型の文字列(判断・正規化) >>>> 3116|/*-------------------------------------------------------------------------*/ 3117| 3118| 3119| 3120|/*********************************************************************** 3121| 9-1. <<< [StrX_isSJis1byte] 指定位置の文字が日本語の1バイト目かどうか判定する >>> 3122|【引数】 3123| ・char* char_top; pChar を含む文字列の先頭アドレス 3124| ・char* pChar; 1バイト目かどうか判定する文字のアドレス 3125| ・int 返り値; 1バイト目かどうか( yes=1, no=0 ) 3126|************************************************************************/ 3127|int StrX_isSJis1byte( const char* char_top, const char* pChar ) 3128|{ 3129| const char* p; 3130| 3131| for ( p = char_top; *p != '\0'; p++ ) { 3132| if ( p == pChar ) return _ismbblead( *p ); 3133| if ( _ismbblead( *p ) ) { 3134| p++; 3135| if ( p == pChar ) return 0; 3136| } 3137| } 3138| error(); 3139| return 0; 3140|} 3141| 3142| 3143| 3144|/*********************************************************************** 3145| 9-2. <<< [StrX_isSJis2byte] 指定位置の文字が日本語の2バイト目かどうか判定する >>> 3146|【引数】 3147| ・char* char_top; pChar を含む文字列の先頭アドレス 3148| ・char* pChar; 2バイト目かどうか判定する文字のアドレス 3149| ・int 返り値; 2バイト目かどうか( yes=1, no=0 ) 3150|************************************************************************/ 3151|int StrX_isSJis2byte( const char* char_top, const char* pChar ) 3152|{ 3153| const char* p; 3154| 3155| for ( p = char_top; *p != '\0'; p++ ) { 3156| if ( p == pChar ) return 0; 3157| if ( _ismbblead( *p ) ) { 3158| p++; 3159| if ( p == pChar ) return 1; 3160| } 3161| } 3162| error(); 3163| return 0; 3164|} 3165| 3166| 3167| 3168|/*********************************************************************** 3169| 9-3. <<< [StrX_isExist2byte] 2バイト文字が含まれているかどうか判定する >>> 3170|【引数】 3171| ・char* s; 判定する文字列 3172| ・int 返り値; 2バイト文字が含まれているかどうか 3173|************************************************************************/ 3174|int StrX_isExist2byte( const char* s ) 3175|{ 3176| const char* p; 3177| 3178| for ( p = s; *p != '\0'; p++ ) { 3179| if ( _ismbblead( *p ) ) return 1; 3180| } 3181| return 0; 3182|} 3183| 3184| 3185| 3186|/*********************************************************************** 3187| 9-4. <<< [StrX_isSpace] 空白かどうか判断する >>> 3188| isspace では 8bit キャラクタに対応していないが、これは対応している 3189|************************************************************************/ 3190|bool StrX_isSpace( int c ) 3191|{ 3192| if ( c < 0 ) return 0; 3193| else return isspace( c ) != 0; 3194|} 3195| 3196| 3197| 3198|/*********************************************************************** 3199| 9-5. <<< [StrX_isAlpha] アルファベットかどうか判断する >>> 3200|************************************************************************/ 3201|bool StrX_isAlpha( int c ) 3202|{ 3203| return ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' ); 3204|} 3205| 3206| 3207| 3208|/*********************************************************************** 3209| 9-6. <<< [StrX_isDigit] 数字かどうか判断する >>> 3210|************************************************************************/ 3211|bool StrX_isDigit( int c ) 3212|{ 3213| return ( c >= '0' && c <= '9' ); 3214|} 3215| 3216| 3217| 3218|/*********************************************************************** 3219| 9-7. <<< [StrX_isSpcTabRet] 空白、タブ、改行かどうか判断する >>> 3220|************************************************************************/ 3221|bool StrX_isSpcTabRet( int c ) 3222|{ 3223| return c == ' ' || c == '\n' || c == '\r' || c == '\t'; 3224|} 3225| 3226| 3227| 3228|/*********************************************************************** 3229| 9-8. <<< [StrX_isSpaceStr] 空白文字列かどうか判断する >>> 3230|************************************************************************/ 3231|int StrX_isSpaceStr( const char* c ) 3232|{ 3233| while ( *c != '\0' ) 3234| if ( ! StrX_isSpace(*c) ) return 0; 3235| return 1; 3236|} 3237| 3238| 3239| 3240|/*********************************************************************** 3241| 9-9. <<< [StrX_isTerm] 区切り文字か判断する >>> 3242|【引数】 3243| ・int 返り値; 区切り文字=1、その他=0 3244|************************************************************************/ 3245|int StrX_isTerm( char c ) 3246|{ 3247| return ! ( isalpha(c) || c == '_' ); 3248|} 3249| 3250| 3251| 3252|/*********************************************************************** 3253| 9-10. <<< [StrX_isFName] ファイル名として有効かどうか判断する >>> 3254|************************************************************************/ 3255|bool StrX_isFName( const char* name ) 3256|{ 3257| if ( StrX_strchrs( name, "\\/:,;*?\"<>|" ) != NULL ) return false; 3258| if ( name[0]=='.' ) return false; 3259| return true; 3260|} 3261| 3262| 3263| 3264|/************************************************************************* 3265| 9-11. <<< [StrX_cmpWild] ワイルドカードを持った文字列を比較する(大文字小文字を区別) >>> 3266|【補足】 3267|・ワイルドカードは、wild 引数にのみ指定できます。 3268| ・'?' ワイルドカードは、任意の1文字と対応します。空文字には対応しません。 3269| ・'*' ワイルドカードは、任意長の文字列と対応します。ただし、'*' は1つ 3270| しか指定できません。 3271| ・ワイルドカードは指定しなくても構いません 3272|・大文字と小文字は区別します。 3273|・複数のワイルドカードを使うときは、StrX_Set_searchWild2 関数を使用し 3274| てください。 3275|【例】 3276|・wild="abc*", str="abcdef" ... ret == 0 3277|・wild="abc?", str="abcdef" ... ret < 0 ('e' を比較) 3278|・wild="abc*e", str="abcdef" ... ret > 0 (後ろの 'f' を比較) 3279|・wild="*.c", str="main.c" ... ret == 0 3280|**************************************************************************/ 3281|int StrX_cmpWild( const char* wild, const char* str ) 3282|{ 3283| const char* w; 3284| const char* s; 3285| int diff; 3286| #ifndef NDEBUG 3287| const char* ww; /* '*' が2つあるかチェックするため */ 3288| #endif 3289| 3290| /* '*'ワイルドカードまで比較する */ 3291| w = wild; s = str; 3292| while ( *w != '\0' && *w != '*' ) { 3293| if ( *w != *s && *w != '?' ) { 3294| return *w - *s; 3295| } 3296| w++; s++; 3297| } 3298| 3299| /* '*'ワイルドカードが無ければ、文字数を確認して終了する */ 3300| if ( *w == '\0' ) { 3301| return - *s; 3302| } 3303| 3304| /* '*'ワイルドカードより後を、後ろから比較する */ 3305| #ifndef NDEBUG 3306| ww = w; /* あとで、'*' が2つあるかチェックする */ 3307| #endif 3308| w = strchr( w, '\0' ) - 1; 3309| s = strchr( s, '\0' ) - 1; 3310| diff = 0; 3311| while ( *w != '*' ) { 3312| if ( *w != *s && *w != '?' ) { 3313| diff = *w - *s; 3314| } 3315| w--; s--; 3316| } 3317| 3318| #ifndef NDEBUG 3319| if ( ww != w ) error(); /* '*' が2つある */ 3320| #endif 3321| 3322| return diff; 3323|} 3324| 3325| 3326| 3327|/************************************************************************* 3328| 9-12. <<< [StrX_cmpWildI] ワイルドカードを持った文字列を比較する(大文字小文字を区別しない) >>> 3329|【補足】 3330|・大文字と小文字を区別しない StrX_cmpWild です。 3331|・'*' は2つ以上指定できます。 3332|**************************************************************************/ 3333|int StrX_cmpWildI( const char* wild, const char* str ) 3334|{ 3335| const char* w; 3336| const char* s; 3337| 3338|#if 1 3339| w = wild; s = str; 3340| while ( *w != '\0' ) { 3341| 3342| if ( *w == '*' ) { 3343| const char* w_start; /* ワイルドカードの後に続くキーワードの開始位置 */ 3344| const char* w_over; /* 同、終了位置 */ 3345| 3346| /* w_start, w_over の取得 */ 3347| w ++; w_start = w; 3348| while ( *w != '*' && *w != '?' && *w != '\0' ) 3349| w++; 3350| w_over = w; 3351| 3352| /* ワイルドカード分をスキップする */ 3353| w = w_start; 3354| while ( *s != '\0' ) { 3355| if ( tolower( *w ) == tolower( *s ) ) { 3356| w++; 3357| if ( w == w_over ) 3358| { s++; break; } 3359| } 3360| else { 3361| w = w_start; 3362| } 3363| s++; 3364| } 3365| } 3366| 3367| else if ( *w == '?' ) { 3368| if ( *s == '\0' ) 3369| return +1; 3370| w++; s++; 3371| } 3372| 3373| else { 3374| if ( tolower( *w ) != tolower( *s ) ) 3375| return *w - *s; 3376| w++; s++; 3377| } 3378| } 3379| 3380| return -*s; 3381|#else 3382| int diff; 3383| #ifndef NDEBUG 3384| const char* ww; /* '*' が2つあるかチェックするため */ 3385| #endif 3386| 3387| /* '*'ワイルドカードまで比較する */ 3388| w = wild; s = str; 3389| while ( *w != '\0' && *w != '*' ) { 3390| 3391| if ( tolower( *w ) != tolower( *s ) && *w != '?' ) { 3392| return *w - *s; 3393| } 3394| w++; s++; 3395| } 3396| 3397| /* '*'ワイルドカードが無ければ、文字数を確認して終了する */ 3398| if ( *w == '\0' ) { 3399| return - *s; 3400| } 3401| 3402| /* '*'ワイルドカードより後を、後ろから比較する */ 3403| #ifndef NDEBUG 3404| ww = w; /* あとで、'*' が2つあるかチェックする */ 3405| #endif 3406| w = strchr( w, '\0' ) - 1; 3407| s = strchr( s, '\0' ) - 1; 3408| diff = 0; 3409| while ( *w != '*' ) { 3410| if ( tolower( *w ) != tolower( *s ) && *w != '?' ) { 3411| diff = *w - *s; 3412| } 3413| w--; s--; 3414| } 3415| 3416| #ifndef NDEBUG 3417| if ( ww != w ) error(); /* '*' が2つある */ 3418| #endif 3419| 3420| return diff; 3421|#endif 3422|} 3423| 3424| 3425| 3426|/*********************************************************************** 3427| 9-13. <<< [StrX_isMatchMask] ワイルドカードにマッチするか判断する >>> 3428|【補足】 3429|・ワイルドカードは、'*'(いくつかの任意の文字)と'?'(任意の1文字)のことを 3430| いい、たとえば、*.c は main.c や sub.c などの文字列とマッチします。 3431|************************************************************************/ 3432|#if 0 3433|bool StrX_isMatchMask( const char* target, const char* wildcard ) 3434|{ 3435| return StrX_cmpWild( wildcard, target ) == 0; 3436|} 3437|#endif 3438| 3439| 3440| 3441|/*-------------------------------------------------------------------------*/ 3442|/* ◆10. <<<< (StrX) char* 型の文字列(ファイル名、ファイルパス) >>>> */ 3443|/*・ファイル名に関する処理は、このエリア以外にもあります。 */ 3444|/*-------------------------------------------------------------------------*/ 3445| 3446| 3447| 3448|/*********************************************************************** 3449| 10-1. <<< [StrX_getRunFullPath] 実行しているディレクトリからフルパスを得る >>> 3450|【引数】 3451| ・fullPath : フルパス(出力) 3452| ・stepPath : 相対パス、fullPath と同じでもよい 3453| ・fullPath_len : フルパスに格納できる最大の文字数(byte) 3454|【補足】 3455|・標準関数に _fullpath 関数があります。 3456|・stepPath の ".\" や "..\" は、まとめられます。 3457|・ルート・ディレクトリよりも親へ指定しないこと(b:\..\a.txt など) 3458| 例 : 実行dir="b:\curdir", stepPath="..\a.dat" なら 3459| fullPath="b:\a.dat" 3460|************************************************************************/ 3461|#if defined(_MSC_VER) && !defined(FOR_WINCE) 3462|char* StrX_getRunFullPath( char* fullPath, const char* stepPath, 3463| int fullPath_len ) 3464|{ 3465| char s[_MAX_PATH]; 3466| 3467| _getcwd( s, 254 ); 3468| if ( fullPath != stepPath ) strcpy( fullPath, stepPath ); 3469| StrX_toAbsPath( fullPath, fullPath_len, s ); 3470| 3471| return fullPath; 3472|} 3473|#endif /* _MSC_VER */ 3474| 3475| 3476| 3477|/*********************************************************************** 3478| 10-2. <<< [StrX_getExeFullPath] 実行ファイルのディレクトリからフルパスを得る >>> 3479|【引数】 3480| ・char* 返り値; fullPath 3481|【補足】 3482|・main で StrX_argv0 = argv[0] を設定してから使うこと。 3483| (MFC では、StrX_argv0 = AfxGetApp()->m_pszHelpFilePath;) 3484| (または GetModuleFileName( AfxGetApp()->m_hInstance, s, 255 );) 3485|・ベースのディレクトリが異なること以外は、StrX_getRunFullPath と同じ 3486|・fullPath と stepPath が同じアドレスでも構いません。 3487|************************************************************************/ 3488|#ifdef _MSC_VER 3489|const char* StrX_argv0 = NULL; /* main() の argv[0] 引数をポイントすること */ 3490| 3491|char* StrX_getExeFullPath( char* fullPath, char* stepPath, 3492| int fullPath_len ) 3493|{ 3494| char s[_MAX_PATH]; 3495| 3496| /* stepPath が絶対パスなら、そのままコピー */ 3497| if ( stepPath[0] == '\\' || stepPath[1] == ':' ) { 3498| strcpy( fullPath, stepPath ); 3499| return fullPath; 3500| } 3501| 3502| /* "b:\exedir\stepPath" を s に得る */ 3503| ASSERT( StrX_argv0 != NULL ); 3504| strcpy( s, StrX_argv0 ); 3505| *( strrchr( s, StrX_DirMark_char ) + 1 ) = '\0'; 3506| StrX_cat( s, stepPath, 256 ); 3507| 3508| /* ".\" や "..\" をまとめて、fullPath に得る */ 3509| StrX_toRegularPath( s ); 3510| StrX_cpy( fullPath, s, fullPath_len ); 3511| 3512| return fullPath; 3513|} 3514|#endif /* _MSC_VER */ 3515| 3516| 3517| 3518|/*********************************************************************** 3519| 10-3. <<< [StrX_isAbsPath] 絶対パスかどうか判定する >>> 3520|【引数】 3521| ・char* path; 判定する文字列 3522| ・bool 返り値; 絶対パスかどうか 3523|************************************************************************/ 3524|bool StrX_isAbsPath( const char* path ) 3525|{ 3526| char* p = strchr( path, '\\' ); 3527| char* p2 = strchr( path, '/' ); 3528| 3529| if ( p == NULL && p2 == NULL ) return false; 3530| 3531| if ( p != NULL && p2 != NULL ) { 3532| if ( p > p2 ) p = p2; 3533| } 3534| else if ( p == NULL ) p = p2; 3535| 3536| return ( p == path || *(p - 1) == ':' ); 3537|} 3538| 3539| 3540| 3541|/*********************************************************************** 3542| 10-4. <<< [StrX_isUrl] Netscape URL かどうか判定する >>> 3543|【引数】 3544| ・char* url; 判定する文字列 3545| ・bool 返り値; Netscape URL かどうか 3546|【補足】 3547|・Windows ファイルパスか Netscape URL かのみを比較しています。 3548|************************************************************************/ 3549|bool StrX_isUrl( const char* url ) 3550|{ 3551| if ( ( url[0] == '/' && url[1] == '/' ) || 3552| ( url[0] == '\\' && url[1] == '\\' ) ) { 3553| return false; 3554| } 3555| if ( url[1] == ':' ) 3556| return false; 3557| 3558| return true; 3559|} 3560| 3561| 3562| 3563|/*********************************************************************** 3564| 10-5. <<< [StrX_chgPathToUrl] Windows パスを Netscape URL に変換する >>> 3565|【引数】 3566| ・char* url; URL に変換した文字列を格納するアドレス 3567| ・char* path; パス文字列(フルパス) 3568| ・char* 返り値; url と同じ 3569|【補足】 3570|・url と path が同じアドレスでも構いません。 3571|・url のメモリサイズは、_MAX_PATH 以上にしてください。 3572|・path のディレクトリ区切り文字は、'/' でも '\' でも構いません。 3573|【例】 3574|・path = "\\pc01\c\file.txt" → url = "file://pc01/c/file.txt" 3575|・path = "c:\file.txt" → url = "file:///c|/file.txt" 3576|************************************************************************/ 3577|char* StrX_chgPathToUrl( char* url, const char* path ) 3578|{ 3579| /* Microsoft ネットワーク・パスの場合 */ 3580| if ( ( path[0] == '/' && path[1] == '/' ) || 3581| ( path[0] == '\\' && path[1] == '\\' ) ) { 3582| ASSERT( strlen(path) < _MAX_PATH - 6 ); 3583| 3584| memmove( url + 7, path + 2, strlen(path)-1 ); 3585| StrX_rep1b( url + 7, '\\', '/' ); 3586| memcpy( url, "file://", 7 ); 3587| } 3588| 3589| /* ローカル・ファイルパスの場合 */ 3590| else { 3591| ASSERT( path[1] == ':' ); 3592| ASSERT( path[2] == '/' || path[2] == '\\' ); 3593| ASSERT( strlen(path) < _MAX_PATH - 9 ); 3594| 3595| memmove( url + 8, path, strlen(path) + 1 ); 3596| StrX_rep1b( url + 8, '\\', '/' ); 3597| memcpy( url, "file:///", 8 ); 3598| url[9] = '|'; 3599| } 3600| 3601| StrX_rep( url, _MAX_PATH, " ", "%20" ); 3602| 3603| return url; 3604|} 3605| 3606| 3607| 3608|/*********************************************************************** 3609| 10-6. <<< [StrX_toRegularPath] ファイル名の ".\" や "..\" を、取り除く >>> 3610| ルート・ディレクトリよりも親へ指定しないこと(b:\..\a.txt など) 3611| 戻り値 : s 3612| 例 : 実行dir="b:\curdir", stepPath="..\a.dat" なら 3613| fullPath="b:\a.dat" 3614|************************************************************************/ 3615|char* StrX_toRegularPath( char* s ) 3616|{ 3617| char* p0; /* 先頭の "..\" の次のアドレス */ 3618| char *p, *p2; 3619| 3620| /* 先頭の "..\" はスキップする, p0 を設定する */ 3621| p0 = s; 3622| while ( strncmp( p0, "..\\", 3 ) == 0 ) p0 += 3; 3623| 3624| /* s から "parentdir\..\" を取り除く */ 3625| p = p0; 3626| while ( ( p2 = strstr( p, ".." StrX_DirMark_str ) ) != NULL ) { 3627| *(p2 - 1) = '\0'; 3628| p = strrchr( s, StrX_DirMark_char ) + 1; 3629| if ( p - 1 == NULL ) 3630| error2_0( StrX_Err_NoMoreParentDir, "親ディレクトリ指定\"..\\\"が多すぎます。" ); 3631| memmove( p, p2+3, strlen( p2+3 ) + 1 ); 3632| } 3633| 3634| /* s から ".\" を取り除く */ 3635| p = p0; 3636| while ( ( p2 = strstr( p, "." StrX_DirMark_str ) ) != NULL ) { 3637| if ( p2 != strstr( p, ".." StrX_DirMark_str ) +1 ) 3638| memmove( p2, p2+2, strlen( p2+2 ) + 1 ); 3639| p = p2+1; 3640| } 3641| 3642| return s; 3643|} 3644| 3645| 3646| 3647|/*********************************************************************** 3648| 10-7. <<< [StrX_toAbsPath] 相対パスを絶対パスにする >>> 3649|【引数】 3650| ・char* path; (入力)相対パス(絶対パスでも可、ただし何もしない)(出力)絶対パス 3651| ・int maxlen; path に格納できる最大の文字数('\0'含まない) 3652| ・char* base; 基準パス 3653| ・char* 戻り値; path 3654|【補足】 3655|・ルート・ディレクトリよりも親へ指定しないこと(b:\..\a.txt など) 3656|・例 : base="b:\curdir", path="..\a.dat" なら 3657| ret="b:\a.dat" 3658|・path に http://〜 を指定した場合、何もしません。 3659|************************************************************************/ 3660|char* StrX_toAbsPath( char* path, int path_maxlen, const char* base ) 3661|{ 3662| char* p; 3663| 3664| if ( path[0] == '\0' ) return path; 3665| 3666| /* path が絶対パスの場合、なにもしない */ 3667| p = strchr( path, ':' ); 3668| if ( p != NULL ) { 3669| for ( p--; p >= path; p-- ) /* 先頭が1文字または複数の英文字+':' かチェック */ 3670| if ( ! isalpha( *p ) ) break; 3671| } 3672| if ( path[0] == '/' || path[0] == '\\' || p == path -1 ) { 3673| return path; 3674| } 3675| 3676| 3677| /* path が相対パスの場合、絶対パスにする */ 3678| { 3679| #ifdef FOR_WIN32 3680| char* path2 = (char*)malloc( path_maxlen ); 3681| #else 3682| char path2[512]; 3683| #endif 3684| 3685| strcpy( path2, base ); 3686| if ( StrX_getLast( path2 ) != '/' ) 3687| StrX_setLast( path2, '\\' ); 3688| strcat( path2, path ); 3689| StrX_toRegularPath( path2 ); 3690| if ( path_maxlen < (int)strlen( path2 ) && path_maxlen < 512 ) 3691| path2[path_maxlen] = '\0'; 3692| strcpy( path, path2 ); 3693| 3694| p = strchr( path, '\0' ); 3695| if ( ( *( p - 2 ) == '\\' || *( p - 2 ) == '/' ) && *( p - 1 ) == '.' ) 3696| *( p - 2 ) = '\0'; 3697| 3698| #ifdef FOR_WIN32 3699| free( path2 ); 3700| #endif 3701| 3702| return path; 3703| } 3704|} 3705| 3706| 3707| 3708|/*********************************************************************** 3709| 10-8. <<< [StrX_toAbsPath2] 相対パスを絶対パスにする(ファイル指定) >>> 3710|【引数】 3711| ・char* path; 相対パス(絶対パスでも可、ただし何もしない) 3712| ・int maxlen; path に格納できる最大の文字数('\0'含まない) 3713| ・char* base; 基準ファイルパス 3714| ・char* 戻り値; path 3715|【補足】 3716|・StrX_toAbsPath の base 引数がフォルダではなくファイルになっています。 3717|************************************************************************/ 3718|char* StrX_toAbsPath2( char* path, int path_maxlen, const char* base ) 3719|{ 3720| if ( path[0] == '\0' ) return path; 3721| 3722| { 3723| #ifdef FOR_WIN32 3724| char* s = (char*)malloc( path_maxlen ); 3725| #else 3726| char s[_MAX_PATH]; 3727| #endif 3728| 3729| StrX_cpyFolder( s, base ); 3730| StrX_toAbsPath( path, path_maxlen, s ); 3731| 3732| #ifdef FOR_WIN32 3733| free( s ); 3734| #endif 3735| } 3736| 3737| return path; 3738|} 3739| 3740| 3741| 3742|/*********************************************************************** 3743| 10-9. <<< [StrX_cpyAbsPath2CSV] CSV 形式のパス列をすべて絶対パスにする >>> 3744|************************************************************************/ 3745|#ifdef USES_BIGSTACK 3746|char* StrX_cpyAbsPath2CSV( char* absp, const char* stepp, int absp_size, 3747| const char* base ) 3748|{ 3749| char path2[_MAX_PATH]; 3750| char* p = absp; 3751| int i; 3752| 3753| ASSERT( stepp != absp ); 3754| 3755| for ( i = 1; ; i++ ) { 3756| if ( StrX_getCSV( stepp, i, path2, _MAX_PATH ) == NULL ) 3757| break; 3758| if ( i == 1 && path2[0] == '\0' ) { absp[0] = '\0'; return absp; } 3759| StrX_toAbsPath2( path2, _MAX_PATH, base ); 3760| StrX_toCSV( p, path2, absp + absp_size - p - 1 ); 3761| p = strchr( p, '\0' ); 3762| p[0] = ','; p[1] = ' '; p += 2; 3763| if ( p >= absp + absp_size ) error(); 3764| } 3765| if ( i >= 2 ) p -= 2; 3766| *p = '\0'; 3767| 3768| return absp; 3769|} 3770|#endif 3771| 3772| 3773| 3774|/*********************************************************************** 3775| 10-10. <<< [StrX_toStepPath] 絶対パスを相対パスにする(フォルダ指定) >>> 3776|【引数】 3777| ・char* path; 変換する絶対パス 3778| ・int path_sizeof; path のメモリサイズ('\0'含む) 3779| ・char* base; 基準フォルダパス(絶対パス) 3780| ・char* 戻り値; path(相対パス) 3781|【補足】 3782|・区切り記号は '\' でも '/' でも構いません。 3783|・exe ファイルにドラッグ&ドロップしたファイルのパスは DOS8.3 形式なので、 3784| 長いファイル名のもう片方の path か base に指定すると正しく処理できません。 3785|【例】 3786| path="b:\curdir\sub\a.txt", base="b:\curdir" なら ret="sub\a.txt" 3787| path="b:\curdir\sub\a.txt", base="a:\curdir" なら ret="b:\curdir\sub\a.txt" 3788| path="/sub/a.txt", base="/dir/" なら ret="../sub/a.txt" 3789|************************************************************************/ 3790|char* StrX_toStepPath( char* path, int path_sizeof, const char* base ) 3791|{ 3792| #ifdef FOR_WIN32 3793| char* path2; 3794| #else 3795| static char path2[512]; 3796| #endif 3797| char* ret = path; 3798| char* pPath; 3799| const char* pBase = base; 3800| char* pDirMarkInPath = NULL; 3801| const char* pDirMarkInBase = NULL; 3802| char* ret_over = ret + path_sizeof; 3803| int lastCh = *( strchr( path, '\0' ) - 1 ); 3804| 3805| 3806| #ifndef NDEBUG 3807| char path_backup[256]; 3808| char base_backup[256]; 3809| strncpy( path_backup, path, sizeof(path_backup) ); 3810| strncpy( base_backup, base, sizeof(base_backup) ); 3811| #endif 3812| 3813| #ifndef NDEBUG 3814| #if _MAX_PATH > 512 3815| #error 3816| #endif 3817| #endif 3818| 3819| ASSERT( strchr( base, '\\' ) != NULL ); 3820| 3821| if ( path[0] == '\0' ) return path; 3822| if ( stricmp( path, base ) == 0 ) { strcpy( path, "." ); return path; } 3823| if ( ! StrX_isAbsPath( path ) ) return path; 3824| if ( StrX_isUrl( path ) ) return path; 3825| 3826| #ifdef FOR_WIN32 3827| path2 = (char*)malloc(path_sizeof); 3828| pPath = path2; 3829| #endif 3830| 3831| strcpy( path2, path ); 3832| *ret = '\0'; 3833| 3834| /* \\ によるイントラネットへのパスのときは、マシン名、共有名が同じでないと相対にしない */ 3835| if ( path2[0] == '\\' && path2[1] == '\\' ) { 3836| char* p; 3837| 3838| p = strchr( path2 + 2, '\\' ); 3839| if ( p == NULL ) { strcpy( path, path2 ); goto ret; } 3840| p = strchr( p + 1, '\\' ); 3841| if ( p == NULL ) { strcpy( path, path2 ); goto ret; } 3842| if ( strnicmp( path2, base, p - path2 ) != 0 ) 3843| { strcpy( path, path2 ); goto ret; } 3844| } 3845| 3846| /* ドライブが同じならドライブ指定を無くす */ 3847| if ( path2[1] == ':' ) { 3848| if ( base[1] == ':' ) { 3849| if ( tolower(path2[0]) != tolower(base[0]) ) { 3850| strcpy( path, path2 ); 3851| goto ret; 3852| } 3853| pBase += 2; 3854| } 3855| else { 3856| strcpy( path, path2 ); 3857| goto ret; 3858| } 3859| pPath += 2; 3860| } 3861| else if ( base[1] == ':' ) { 3862| strcpy( path, path2 ); 3863| goto ret; 3864| 3865| #if 0 3866| *ret = *pBase; 3867| *(ret + 1) = ':'; 3868| ret += 2; 3869| pBase += 2; 3870| #endif 3871| } 3872| 3873| 3874| /* 親フォルダが同じ間、スキップする */ 3875| while ( tolower(*pPath) == tolower(*pBase) ) { 3876| 3877| #ifndef NDEBUG 3878| if ( *pPath == '\0' ) goto ret; 3879| #endif 3880| 3881| /* 最後のフォルダ区切り記号の位置を取っておく */ 3882| if ( *pPath == '\\' || *pPath == '/' ) { 3883| pDirMarkInPath = pPath; 3884| pDirMarkInBase = pBase; 3885| } 3886| 3887| pPath ++; pBase ++; 3888| } 3889| 3890| if ( *pPath == '\0' && ( *pBase == '\\' || *pBase == '/' ) ) { 3891| pDirMarkInPath = pPath; 3892| pDirMarkInBase = pBase; 3893| } 3894| 3895| ASSERT( pDirMarkInPath != NULL ); 3896| 3897| /* base フォルダの最後に \ を付ける */ 3898| if ( (*pBase == '\0') && 3899| (*pPath == '\\' || *pPath == '/') ) { 3900| if ( ret != path && *(ret - 1) != ':' ) 3901| { *ret = *pPath; ret ++; } 3902| pDirMarkInPath = pPath; 3903| } 3904| 3905| /* 親フォルダへ戻る記号 "..\" を付ける */ 3906| else { 3907| pBase = pDirMarkInBase; 3908| while ( *(pBase + 1) != '\0' ) { 3909| if ( *pBase == '\\' || *pBase == '/' ) { 3910| if ( ret +3 >= ret_over ) { *ret = '\0'; goto ret; } 3911| *ret = '.'; ret++; 3912| *ret = '.'; ret++; 3913| *ret = *pBase; ret++; 3914| } 3915| pBase ++; 3916| } 3917| } 3918| 3919| /* のこりの相対パスを付ける */ 3920| if ( *pDirMarkInPath == '\0' ) { 3921| *(ret - 1) = '\0'; 3922| } 3923| else { 3924| pPath = pDirMarkInPath + 1; 3925| if ( ret + strlen( pPath ) >= ret_over ) 3926| *(pPath + (ret_over - ret) - 1) = '\0'; 3927| strcpy( ret, pPath ); 3928| } 3929| 3930| /* path と base が同じだったら、"." を返す */ 3931| if ( path[0] == '\0' ) { 3932| if ( lastCh == '\\' || lastCh == '/' ) sprintf( path, ".%c", lastCh ); 3933| else strcpy( path, "." ); 3934| } 3935| 3936|ret: 3937| #ifdef FOR_WIN32 3938| free( path2 ); 3939| #endif 3940| 3941| return path; 3942|} 3943| 3944| 3945| 3946|/*********************************************************************** 3947| 10-11. <<< [StrX_toStepPath2] 絶対パスを相対パスにする(ファイル指定) >>> 3948|【引数】 3949| ・char* path; 変換する絶対パス 3950| ・int path_sizeof; path のメモリサイズ('\0'含む) 3951| ・char* file; 基準ファイルパス(絶対パス) 3952| ・char* 戻り値; path(相対パス) 3953|【補足】 3954|・StrX_toStepPath の base 引数がフォルダではなくファイルになっています。 3955|************************************************************************/ 3956|#ifdef USES_BIGSTACK 3957|char* StrX_toStepPath2( char* path, int path_sizeof, const char* file ) 3958|{ 3959| char s[_MAX_PATH]; 3960| 3961| StrX_cpyFolder( s, file ); 3962| StrX_toStepPath( path, path_sizeof, s ); 3963| 3964| return path; 3965|} 3966|#endif /* #ifdef USES_BIGSTACK */ 3967| 3968| 3969| 3970|/*********************************************************************** 3971| 10-12. <<< [StrX_cpyStepPath2CSV] CSV 形式のパス列をすべて相対パスにする >>> 3972|************************************************************************/ 3973|#ifdef USES_BIGSTACK 3974|char* StrX_cpyStepPath2CSV( char* stepp, const char* absp, int stepp_size, 3975| const char* base ) 3976|{ 3977| char path2[_MAX_PATH]; 3978| char* p = stepp; 3979| int i; 3980| 3981| for ( i = 1; ; i++ ) { 3982| if ( StrX_getCSV( absp, i, path2, _MAX_PATH ) == NULL ) 3983| break; 3984| if ( i == 1 && path2[0] == '\0' ) { stepp[0] = '\0'; return stepp; } 3985| StrX_toStepPath2( path2, _MAX_PATH, base ); 3986| StrX_toCSV( p, path2, stepp + stepp_size - p - 1 ); 3987| p = strchr( p, '\0' ); 3988| p[0] = ','; p[1] = ' '; p += 2; 3989| if ( p >= stepp + stepp_size ) error(); 3990| } 3991| if ( i >= 2 ) p -= 2; 3992| *p = '\0'; 3993| 3994| return stepp; 3995|} 3996|#endif 3997| 3998| 3999| 4000|/*********************************************************************** 4001| 10-13. <<< [StrX_toStepURL] 絶対 URL を相対 URL にする >>> 4002|【引数】 4003| ・char* url; 絶対 URL 4004| ・int url_sizeof; url のメモリサイズ('\0'含む) 4005| ・char* base; 基準 URL(絶対 URL) 4006| ・char* 戻り値; url 4007|【補足】 4008|・base は、基準となる HTML ファイルを指定します。格納されている 4009| ディレクトリではありません。 4010|・区切り記号は '\' でも '/' でも構いません。 4011|【例】 4012| url="b:\sub\a.htm#1", base="b:\sub\a.htm" なら ret="#1" 4013| url="http://sub/bb.htm#1", base="http://sub/a.htm" なら ret="bb.htm#1" 4014| url="bb.htm#1", base="bb.htm#2" なら ret="#1" 4015| url="/sub/ccc.htm", base="/dir/a.htm" なら ret="../sub/ccc.htm" 4016|************************************************************************/ 4017|char* StrX_toStepURL( char* url, int url_sizeof, const char* base ) 4018|{ 4019| char* p; 4020| int len; 4021| static char baseDir[_MAX_PATH]; 4022| 4023| p = strchr( url, '#' ); 4024| len = p - url; 4025| if ( p != NULL && memcmp( url, base, len ) == 0 && 4026| ( *(base + len) == '\0' || *(base + len) == '#' ) ) { 4027| memmove( url, p, strlen(p)+1 ); 4028| } 4029| else { 4030| strcpy( baseDir, base ); 4031| StrX_cutFName( baseDir ); 4032| StrX_toStepPath( url, url_sizeof, baseDir ); 4033| } 4034| 4035| return url; 4036|} 4037| 4038| 4039| 4040|/*********************************************************************** 4041| 10-14. <<< [StrX_movePath] フォルダ間を移動するようにパスを変換する >>> 4042|【引数】 4043| ・char* src; 変換前のファイルの絶対パス 4044| ・char* from_folder; 基準フォルダの移動前の絶対パス 4045| ・char* to_folder; 基準フォルダの移動後の絶対パス 4046| ・char* dst; 変換後のファイルの絶対パス 4047| ・char* dst_size; dst のメモリ領域サイズ 4048|************************************************************************/ 4049|void StrX_movePath( const char* src, 4050| const char* from_folder, const char* to_folder, 4051| char* dst, int dst_size ) 4052|{ 4053| int from_len = strlen( from_folder ); 4054| int to_len = strlen( to_folder ); 4055| 4056| if ( from_folder[from_len - 1] != '\\' ) from_len ++; 4057| 4058| ASSERT( strncmp( src, from_folder, from_len ) ); 4059| ASSERT( to_len < dst_size ); 4060| 4061| strcpy( dst, to_folder ); 4062| dst += to_len; 4063| if ( *(dst - 1) != '\\' ) { 4064| *dst = '\\'; dst++; 4065| } 4066| if ( to_len + (int)strlen( src + from_len ) >= dst_size ) 4067| error(); 4068| strcpy( dst, src + from_len ); 4069|} 4070| 4071| 4072| 4073|/************************************************************************** 4074| 10-15. <<< [StrX_getSpacedPath] 文字列の先頭から、空白を含んだファイルパスを取得する >>> 4075|【引数】 4076| ・char* str; ファイルパスを含んだ文字列 4077| ・char* path; ファイルパスを格納する領域(サイズは_MAX_PATH) 4078| ・char** param; str の中のパラメータの先頭位置を格納するアドレス(NULL可) 4079|【補足】 4080|・たとえば、"c:\Program Files\a.exe %1" から "c:\Program Files\a.exe" を 4081| 取得します。このとき、Program と Files の間の空白と、.exe の後の空白の違いを 4082| 存在するファイルのパスを参照して区別します。 4083|・str が "c:\Program Files\a.exe %1 %2" のとき、*param は、"%1 %2" になります。 4084|・空白を含んでいなくてもファイルパスを取得できます。 4085|***************************************************************************/ 4086|#if defined(USES_FILEX) && !defined(FOR_WINCE) 4087|void StrX_getSpacedPath( const char* str, char* path, char** param ) 4088|{ 4089| char* p; 4090| 4091| /* ファイルパスが "" で囲まれているとき */ 4092| if ( str[0] == '\"' ) { 4093| p = StrX_strchr2( str + 1, '\"' ); 4094| if ( p == NULL ) { 4095| strcpy( path, p + 1 ); 4096| if ( param != NULL ) *param = strchr( str + 1, '\0' ); 4097| } 4098| else { 4099| strncpy( path, str + 1, p - str - 1 ); 4100| do { 4101| p++; 4102| } while ( *p == ' ' ); 4103| if ( param != NULL ) *param = p; 4104| } 4105| } 4106| 4107| /* ファイルパスが "" で囲まれていないとき */ 4108| else { 4109| p = StrX_strchr2( str, ' ' ); 4110| while ( p != NULL ) { 4111| *p = '\0'; 4112| if ( FileX_isExist( str ) ) { 4113| strcpy( path, str ); 4114| *p = ' '; 4115| if ( param != NULL ) *param = p + 1; 4116| break; 4117| } 4118| *p = ' '; 4119| p = StrX_strchr2( p + 1, ' ' ); 4120| } 4121| if ( p == NULL ) { 4122| strcpy( path, str ); 4123| if ( param != NULL ) *param = strchr( str, '\0' ); 4124| } 4125| } 4126|} 4127|#endif 4128| 4129| 4130| 4131|/*********************************************************************** 4132| 10-16. <<< [StrX_toLongPath] 長いファイル名に変更する >>> 4133|【補足】 4134|・存在していないファイルを指定した場合、ファイル名は未定です。 4135|・相対パスを指定しないでください。 4136|・ネットワーク上のファイルパスには、使えません。 4137|・longPath と shortPath を同じアドレスに指定することもできます。 4138|・大文字または小文字に統一したパスから、実際のファイルの大文字小文字に 4139| 合わせるときにも使うことができます。 4140|・短いファイル名にするときは、API に GetShortPathName があります。 4141|************************************************************************/ 4142|#if defined(USES_BIGSTACK) && defined(USES_FILEX) && defined(USES_EXCEPT3) 4143|#if defined(FOR_WIN32) || defined(FOR_DOS32) 4144|char* StrX_toLongPath( char* longPath, const char* shortPath ) 4145|{ 4146| WIN32_FIND_DATA find; 4147| const char* p; 4148| char* workPath; /* ルートから子フォルダをたどるパス */ 4149| const char* sp; /* shortPath をたどる */ 4150| char* lp; /* longPath をたどる */ 4151| char* wp; /* workPath をたどる */ 4152| HANDLE h; 4153| 4154| ASSERT( FileX_isExist(shortPath) ); /* 引数に "" が無い可能性があります。*/ 4155| 4156| /* ルートフォルダのみのとき */ 4157| if ( shortPath[1] == ':' && shortPath[2] == '\\' && shortPath[3] == '\0' ) { 4158| strcpy( longPath, shortPath ); 4159| return longPath; 4160| } 4161| 4162| /* ネットワークパスのとき */ 4163| if ( shortPath[0] == '\\' && shortPath[1] == '\\' ) { 4164| strcpy( longPath, shortPath ); 4165| return longPath; 4166| } 4167| 4168| BigStack_start(); 4169| sp = shortPath; 4170| lp = longPath; 4171| workPath = wp = BigStack_alloc( _MAX_PATH ); 4172| 4173| /* ルートフォルダまで(ドライブ名など)をコピーする */ 4174| p = strchr( sp, '\\' ); 4175| ASSERT( p != NULL ); 4176| for ( sp = shortPath; sp <= p; sp++ ) { 4177| *wp = *sp; wp++; 4178| *lp = *sp; lp++; 4179| } 4180| 4181| /* ファイル名の追加 */ 4182| for(;;) { 4183| 4184| /* 次の workPath を作る */ 4185| p = StrX_strchr2( sp, '\\' ); if ( p == NULL ) break; 4186| for ( ; sp < p; sp++ ) { 4187| *wp = *sp; wp++; 4188| } 4189| *wp = '\0'; 4190| 4191| /* 長いファイル名を追加する */ 4192| FindFirstFile( workPath, &find ); 4193| for ( p = find.cFileName; *p != '\0'; p++ ) { 4194| *lp = *p; lp++; 4195| } 4196| sp++; 4197| *wp = '\\'; wp++; 4198| *lp = '\\'; lp++; 4199| } 4200| strcpy( workPath, shortPath ); 4201| if ( shortPath[strlen(shortPath)-1] != '\\' ) { 4202| if ( strlen( shortPath ) > 3 ) 4203| StrX_cutLastOf( workPath, '\\' ); 4204| h = FindFirstFile( workPath, &find ); 4205| ASSERT( h != INVALID_HANDLE_VALUE ); /*ときどき判断しないぞ*/ 4206| for ( p = find.cFileName; *p != '\0'; p++ ) { 4207| *lp = *p; lp++; 4208| } 4209| *lp = '\0'; 4210| } 4211| 4212| FindClose( h ); 4213| 4214| BigStack_end(); 4215| return longPath; 4216|} 4217|#endif 4218|#endif 4219| 4220| 4221|/*********************************************************************** 4222| 10-17. <<< [StrX_refFName] パス中のファイル名を参照する >>> 4223|【引数】 4224| ・char* path; パス(フォルダ指定付き) 4225| ・char* 返り値; ファイル名(フォルダ指定なし) 4226|【補足】 4227|・内容は、StrX_cpyFName 関数とほとんど同じですが、path の末尾に 4228| '\'が付いている場合、返り値にも'\' が付くので注意してください。 4229| 例:path="sub\file\" ... 返り値="file\" 4230|・返り値の内容は、path と同じ領域を参照しています。 4231|************************************************************************/ 4232|char* StrX_refFName( const char* path ) 4233|{ 4234| char* p = strchr( path, '\0' ) - 1; 4235| 4236| if ( *p == StrX_DirMark_char && p + 1 != path && p != path ) { 4237| char* p2; 4238| 4239| if ( p > path && ( *(p - 1) == ':' || *(p - 1) == StrX_DirMark_char ) ) 4240| return p+1; /* ルート */ 4241| 4242| *p = '\0'; 4243| p2 = StrX_RSearchC2( path, StrX_DirMark_char ); 4244| *p = StrX_DirMark_char; 4245| return p2 + 1; 4246| } 4247| else { 4248| p = StrX_RSearchC2( path, StrX_DirMark_char ); 4249| if ( p == NULL ) return (char*)path; 4250| else return p + 1; 4251| } 4252|} 4253| 4254| 4255| 4256|/*********************************************************************** 4257| 10-18. <<< [StrX_cpyFName] パス中のファイル名をコピーする >>> 4258|【引数】 4259| ・char* fname; ファイル名を格納するアドレス 4260| ・char* 返り値; fname と同じ 4261|【補足】 4262|・fname のサイズは、path と同じサイズにします。 4263|・fname と path が同じアドレスでも構いません。 4264|【例】 4265|・path="b:\dir\fname.txt" なら fname="fname.txt" 4266|・path="b:\dir\subdir\" なら fname="subdir" 4267|・path="step\" なら fname="step" 4268|・path="step" なら fname="step" 4269|************************************************************************/ 4270|char* StrX_cpyFName( char* fname, const char* path ) 4271|{ 4272| char* path_last = strchr( path, '\0' ) - 1; 4273| char* p; 4274| char* p2; 4275| 4276| /* path の末尾がフォルダ区切り記号でない場合 */ 4277| if ( (*path_last != '/' && *path_last != '\\') || 4278| StrX_isSJis2byte( path, path_last ) ) { 4279| 4280| /* 最後のフォルダ区切り記号から path の末尾までコピーする */ 4281| p = StrX_RSearchC2( path, '/' ); 4282| p2 = StrX_RSearchC2( path, '\\' ); 4283| if ( p < p2 ) p = p2; 4284| if ( p == NULL ) return strcpy( fname, path ); 4285| else return strcpy( fname, p+1 ); 4286| } 4287| 4288| /* そうでない場合、 */ 4289| else { 4290| /* 一度、末尾に文字列終端文字を置いて、同様にコピーする */ 4291| *path_last = '\0'; 4292| p = StrX_RSearchC2( path, '/' ); 4293| p2 = StrX_RSearchC2( path, '\\' ); 4294| if ( p < p2 ) p = p2; 4295| if ( p == NULL ) strcpy( fname, path ); 4296| else strcpy( fname, p+1 ); 4297| *path_last = StrX_DirMark_char; /* 戻す */ 4298| return fname; 4299| } 4300|} 4301| 4302| 4303| 4304|/*********************************************************************** 4305| 10-19. <<< [StrX_cpyFolder] パス中のファイル名以外をコピーする >>> 4306|【引数】 4307| ・char* folder; フォルダパスを格納するアドレス 4308| ・char* 返り値; folder と同じ 4309|【補足】 4310|・folder のサイズは、path と同じサイズにします。 4311|・folder と path が同じアドレスでも構いません。 4312|************************************************************************/ 4313|char* StrX_cpyFolder( char* folder, const char* path ) 4314|{ 4315| strcpy( folder, path ); 4316| StrX_cutFName( folder ); 4317| return folder; 4318|} 4319| 4320| 4321| 4322|/*********************************************************************** 4323| 10-20. <<< [StrX_cutFName] パス中のファイル名を削除する >>> 4324|【引数】 4325| ・char* 返り値; path と同じ 4326|【補足】 4327|・フォルダの区切り記号は '\' でも '/' でも構いません 4328|【例】 4329|・path="b:\dir\fname.txt" なら "b:\dir" 4330|・path="b:\dir\subdir\" なら "b:\dir" 4331|・path="step\" なら "" 4332|・path="step" なら "" 4333|************************************************************************/ 4334|char* StrX_cutFName( char* path ) 4335|{ 4336| char* p; 4337| char* p_last; 4338| char* lastTerm = NULL; 4339| 4340| /* 末尾のディレクトリ区切り記号を取り除く */ 4341| p = strchr( path, '\0' ) - 1; 4342| if ( *p == '\\' || *p == '/' ) { 4343| *p = '\0'; 4344| } 4345| else 4346| p++; 4347| 4348| /* ルートでない限り、いちばん後ろのディレクトリ区切り記号を '\0'にする */ 4349| p_last = p; 4350| p = path; 4351| while ( p <= p_last ) { 4352| if ( *p == '\\' || *p == '/' ) { 4353| lastTerm = p; 4354| } 4355| else if ( _ismbblead( *p ) ) 4356| p++; 4357| p++; 4358| } 4359| if ( lastTerm == NULL ) { 4360| *path = '\0'; 4361| } 4362| else { 4363| if ( lastTerm == path + 2 && *(path + 1) == ':' ) 4364| lastTerm ++; 4365| *lastTerm = '\0'; 4366| } 4367| 4368| return path; 4369|} 4370| 4371| 4372| 4373|/*********************************************************************** 4374| 10-21. <<< [StrX_addFName] パスにファイル名を追加する >>> 4375|【引数】 4376| ・char* 返り値; path と同じ 4377|【補足】 4378|・path の領域サイズに注意してください。 4379|・fname に、相対パスを指定した場合、後で、StrX_toRegularPath 関数を 4380| 呼び出してください。 4381|【例】 4382|・path="b:\subdir\" に "fname.txt" を追加したら "b:\subdir\fname.txt" 4383|・path="b:\f.txt" に "fname.txt" を追加したら "b:\f.txt\fname.txt" 4384|・path="" に "fname.txt" を追加したら "fname.txt" 4385|・path="b:\sub\f.txt" に "a:\fname.txt" を追加したら "a:\fname.txt" 4386|************************************************************************/ 4387|char* StrX_addFName( char* path, const char* fname ) 4388|{ 4389| if ( *path == '\0' || fname[1] == ':' ) { 4390| strcpy( path, fname ); 4391| } 4392| else { 4393| StrX_setLast( path, StrX_DirMark_char ); 4394| strcat( path, fname ); 4395| } 4396| return path; 4397|} 4398| 4399| 4400| 4401|/*********************************************************************** 4402| 10-22. <<< [StrX_insLastOfFName] ファイル名の末尾に文字列を挿入する(拡張子はそのまま) >>> 4403|************************************************************************/ 4404|char* StrX_insLastOfFName( char* path, char* ins ) 4405|{ 4406| char* ext = StrX_refExt( path ); 4407| int len = strlen(ins); 4408| 4409| if ( *ext == '\0' ) 4410| strcat( path, ins ); 4411| else { 4412| memmove( ext + len - 1, ext - 1, strlen( ext ) + 2 ); 4413| strncpy( ext - 1, ins, len ); 4414| } 4415| return path; 4416|} 4417| 4418| 4419| 4420|/*********************************************************************** 4421| 10-23. <<< [StrX_cdFName] パスのディレクトリを変更する >>> 4422|【引数】 4423| ・char* cd; ディレクトリの変更先(相対パス可) 4424| ・char* 返り値; path と同じ、内容は変更後のパス 4425|【補足】 4426|・path の領域サイズに注意してください。 4427|【例】 4428|・path="b:\subdir\fname.txt", cd="sub" なら "b:\subdir\sub\fname.txt" 4429|・path="..\subdir\fname.txt", cd="sub" なら "..\subdir\sub\fname.txt" 4430|・path="fname.txt", cd="\sub" なら "\sub\fname.txt" 4431|・path="..\subdir\fname.txt", cd="c:\sub" なら "c:\sub\fname.txt" 4432|************************************************************************/ 4433|#ifndef FOR_WINCE 4434|char* StrX_cdFName( char* path, const char* cd ) 4435|{ 4436| static char fname[_MAX_FNAME]; 4437| 4438| if ( cd[0] == '\\' || cd[1] == ':' ) { 4439| StrX_cpyFName( fname, path ); 4440| strcpy( path, cd ); 4441| StrX_addFName( path, fname ); 4442| } 4443| else { 4444| StrX_cpyFName( fname, path ); 4445| StrX_cutFName( path ); 4446| StrX_addFName( path, cd ); 4447| StrX_toRegularPath( path ); 4448| StrX_addFName( path, fname ); 4449| } 4450| 4451| return path; 4452|} 4453|#endif 4454| 4455| 4456| 4457|/*********************************************************************** 4458| 10-24. <<< [StrX_cdURL] 相対 URL のディレクトリを変更する >>> 4459|************************************************************************/ 4460|char* StrX_cdURL( char* url, const char* cd ) 4461|{ 4462| /* 作成中 */ 4463| cd; /* avoid warning */ 4464| return url; 4465|} 4466| 4467| 4468| 4469|/*********************************************************************** 4470| 10-25. <<< [StrX_refExt] 拡張子を参照する >>> 4471|【補足】 4472|・返り値は変更しないでください。 4473|・拡張子が無いときは、path の最後のヌル文字'\0'を指すポインタが返ります。 4474|************************************************************************/ 4475|char* StrX_refExt( const char* path ) 4476|{ 4477| char* p = strrchr( path, '.' ); 4478| char* name = StrX_refFName( path ); 4479| 4480| if ( p == NULL || p < name ) return strchr( path, '\0' ); 4481| else return (char*)p+1; 4482|} 4483| 4484| 4485| 4486|/*********************************************************************** 4487| 10-26. <<< [StrX_chgExt] 拡張子を変更する >>> 4488|【引数】 4489| ・char* path; ファイル名またはファイルパス 4490| ・char* ext; 変更後の拡張子 4491| ・char* 返り値; path(変更したファイル名またはファイルパス) 4492|【補足】 4493|・ext = "" と指定すると、拡張子を区切る "." も無くなります。 4494|************************************************************************/ 4495|char* StrX_chgExt( char* path, const char* ext ) 4496|{ 4497| char* p = strrchr( path, '.' ); 4498| char* name = StrX_refFName( path ); 4499| 4500| if ( p == NULL || p < name ) { 4501| if ( ext[0] != '\0' ) { 4502| strcat( path, "." ); 4503| strcat( path, ext ); 4504| } 4505| } 4506| else { 4507| if ( ext[0] == '\0' ) 4508| *p = '\0'; 4509| else 4510| strcpy( p+1, ext ); 4511| } 4512| return path; 4513|} 4514| 4515| 4516| 4517|/*********************************************************************** 4518| 10-27. <<< [StrX_setExt] 拡張子を設定する >>> 4519|【引数】 4520| ・char* path; ファイル名またはファイルパス 4521| ・char* ext; 変更後の拡張子 4522| ・char* 返り値; path(拡張子を設定したファイル名またはファイルパス) 4523|【補足】 4524|・path="abc.2", ext="txt" のとき、StrX_chgExt では "abc.txt" となりますが、 4525| 本関数では "abc.2.txt" となります。 4526|・path="abc.2.txt", ext="txt" のときは、"abc.2.txt" のままです。 4527|・ext = "" を指定すると、拡張子を区切る "." が最後に付きます。 4528|************************************************************************/ 4529|char* StrX_setExt( char* path, const char* ext ) 4530|{ 4531| char* p; 4532| 4533| p = StrX_refExt( path ); 4534| 4535| if ( stricmp( p, ext ) != 0 ) { 4536| p = strchr( p, '\0' ); 4537| 4538| *p = '.'; strcpy( p+1, ext ); 4539| } 4540| 4541| return path; 4542|} 4543| 4544| 4545| 4546|/*********************************************************************** 4547| 10-28. <<< [StrX_addNumInFName] ファイル名に標準的な通し番号を付ける >>> 4548|【引数】 4549| ・char* path; (出力)通し番号を付けたファイル名またはファイルパス 4550| ・char* src_path; 通し番号が付く前のファイル名またはファイルパス 4551| ・int num; 通し番号 4552| ・char* 返り値; path 4553|【補足】 4554|・src_path="abc.txt", num=1 のとき、"abc (1).txt" となります。 4555|・Windows Xp のエクスプローラでは、この関数で得られるような形式のファイル名を 4556| 複数選択して、一度に名前を変えることができます。 4557|・拡張子は src_path のものが保持されます。 4558|・path == src_path にできます。 4559|************************************************************************/ 4560|char* StrX_addNumInFName( char* path, const char* src_path, int num ) 4561|{ 4562| char* p; 4563| 4564| if ( path != src_path ) strcpy( path, src_path ); 4565| 4566| p = StrX_refExt( path ); 4567| if ( *p == '\0' ) 4568| sprintf( p, " (%d)", num ); 4569| else { 4570| char num2[20]; 4571| 4572| sprintf( num2, " (%d)", num ); 4573| StrX_ins( p - 1, num2 ); 4574| } 4575| 4576| return path; 4577|} 4578| 4579| 4580| 4581|/*********************************************************************** 4582| 10-29. <<< [StrX_cmpNoExt] 拡張子以外を比較する >>> 4583|【引数】 4584| ・char* path1; ファイル名またはファイルパス 4585| ・char* path2; ファイル名またはファイルパス 4586| ・int 返り値; 0より大小による比較結果 4587|【補足】 4588|・拡張子が異なっていても、ファイル名が同じときは0を返します。 4589|************************************************************************/ 4590|int StrX_cmpNoExt( const char* path1, const char* path2 ) 4591|{ 4592| const char* tree = path1; 4593| const char* period = path1; 4594| 4595| while ( toupper(*path1) == toupper(*path2) ) { 4596| switch ( *path1 ) { 4597| case '\\': tree = path1; break; 4598| case '.': period = path1; break; 4599| case '\0': return 0; 4600| } 4601| path1++; path2++; 4602| } 4603| if ( tree < period ) return 0; 4604| else return *path1 - *path2; 4605|} 4606| 4607| 4608| 4609|/*********************************************************************** 4610| 10-30. <<< [StrX_cpyWithoutURLSubName] URL のパスの後の名前をカットしてコピーする >>> 4611|【引数】 4612| ・char* path; URL のパスの後の名前をカットしたものを格納するアドレス 4613| ・char* url; URL 4614| ・char* 返り値; path 4615|【補足】 4616|・url = http://www.a.com/index.htm#name なら 4617| path = http://www.a.com/index.htm にします。 4618|・#name がなかったらそのままコピーします。 4619|************************************************************************/ 4620|char* StrX_cpyWithoutURLSubName( char* path, const char* url ) 4621|{ 4622| char* subName = StrX_refURLSubName( url ); 4623| 4624| if ( *subName == '\0' ) 4625| strcpy( path, url ); 4626| else { 4627| int n = subName - url - 1; 4628| strncpy( path, url, n ); 4629| path[n] = '\0'; 4630| } 4631| 4632| return path; 4633|} 4634| 4635| 4636| 4637|/*********************************************************************** 4638| 10-31. <<< [StrX_refURLSubName] URL のパスの後の名前を参照する >>> 4639|【引数】 4640| ・char* url; URL 4641| ・char* 返り値; URL のパスの後の名前(なし="") 4642|【補足】 4643|・URL のパスの後の名前とは、http://www.a.com/index.htm#name の name のこと。 4644|************************************************************************/ 4645|char* StrX_refURLSubName( const char* url ) 4646|{ 4647| char* p = StrX_RSearchC2( url, '.' ); 4648| char* s = StrX_RSearchC2( url, '#' ); 4649| 4650| if ( s == NULL || s < p ) { 4651| return ""; 4652| } 4653| else { 4654| return s + 1; 4655| } 4656|} 4657| 4658| 4659| 4660|/*-------------------------------------------------------------------------*/ 4661|/* ◆11. <<<< (StrX) char* 型の文字列(数値との変換・n進数) >>>> */ 4662|/*-------------------------------------------------------------------------*/ 4663| 4664| 4665| 4666|/*********************************************************************** 4667| 11-1. <<< 整数を 4桁の16進数に変換して文字列に格納する [StrX_initByInt16s()] >>> 4668|【引数】 4669| ・char* str 変換した16進数を格納する文字列のアドレス 4670| ・unsigned int n 変換する整数 4671|【補足】 4672|・変換した 16 進数の A〜F は大文字になります。 4673|・3桁以下の場合、先頭に 0 が付きます。例 "012F", "004A" 4674|・str のポイント先は 4byte以上確保してあること。 4675|・int は 16bit であること。 4676|************************************************************************/ 4677|void StrX_initByInt16s( char* str, unsigned int n ) 4678|{ 4679| unsigned int n1; 4680| 4681| n1 = n >> 12; 4682| if ( n1 <= 9 ) *str = '0' + n1; 4683| else *str = 'A' - 10 + n1; 4684| str ++; 4685| 4686| n1 = ( n << 4 ) >> 12; 4687| if ( n1 <= 9 ) *str = '0' + n1; 4688| else *str = 'A' - 10 + n1; 4689| str ++; 4690| 4691| n1 = ( n << 8 ) >> 12; 4692| if ( n1 <= 9 ) *str = '0' + n1; 4693| else *str = 'A' - 10 + n1; 4694| str ++; 4695| 4696| n1 = ( n & 0xF ); 4697| if ( n1 <= 9 ) *str = '0' + n1; 4698| else *str = 'A' - 10 + n1; 4699| str ++; 4700| 4701| *str = '\0'; 4702|} 4703| 4704| 4705| 4706|/*********************************************************************** 4707| 11-2. <<< 整数を 2桁の16進数に変換する [StrX_initByInt16s_2()] >>> 4708|【引数】 4709| ・char* str 変換した16進数を格納する文字列のアドレス 4710| ・unsigned int n 変換する整数 4711|【補足】 4712|・変換した 16 進数の A〜F は大文字になります。 4713|・1桁の場合、先頭に 0 が付きます。例 "0F" 4714|・str のポイント先は 2byte以上確保してあること。 4715|・int は 16bit であること。 4716|************************************************************************/ 4717|void StrX_initByInt16s_2( char* str, unsigned int n ) 4718|{ 4719| unsigned int n1; 4720| 4721| n = n & 0xFF; 4722| 4723| n1 = n >> 4; 4724| if ( n1 <= 9 ) *str = '0' + n1; 4725| else *str = 'A' - 10 + n1; 4726| str ++; 4727| 4728| n1 = ( n & 0xF ); 4729| if ( n1 <= 9 ) *str = '0' + n1; 4730| else *str = 'A' - 10 + n1; 4731| str ++; 4732| 4733| *str = '\0'; 4734|} 4735| 4736| 4737| 4738|/*********************************************************************** 4739| 11-3. <<< 整数を 8桁の16進数に変換する [StrX_initByLong16s()] >>> 4740|【引数】 4741| ・char* str 変換した16進数を格納する文字列のアドレス 4742| ・unsigned long n 変換する整数 4743|【補足】 4744|・変換した 16 進数の A〜F は大文字になります。 4745|・7桁以下の場合、先頭に 0 が付きます。例 "012F", "004A" 4746|・str のポイント先は 9byte以上確保してあること。 4747|・int は 16bit であること。 4748|************************************************************************/ 4749|void StrX_initByLong16s( char* str, unsigned long n ) 4750|{ 4751| int i; 4752| unsigned int n1; 4753| 4754| for ( i = 0; i < 8; i ++ ) { 4755| n1 = (int)(n >> 28); 4756| if ( n1 <= 9 ) *str = '0' + n1; 4757| else *str = 'A' - 10 + n1; 4758| str ++; 4759| n <<= 4; 4760| } 4761| 4762| *str = '\0'; 4763|} 4764| 4765| 4766| 4767|/*********************************************************************** 4768| 11-4. <<< 整数を文字列に変換して格納する [StrX_initByInt()] >>> 4769|【引数】 4770| ・char* str 変換した10進数を格納する文字列のアドレス 4771| ・int str_len str に格納できる最大の文字数 [byte] 4772| ・int n 変換する整数(負または正または0) 4773|【補足】 4774|・変換した整数は 10 進数で表現されます。 4775|・str_len を超える桁数の場合、上位 str_len 桁が格納されます。 4776|・桁数が超えたかどうかは確認できません。 4777|***********************************************************************/ 4778|void StrX_initByInt( char* str, int str_len, int n ) 4779|{ 4780| int n1; /* 一桁の数字 */ 4781| int base = 10000; 4782| int setF = 0; /* 数字を1つでも格納したかどうか 1=した、0=しない */ 4783| char* str_over = str + str_len; /* str_len 文字を超えた str の位置 */ 4784| 4785| /* 負の符号を格納する */ 4786| if ( n < 0 ) { 4787| *str = '-'; str++; 4788| n = -n; 4789| } 4790| 4791| /* 上位から数字を格納する */ 4792| if ( n != 0 && n != -32768 ) { 4793| do { 4794| n1 = n / base; 4795| if ( n1 != 0 || setF == 1 ) { 4796| *str = '0' + n1; str++; 4797| if ( str == str_over ) break; /* 桁あふれ */ 4798| setF = 1; 4799| } 4800| n -= n1 * base; 4801| base /= 10; 4802| } while ( base > 0 ); 4803| } 4804| else if ( n == 0 ) { 4805| *str = '0'; str++; 4806| } 4807| else /* if ( n == 32768 ) */ { 4808| *str = '3'; str++; 4809| if ( str == str_over ) goto endif1; /* 桁あふれ */ 4810| *str = '2'; str++; 4811| if ( str == str_over ) goto endif1; /* 桁あふれ */ 4812| *str = '7'; str++; 4813| if ( str == str_over ) goto endif1; /* 桁あふれ */ 4814| *str = '6'; str++; 4815| if ( str == str_over ) goto endif1; /* 桁あふれ */ 4816| *str = '8'; str++; 4817| endif1:; 4818| } 4819| 4820| *str = '\0'; 4821|} 4822| 4823| 4824| 4825|/*********************************************************************** 4826| 11-5. <<< 文字列から整数を取得する [StrX_scanInt()] >>> 4827|【引数】 4828| ・char* str 10進数が格納された文字列 4829| ・int n 取得した数値を格納する変数のアドレス 4830| ・char* 返り値; 数値の次の文字のアドレス 4831|【補足】 4832|・str のアドレスの内容は、数字か + か - である必要があります。 4833|・返り値が要らない場合、atoi があります。 4834|***********************************************************************/ 4835|char* StrX_scanInt( const char* str, int* n ) 4836|{ 4837| int flag = 1; 4838| int num = 0; 4839| 4840| if ( *str == '+' ) str++; 4841| while ( *str == '-' ) { str++; flag = -flag; } 4842| 4843| while ( *str >= '0' && *str <= '9' ) { 4844| num = num * 10 + (*str - '0'); 4845| str++; 4846| } 4847| 4848| *n = flag * num; 4849| 4850| return (char*)str; 4851|} 4852| 4853| 4854| 4855|/*********************************************************************** 4856| 11-6. <<< long 型の n から s へ2進数を格納する [StrX_get2s_fromLong()] >>> 4857|【引数】 4858| ・char* s; 2進数の文字列を格納するアドレス(33〜36byte) 4859| ・unsigned long n; long 型の数値 4860| ・char term; 8桁ごとの区切り文字, '\0' なら区切らない 4861| ・char* 返り値; s と同じ 4862|【補足】 4863|・s のエディアンは n と同じ 4864|・例:n=0x1234, term=':' なら s = "00000000:00000000:00010010:00110100" 4865|・例:n=0x1234, term='\0' なら s = "00000000000000000001001000110100" 4866|************************************************************************/ 4867|char* StrX_get2s_fromLong( char* s, unsigned long n, char term ) 4868|{ 4869| int i; 4870| char* sp = s; 4871| const char* p; 4872| const static char* dig[0x10] = { 4873| "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", 4874| "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" }; 4875| 4876| for ( i = 0; i < 4; i++ ) { 4877| p = dig[n >> 28]; 4878| *sp++ = *p++; *sp++ = *p++; *sp++ = *p++; *sp++ = *p; 4879| n <<= 4; 4880| p = dig[n >> 28]; 4881| *sp++ = *p++; *sp++ = *p++; *sp++ = *p++; *sp++ = *p; 4882| n <<= 4; 4883| if ( term != '\0' && i < 3 ) *sp++ = term; 4884| } 4885| *sp = '\0'; 4886| 4887| return s; 4888|} 4889| 4890| 4891| 4892|/*********************************************************************** 4893| 11-7. <<< 2進数の文字列 s の数値を long 型で返す [StrX_getLong_from2s()] >>> 4894|【引数】 4895| ・char* s; 2進数の文字列へのアドレス 4896| ・long 返り値; 数値 4897|【補足】 4898|・s に区切り文字('0','1'以外)があっても構わない。 4899|・例:s = "00000000:00000000:00010010:00110100" なら 返り値=0x1234 4900|・例:s = "00000000000000000001001000110100" なら 返り値=0x1234 4901|・s は、8の倍数の桁数でなくてもよい。 4902| 例:s = "10010:00110100" なら 返り値=0x1234 4903|・32桁以上指定しないでください 4904|***********************************************************************/ 4905|long StrX_getLong_from2s( char* s ) 4906|{ 4907| long result = 0; 4908| long base = 0x0001; 4909| char* sp; 4910| 4911| /* sp を下の桁にポイントする */ 4912| for ( sp = s; *sp != '\0'; sp++ ); 4913| 4914| /* 下の桁から変換する */ 4915| for ( ; sp > s; sp-- ) { 4916| switch ( *sp ) { 4917| case '0': base <<= 1; break; 4918| case '1': result += base; base <<= 1; break; 4919| default: break; 4920| } 4921| } 4922| 4923| return result; 4924|} 4925| 4926| 4927| 4928|/*********************************************************************** 4929| 11-8. <<< [StrX_getColorValue] カラー文字列から数値を得る >>> 4930|【引数】 4931| ・char* color_str; カラー文字列、"rgb(R,G,B)", 例:"rgb(192,192,255)" 4932| ・Color_WinRGB 返り値; カラーの数値 4933|************************************************************************/ 4934|#ifdef USES_COLOR 4935|Color_WinRGB StrX_getColorValue( const char* color_str ) 4936|{ 4937| const char* p; 4938| Color_WinRGB color; 4939| 4940| p = strchr( color_str, '(' ); 4941| if ( p == NULL ) return false; 4942| color = atoi( p + 1 ); /* RED */ 4943| p = strchr( p, ',' ); 4944| if ( p == NULL ) return false; 4945| color |= atoi( p + 1 ) << 8; /* GREEN */ 4946| p = strchr( p + 1, ',' ); 4947| if ( p == NULL ) return false; 4948| color |= atoi( p + 1 ) << 16; /* BLUE */ 4949| 4950| return color; 4951|} 4952|#endif 4953| 4954| 4955| 4956|/*********************************************************************** 4957| 11-9. <<< [StrX_getColorStr] カラーの数値からカラー文字列を取得する >>> 4958|【引数】 4959| ・char* color_str; (出力)カラー文字列を格納する領域の先頭アドレス 4960| ・Color_WinRGB value; カラーの数値 4961|【補足】 4962|・関連:StrX_getColorValue 4963|・color_str は、17バイト以上の領域を指定してください。 4964|・color_str は、次のフォーマットで格納されます。"rgb(R,G,B)", 例:"rgb(192,192,255)" 4965|************************************************************************/ 4966|#ifdef USES_COLOR 4967|void StrX_getColorStr( char* color_str, Color_WinRGB value ) 4968|{ 4969| sprintf( color_str, "rgb(%d,%d,%d)", 4970| Color_WinRGB_getR( value ), Color_WinRGB_getG( value ), 4971| Color_WinRGB_getB( value ) ); 4972|} 4973|#endif 4974| 4975| 4976| 4977|/*********************************************************************** 4978| 11-10. <<< [StrX_getFontValue] フォント文字列から各属性を取得する >>> 4979|【引数】 4980| ・char* font_str; フォント文字列、"face, size, bold, italic" 4981| ・char* face; (出力)フォント名(font_str のより大きいこと) 4982| ・char* size10; (出力)フォントサイズの10倍 4983| ・bool* bBold; (出力)太字かどうか 4984| ・bool* bItalic; (出力)斜め文字かどうか 4985|【補足】 4986|・フォント文字列の中のフォントサイズは、10倍ではなく小数で記述します。 4987|・フォント文字列の中の bool 値は、1 or 0 で記述します。 4988|************************************************************************/ 4989|void StrX_getFontValue( const char* font_str, char* face, int* size10, 4990| bool* bBold, bool* bItalic ) 4991|{ 4992| int font_str_size = strlen(font_str) + 1; 4993| char s[256]; 4994| 4995| StrX_getCSV( font_str, 1, face, font_str_size ); 4996| StrX_getCSV( font_str, 2, s, font_str_size ); 4997| *size10 = atoi( s ) * 10; 4998| StrX_getCSV( font_str, 3, s, font_str_size ); 4999| *bBold = s[0] != '0'; 5000| StrX_getCSV( font_str, 4, s, font_str_size ); 5001| *bItalic = s[0] != '0'; 5002|} 5003| 5004| 5005| 5006|/*********************************************************************** 5007| 11-11. <<< [StrX_getFontStr] フォント文字列を作成する >>> 5008|【引数】 5009| ・char* font_str; (出力)フォント文字列、"face, size, bold, italic" 5010| ・char* face; フォント名 5011| ・char size10; フォントサイズの10倍 5012| ・bool bBold; 太字かどうか 5013| ・bool bItalic; 斜め文字かどうか 5014|【補足】 5015|・フォント文字列の中のフォントサイズは、10倍ではなく小数で記述します。 5016|・フォント文字列の中の bool 値は、1 or 0 で記述します。 5017|************************************************************************/ 5018|void StrX_getFontStr( char* font_str, const char* face, int size10, 5019| bool bBold, bool bItalic ) 5020|{ 5021| sprintf( font_str, "%s, %d, %d, %d", face, size10 / 10, bBold != 0, bItalic != 0 ); 5022|} 5023| 5024| 5025| 5026|/*-------------------------------------------------------------------------*/ 5027|/* ◆12. <<<< (StrX_ListElem) リストの要素になる文字列 >>>> */ 5028|/*-------------------------------------------------------------------------*/ 5029| 5030| 5031| 5032|#ifdef USES_LISTX 5033| 5034|#ifdef USES_SYM 5035|SYM_STRUCT_START( StrX_ListElem ) 5036|SYM_STRUCT_MEMB( StrX_ListElem, char*, p ) 5037|SYM_STRUCT_END( StrX_ListElem ) 5038|#endif 5039| 5040| 5041| 5042|/*********************************************************************** 5043| 12-1. <<< [StrX_ListElem_finish2] リスト要素の文字列を後始末する >>> 5044|************************************************************************/ 5045|void StrX_ListElem_finish2( StrX_ListElem* m ) 5046|{ 5047| free( m->p ); 5048|} 5049| 5050| 5051| 5052|#endif 5053| 5054| 5055| 5056|/*-------------------------------------------------------------------------*/ 5057|/* ◆13. <<<< (StrX_Mem) 文字列領域 >>>> */ 5058|/*-------------------------------------------------------------------------*/ 5059| 5060| 5061| 5062|/************************************************************************** 5063| 13-1. <<< [StrX_Mem_init] 初期化する >>> 5064|【補足】 5065|・buf に malloc したアドレスを指定した場合、StrX_Mem_getTopAdr で取得 5066| できるアドレスを free することを忘れないでください。 5067|**************************************************************************/ 5068|void StrX_Mem_init( StrX_Mem* m, char* buf, size_t buf_sizeof ) 5069|{ 5070| m->buf = buf; 5071| m->buf_over = buf + buf_sizeof; 5072| m->pBuf = buf; 5073| *buf = '\0'; 5074|} 5075| 5076| 5077| 5078|/************************************************************************** 5079| 13-2. <<< [StrX_Mem_toEmpty] 記憶領域に入っているすべての文字列を消去する >>> 5080|**************************************************************************/ 5081|void StrX_Mem_toEmpty( StrX_Mem* m ) 5082|{ 5083| m->pBuf = m->buf; 5084| *m->buf = '\0'; 5085|} 5086| 5087| 5088| 5089|/************************************************************************** 5090| 13-3. <<< [StrX_Mem_alloc] 記憶領域を確保する >>> 5091|【補足】 5092|・空き領域が無ければ、 NULL を返します。 5093|・この関数によって返されたアドレスには、1つの文字列しか格納できません。 5094| 2つ目の文字列を格納する前に、再び alloc してください。 5095|・alloc した領域に文字列を格納する前に、次の alloc をすることはできません。 5096| つまり、alloc を連続して2回呼び出して、あとからその2つの領域に 5097| 格納することは出来ません。alloc してすぐに格納してください。 5098|【内部補足】 5099|・内部バッファは次のように変化していきます。(\='\0') 5100| \ init pBuf=0, left=9 5101| \\ alloc pBuf=1, left=9 5102| \abc\ strcpy pBuf=1, left=5 5103| \abc\\ alloc pBuf=5, left=5 5104| \abc\123\ strcpy pBuf=5, left=1 5105|**************************************************************************/ 5106|char* StrX_Mem_alloc( StrX_Mem* m ) 5107|{ 5108| m->pBuf = strchr( m->pBuf, '\0' ) + 1; 5109| 5110| if ( m->pBuf >= m->buf_over ) { 5111| error2_0( StrX_Err_MemEmpty, "アプリ内部のメモリ領域が足りません" ); 5112| } 5113| 5114| *m->pBuf = '\0'; 5115| 5116| return m->pBuf; 5117|} 5118| 5119| 5120| 5121|/************************************************************************** 5122| 13-4. <<< [StrX_Mem_alloc2] 記憶領域を初期化して確保する >>> 5123|【引数】 5124| ・const char* str; 初期化する内容 5125| ・char* 返り値; 確保した領域のアドレス 5126|【補足】 5127|・空き領域が無ければ、 NULL を返します。 5128|・空き領域が少なければ、入るだけ入れます。 5129|**************************************************************************/ 5130|char* StrX_Mem_alloc2( StrX_Mem* m, const char* str ) 5131|{ 5132| size_t size, len; 5133| char* p; 5134| 5135| /* 記憶領域を確保する ★ */ 5136| p = StrX_Mem_alloc( m ); 5137| if ( p == NULL ) return p; 5138| 5139| /* 初期化する */ 5140| len = strlen( str ); 5141| size = StrX_Mem_getLeftSize( m ); 5142| if ( len < size ) strcpy( p, str ); 5143| else { strncpy( p, str, size-1 ); p[size-1] = '\0'; } 5144| 5145| return p; 5146|} 5147| 5148| 5149| 5150|/************************************************************************** 5151| 13-5. <<< [StrX_Mem_alloc3] 記憶領域を効率よく初期化して確保する >>> 5152|【機能】 5153|・前回代入した文字列と同じ内容で初期化する場合、記憶領域を確保しないで、 5154| 前回返したアドレスを再び返します。 5155|【引数】 5156| ・const char* str; 初期化する内容 5157| ・char* 返り値; 確保した領域のアドレス 5158|【補足】 5159|・同じ内容の場合、同じ領域を参照することになるので、なるべく内容を変更しない 5160| ようにしてください。 5161|・空き領域が無ければ、NULL を返します。 5162|・空き領域が少なければ、入るだけ入れます。 5163|・前々回以前の文字列に対しても効率よく行う場合は Dic コンポーネントを 5164| 使ってください。 5165|**************************************************************************/ 5166|char* StrX_Mem_alloc3( StrX_Mem* m, const char* str ) 5167|{ 5168| if ( strcmp( str, m->pBuf ) == 0 ) return m->pBuf; 5169| else return StrX_Mem_alloc2( m, str ); 5170|} 5171| 5172| 5173| 5174|/************************************************************************** 5175| 13-6. <<< [StrX_Mem_copyAlloc] 文字列領域を確保して、初期値を代入する >>> 5176|【引数】 5177| ・char* str; 初期値文字列 5178| ・char* 返り値; 確保した文字列領域の先頭アドレス 5179|【補足】 5180|・文字列領域は、StrX_Mem_alloc3 と同じ様に効率よく確保します。 5181|**************************************************************************/ 5182|char* StrX_Mem_copyAlloc( StrX_Mem* m, const char* str ) 5183|{ 5184| if ( strcmp( str, m->pBuf ) == 0 ) return strcpy( m->pBuf, str ); 5185| else return StrX_Mem_alloc2( m, str ); 5186|} 5187| 5188| 5189| 5190|/************************************************************************** 5191| 13-7. <<< [StrX_Mem_free] 前回 StrX_Mem_alloc した領域を次回も使うようにする >>> 5192|【引数】 5193| ・const char* adr; 解放するメモリ領域のアドレス 5194|【補足】 5195|・adr には、直前の StrX_Mem_alloc 関数で返されたアドレスを指定します。 5196|・連続して free する場合、スタックのように alloc した逆の順番に指定して 5197| いきます。 5198|【内部補足】 5199|・内部バッファは次のように変化していきます。(\='\0') 5200| strcpy後 \abc\123\ pBuf=5, left=1 5201| \abc\ pBuf=4, left=5 5202| \ pBuf=0, left=9 5203| alloc後 \abc\\ pBuf=5, left=5 5204| \abc\ pBuf=4, left=5 5205|**************************************************************************/ 5206|void StrX_Mem_free( StrX_Mem* m, const char* adr ) 5207|{ 5208| if ( m->pBuf == m->buf ) 5209| return; 5210| 5211| do { 5212| m->pBuf --; 5213| } while( *m->pBuf != '\0' ); 5214| ASSERT( m->pBuf + 1 == adr ); 5215|} 5216| 5217| 5218| 5219|/************************************************************************** 5220| 13-8. <<< [StrX_Mem_getLeftSize] 残りメモリサイズを返す >>> 5221|**************************************************************************/ 5222|size_t StrX_Mem_getLeftSize( StrX_Mem* m ) 5223|{ 5224| if ( m->buf_over == m->pBuf ) { 5225| #ifndef NDEBUG 5226| error(); 5227| #endif 5228| return 0; 5229| } 5230| return m->buf_over - m->pBuf - strlen( m->pBuf ) - 1; 5231|} 5232| 5233| 5234| 5235|/************************************************************************** 5236| 13-9. <<< [StrX_Mem_getNext] 文字列を先頭から順番にたどる >>> 5237|【引数】 5238| ・char* cur; 現在の文字列のアドレス(NULL=先頭の文字列を返す) 5239| ・char* 返り値; 次の文字列のアドレス(NULL=次は無い) 5240|**************************************************************************/ 5241|char* StrX_Mem_getNext( StrX_Mem* m, char* cur ) 5242|{ 5243| if ( cur == NULL ) { 5244| if ( m->pBuf == m->buf ) return NULL; 5245| else return m->buf + 1; 5246| } 5247| else { 5248| if ( cur >= m->pBuf ) return NULL; 5249| else return strchr( cur, '\0' ) + 1; 5250| } 5251|} 5252| 5253| 5254| 5255|/************************************************************************** 5256| 13-10. <<< [StrX_Mem_print] デバッグ表示する >>> 5257|**************************************************************************/ 5258|#ifndef ERRORS_CUT_DEBUG_TOOL 5259|void StrX_Mem_print( StrX_Mem* m, const char* title ) 5260|{ 5261| Errors_printf( "%sStrX_Mem[%p] buf=%p, buf_over = %p, pBuf = %p, checked = %d", 5262| title, m, m->buf, m->buf_over, m->pBuf, m->checked ); 5263|} 5264|#endif /* #ifndef ERRORS_CUT_DEBUG_TOOL */ 5265| 5266| 5267| 5268|/************************************************************************** 5269| 13-11. <<< [StrX_Mem_printAll] すべての文字列を表示する >>> 5270|**************************************************************************/ 5271|#ifndef ERRORS_CUT_DEBUG_TOOL 5272|void StrX_Mem_printAll( StrX_Mem* m ) 5273|{ 5274| char* s; 5275| 5276| Errors_printf( "StrX_Mem:" ); 5277| for ( StrX_Mem_forEach( m, &s ) ) { 5278| Errors_printf( " %s", s ); 5279| } 5280|} 5281|#endif /* #ifndef ERRORS_CUT_DEBUG_TOOL */ 5282| 5283| 5284| 5285|/*-------------------------------------------------------------------------*/ 5286|/* ◆14. <<<< (StrX_Set) 文字列の記憶領域の部分集合 >>>> */ 5287|/*-------------------------------------------------------------------------*/ 5288| 5289| 5290| 5291|/************************************************************************** 5292| 14-1. <<< [StrX_Set_printAll] 部分集合に含まれるすべての文字列を表示する >>> 5293|**************************************************************************/ 5294|#ifdef USES_STDLIBS 5295|#ifndef ERRORS_CUT_DEBUG_TOOL 5296|void StrX_Set_printAll( StrX_Set* m ) 5297|{ 5298| char* s; 5299| 5300| Errors_printf( "StrX_Set:" ); 5301| for ( StrX_Set_forEach( m, &s ) ) { 5302| Errors_printf( " %s", s ); 5303| } 5304|} 5305|#endif /* #ifndef ERRORS_CUT_DEBUG_TOOL */ 5306|#endif 5307| 5308| 5309| 5310|/************************************************************************** 5311| 14-2. <<< [StrX_Set_searchWild] ワイルドカードで文字列を検索する >>> 5312|【引数】 5313| ・SetX_Set* m; 文字列の集合 5314| ・char* wildkey; 検索キー(ワイルドカード可) 5315| ・int 返り値; 番号(0〜)、見つからない=−1 5316|【補足】 5317|・返り値は、StrX_Mem_alloc で最初に格納した文字列が検索されたときが0、 5318| 次に格納した文字列では1、続いて 2,3... となります。 5319|**************************************************************************/ 5320|#ifdef USES_STDLIBS 5321|int StrX_Set_searchWild( StrX_Set* m, const char* wildkey ) 5322|{ 5323| char* s; 5324| int i = 0; 5325| 5326| for ( StrX_Set_forEach( m, &s ) ) { 5327| if ( StrX_cmpWild( wildkey, s ) == 0 ) 5328| return i; 5329| i++; 5330| } 5331| return -1; 5332|} 5333|#endif 5334| 5335| 5336| 5337|/************************************************************************** 5338| 14-3. <<< [StrX_Set_searchWild2] 文字列に一致するワイルドカードを検索する >>> 5339|【引数】 5340| ・SetX_Set* wilds; ワイルドカードを含む文字列の集合 5341| ・char* key; 検索キー(ワイルドカード不可) 5342| ・int 返り値; 番号(0〜)、見つからない=−1 5343|【補足】 5344|・返り値は、StrX_Set_searchWild 関数と同じです。 5345|**************************************************************************/ 5346|#ifdef USES_STDLIBS 5347|int StrX_Set_searchWild2( StrX_Set* wilds, const char* key ) 5348|{ 5349| char* s; 5350| int i = 0; 5351| 5352| for ( StrX_Set_forEach( wilds, &s ) ) { 5353| if ( StrX_cmpWild( s, key ) == 0 ) 5354| return i; 5355| i++; 5356| } 5357| return -1; 5358|} 5359|#endif 5360| 5361| 5362| 5363|/*-------------------------------------------------------------------------*/ 5364|/* ◆15. <<<< (StrX_MemV) 文字列の記憶領域(malloc 使用)>>>> */ 5365|/*-------------------------------------------------------------------------*/ 5366| 5367| 5368| 5369|/*********************************************************************** 5370| 15-1. <<< [StrX_MemV_init] 初期化する >>> 5371|************************************************************************/ 5372|#ifdef STRX_USES_MALLOC 5373|#ifdef USES_LISTX 5374|void StrX_MemV_init( StrX_MemV* m ) 5375|{ 5376| StrX_MemVE* ve = (StrX_MemVE*)malloc( sizeof(StrX_MemVE) ); 5377| void* memX = malloc( StrX_MemV_unitSize ); 5378| 5379| /* malloc できないとき、エラーにする */ 5380| StdPlus_chkMalloc( ve, memX, StdPlus_End ); 5381| 5382| ERRORS_FINISHCHK_FOR_INIT( StrX_MemV_finish ); 5383| 5384| /* 初期化する */ 5385| ListX_init( &m->mems ); 5386| ListX_addFirst( &m->mems, ve ); 5387| StrX_Mem_init( &ve->mem, memX, StrX_MemV_unitSize ); 5388| 5389| m->mem_last = ve; 5390| m->maxLen = StrX_MemV_maxLen; 5391|} 5392|#endif 5393|#endif 5394| 5395| 5396| 5397|/*********************************************************************** 5398| 15-2. <<< [StrX_MemV_finish] 後始末する >>> 5399|************************************************************************/ 5400|#ifdef STRX_USES_MALLOC 5401|#ifdef USES_LISTX 5402|void StrX_MemV_finish( StrX_MemV* m ) 5403|{ 5404| StrX_MemVE* ve; 5405| StrX_MemVE* ve2; 5406| 5407| for ( ListX_forEachFree( &m->mems, &ve, StrX_MemVE, &ve2, free ) ) { 5408| StdPlus_free( StrX_Mem_getTopAdr( &ve->mem ) ); 5409| } 5410| ERRORS_FINISHCHK_FOR_FINISH( StrX_MemV_finish ); 5411|} 5412|#endif 5413|#endif 5414| 5415| 5416| 5417|/*********************************************************************** 5418| 15-3. <<< [StrX_MemV_alloc] メモリ領域を確保する >>> 5419|【補足】 5420|・返り値によって得られたアドレスのさす領域は、m->maxLen の大きさだけ 5421| 保証されています。 5422|・過去に取得した返り値(アドレス)は、StrX_MemV_alloc の内部で 5423| realloc されたときに無効になります。 5424|************************************************************************/ 5425|#ifdef STRX_USES_MALLOC 5426|#ifdef USES_LISTX 5427|char* StrX_MemV_alloc( StrX_MemV* m ) 5428|{ 5429| StrX_Mem* mem = &m->mem_last->mem; 5430| 5431| /* 確保したメモリ領域が不足してきたとき、メモリ領域を追加確保する */ 5432| if ( (int)StrX_Mem_getLeftSize( mem ) <= m->maxLen ) { 5433| StrX_MemVE* ve = (StrX_MemVE*)malloc( sizeof(StrX_MemVE) ); 5434| void* memX = malloc( StrX_MemV_unitSize ); 5435| 5436| StdPlus_chkMalloc( mem, ve, StdPlus_End ); 5437| 5438| /* リスト要素を初期化する */ 5439| ListX_Elem_insertNext( m->mem_last, ve ); 5440| StrX_Mem_init( &ve->mem, memX, StrX_MemV_unitSize ); 5441| m->mem_last = ve; 5442| 5443| mem = &ve->mem; 5444| ASSERT( (int)StrX_Mem_getLeftSize( mem ) > m->maxLen ); 5445| } 5446| 5447| return StrX_Mem_alloc( mem ); 5448|} 5449|#endif 5450|#endif 5451| 5452| 5453| 5454|/*-------------------------------------------------------------------------*/ 5455|/* ◆16. <<<< (StrX_MemV2) 文字列の記憶領域(malloc & ハッシュ 使用)>>>> */ 5456|/*-------------------------------------------------------------------------*/ 5457| 5458| 5459| 5460|#if defined(USES_INF) && defined(USES_ARRX) && defined(USES_LISTX) && defined(USES_STDPLUS) 5461| 5462| 5463| 5464|/*********************************************************************** 5465| 16-1. <<< [StrX_MemV2_init] 初期化する >>> 5466|【引数】 5467| ・int width; 内部で使用するハッシュテーブルの幅 5468| ・StrX_HashFunc hash; ハッシュ関数(StrX_getHash, StrX_getHashI など) 5469| ・bool bCase; 大文字小文字を区別する 5470|【補足】 5471|・bCase によって hash を変える必要がある可能性があります。 5472|************************************************************************/ 5473|void StrX_MemV2_init( StrX_MemV2* m, int width, StrX_HashFunc hash, 5474| bool bCase ) 5475|{ 5476| ERRORS_INITCHK( m, 0 ); 5477| 5478| Offset_Key_init( &m->key, StrX_MemV2E, p, 5479| ( bCase ? Offset_CStringP : Offset_CStringPI ), 0 ); 5480| ListX_Dic_init( &m->dic, width, StrX_MemV2E, &m->key, hash ); 5481| ListX_init( &m->symbols ); 5482|} 5483| 5484| 5485| 5486|/*********************************************************************** 5487| 16-2. <<< [StrX_MemV2_setSymbol] アドレス指定文字列を設定する >>> 5488|【引数】 5489| ・char* setStr; アドレス指定文字列 5490|【補足】 5491|・setStr と同じ内容の文字列を StrX_MemV2_alloc() した場合に 5492| strStr のアドレスを返すようにします。 5493|・NULL 文字列や汎用文字列などに使用します。 5494|************************************************************************/ 5495|void StrX_MemV2_setSymbol( StrX_MemV2* m, const char* setStr ) 5496|{ 5497| ERRORS_INITCHK( m, 0 ); 5498| 5499| ListX_addFirstMalloc( &m->symbols, StrX_MemV2E )->p = (char*)setStr; 5500|} 5501| 5502| 5503| 5504|/*********************************************************************** 5505| 16-3. <<< [StrX_MemV2_alloc] 指定の文字列領域を確保する >>> 5506|【補足】 5507|・引数 str と同じ内容の文字列領域を確保または再利用し、その文字列の 5508| 先頭アドレスを返します。 5509|・str に NULL または Errors_null が指定されたら、それをそのまま返します。 5510|************************************************************************/ 5511|char* StrX_MemV2_alloc( StrX_MemV2* m, const char* str ) 5512|{ 5513| StrX_MemV2E* p; 5514| 5515| ERRORS_INITCHK( m, 1 ); 5516| 5517| if ( str == NULL || str == Errors_null ) return (char*)str; 5518| 5519| p = ListX_search_s( &m->symbols, &m->key, str, StrX_MemV2E ); 5520| 5521| if ( p == NULL ) { 5522| p = ListX_Dic_alloc( &m->dic, str, StrX_MemV2E ); 5523| if ( p != NULL ) StrX_MemV2E_init( p, (void*)str ); 5524| else p = ListX_Dic_search( &m->dic, str, StrX_MemV2E ); 5525| } 5526| 5527| return p->p; 5528|} 5529| 5530| 5531| 5532|/*********************************************************************** 5533| 16-4. <<< [StrX_MemV2_print] デバッグ表示する >>> 5534|************************************************************************/ 5535|#ifndef ERRORS_CUT_DEBUG_TOOL 5536|void StrX_MemV2_print( StrX_MemV2* m, const char* title ) 5537|{ 5538| ERRORS_INITCHK( m, 1 ); 5539| 5540| ListX_Dic_print( &m->dic, title ); 5541| Offset_Key_print( &m->key, title ); 5542|} 5543|#endif 5544| 5545| 5546| 5547|/*********************************************************************** 5548| 16-5. <<< [StrX_MemV2E_finish] 文字列領域をヒープへ開放する >>> 5549|************************************************************************/ 5550|void StrX_MemV2E_finish( StrX_MemV2E* m ) 5551|{ 5552| free( m->p ); 5553|} 5554| 5555| 5556| 5557|#endif 5558| 5559| 5560| 5561|/*-------------------------------------------------------------------------*/ 5562|/* ◆17. <<<< (StrX_SetV) 文字列の記憶領域の部分集合 >>>> */ 5563|/*-------------------------------------------------------------------------*/ 5564| 5565| 5566| 5567|/************************************************************************** 5568| 17-1. <<< [StrX_SetV_forEach_imp] StrX_SetV_forEach の実装 >>> 5569|**************************************************************************/ 5570|#ifdef STRX_USES_MALLOC 5571|#ifdef USES_LISTX 5572|char* StrX_SetV_forEach_imp( StrX_SetV* m, char* p ) 5573|{ 5574| if ( p < m->pVE->mem.pBuf ) return strchr( p, '\0' ) + 1; 5575| else { 5576| m->pVE = m->pVE->ListX_Elem_extend; 5577| if ( m->pVE == NULL ) return NULL; 5578| else return m->pVE->mem.buf + 1; 5579| } 5580|} 5581|#endif 5582|#endif 5583| 5584| 5585| 5586|/*-------------------------------------------------------------------------*/ 5587|/* ◆18. <<<< (StrX_Pathes) 右クリック『送る』のファイルパス >>>> */ 5588|/*-------------------------------------------------------------------------*/ 5589| 5590| 5591| 5592|#ifdef USES_BIGSTACK 5593|#if defined(USES_FILEX) && defined(USES_EXCEPT3) 5594|#if defined(FOR_WIN32) || defined(FOR_DOS32) 5595| 5596| 5597| 5598|/*********************************************************************** 5599| 18-1. <<< [StrX_Pathes_set] 内部用 >>> 5600|************************************************************************/ 5601|static void StrX_Pathes_set( StrX_Pathes* m ) 5602|{ 5603| if ( *m->curPath == '"' ) { 5604| StrX_wordCpy( m->longPath, _MAX_PATH - 1, m->curPath + 1, '"' ); 5605| } 5606| else { 5607| char s[_MAX_PATH]; 5608| 5609| StrX_wordCpy( s, _MAX_PATH - 1, m->curPath, ' ' ); 5610| StrX_toLongPath( m->longPath, s ); 5611| } 5612|} 5613| 5614| 5615| 5616|/*********************************************************************** 5617| 18-2. <<< [StrX_Pathes_init] 初期化する >>> 5618|【引数】 5619| ・char* cmdline; 短いファイルパス(空白区切り) 5620|【補足】 5621|・cmdline には、オプションをスキップしてファイルパスの始まる位置の 5622| アドレスを指定してください。例:AfxGetApp()->m_lpCmdLine = "-x a.txt" 5623| のときは、"a.txt" のアドレスを指定します。 5624|・長いファイル名を指定するときは、"" で囲んでください。 5625|・StrX_Pathes_next を呼び出す前に最初のファイルパスを StrX_Pathes_getCurPath 5626| で参照することが出来ます。 5627|************************************************************************/ 5628|void StrX_Pathes_init( StrX_Pathes* m, const char* cmdline ) 5629|{ 5630| m->pathes = (char*)cmdline; 5631| m->curPath = (char*)cmdline; 5632| StrX_Pathes_set( m ); 5633|} 5634| 5635| 5636| 5637|/*********************************************************************** 5638| 18-3. <<< [StrX_Pathes_reset] 最初のパスを参照するようにする >>> 5639|************************************************************************/ 5640|void StrX_Pathes_reset( StrX_Pathes* m ) 5641|{ 5642| m->curPath = m->pathes; 5643| StrX_Pathes_set( m ); 5644|} 5645| 5646| 5647| 5648|/*********************************************************************** 5649| 18-4. <<< [StrX_Pathes_getCurPath] 現在ポイントしているパスを参照する >>> 5650|************************************************************************/ 5651|char* StrX_Pathes_getCurPath( StrX_Pathes* m ) 5652|{ 5653| return m->longPath; 5654|} 5655| 5656| 5657| 5658|/*********************************************************************** 5659| 18-5. <<< [StrX_Pathes_next] 次のパスをポイントする >>> 5660|【引数】 5661| ・bool 返り値; 次があるかどうか(ある=true) 5662|************************************************************************/ 5663|bool StrX_Pathes_next( StrX_Pathes* m ) 5664|{ 5665| char* p; 5666| 5667| if ( *m->curPath == '"' ) { 5668| p = strchr( m->curPath + 1, '"' ); 5669| if ( p != NULL && *(p + 1) != '\0' && *(p + 2) != '\0' ) { 5670| m->curPath = p + 2; 5671| StrX_Pathes_set( m ); 5672| return true; 5673| } 5674| return false; 5675| } 5676| else { 5677| p = strchr( m->curPath, ' ' ); 5678| if ( p != NULL ) { 5679| m->curPath = p + 1; 5680| StrX_Pathes_set( m ); 5681| return true; 5682| } 5683| else 5684| return false; 5685| } 5686|} 5687| 5688| 5689| 5690|/*********************************************************************** 5691| 18-6. <<< [StrX_Pathes_getN] 要素数を返す >>> 5692|************************************************************************/ 5693|int StrX_Pathes_getN( StrX_Pathes* m ) 5694|{ 5695| int nPath; 5696| char* curPath_back = m->curPath; 5697| 5698| m->curPath = m->pathes; 5699| 5700| nPath = 1; 5701| while ( StrX_Pathes_next( m ) ) { 5702| nPath ++; 5703| } 5704| 5705| m->curPath = curPath_back; 5706| StrX_Pathes_set( m ); 5707| 5708| return nPath; 5709|} 5710| 5711| 5712| 5713|#endif 5714|#endif 5715|#endif 5716| 5717|