strx.c

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 または NULLNULL = 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内)または NULLNULL = 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 タグ文字である '<', '>', '&' を "&lt;", "&gt;", "&amp;" に変換します。
2724|・src と dst は別の領域にしてください。
2725|・dst の領域を越える場合、残りは切り捨てます。
2726|  その際でも、"&lt;", "&gt;", "&amp;" の一部が残らないようになります。
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|・"&lt;", "&gt;", "&amp;" を '<', '>', '&' に戻します。
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|