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