/*	
 *	clipstr.h
 *
 *	ユーティリティ：文字列操作
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2014 Naoyuki Sawa
 *
 *	* Sat Oct 11 12:29:17 JST 2014 Naoyuki Sawa
 *	- 作成開始。
 *	- strtrim(),strescape(),strcompress()を、clipmisc.h,cからclipstr.h,cへ移動しました。
 *	- strfreev(),strv_length(),strdup_printf(),strdup_vprintf(),strjoin(),strjoinv(),strsplit(),strsplit_set()を追加しました。
 *	* Mon Oct 13 02:54:55 JST 2014 Naoyuki Sawa
 *	- str_has_prefix(),str_has_suffix()を追加しました。
 *	* Sat Oct 18 18:55:59 JST 2014 Naoyuki Sawa
 *	- string_match()を追加しました。
 */
#ifndef __CLIP_STR_H__
#define __CLIP_STR_H__

/*****************************************************************************
 *	トリム
 *****************************************************************************/

/* 指定した文字だけを取り除く。
 * [in]
 *	s		元の文字列
 *	mode		除去する位置の指定	0 両端にある指定文字を除去する
 *						1 左端にある指定文字を除去する
 *						2 右端にある指定文字を除去する
 *						3 文字列内にある全ての指定文字を除去する
 *	reject		除去する文字		NULLを指定した場合は、空白文字を除去する
 * [out]
 *	戻り値		結果の文字列		呼び出し側にて、free()で開放してください
 * [note]
 *	- HSPのstrtrim関数の仕様に倣いました。
 * [使用例]
 *	const char src[] = "   - - - Sample  String - - -   ";
 *	char* dst;
 *	dst = strtrim(src, 0, NULL); puts(dst); free(dst); //   "- - - Sample  String - - -"
 *	dst = strtrim(src, 1, NULL); puts(dst); free(dst); //   "- - - Sample  String - - -   "
 *	dst = strtrim(src, 2, NULL); puts(dst); free(dst); //"   - - - Sample  String - - -"
 *	dst = strtrim(src, 3, NULL); puts(dst); free(dst); //       "---SampleString---"
 *	dst = strtrim(src, 0, " -"); puts(dst); free(dst); //         "Sample  String"
 *	dst = strtrim(src, 1, " -"); puts(dst); free(dst); //         "Sample  String - - -   "
 *	dst = strtrim(src, 2, " -"); puts(dst); free(dst); //"   - - - Sample  String"
 *	dst = strtrim(src, 3, " -"); puts(dst); free(dst); //          "SampleString"
 */
char* strtrim(const char* s, int mode, const char* reject);

/*****************************************************************************
 *	エスケープ
 *****************************************************************************/

/* 文字列のバイナリデータを、印字可能な文字列にエスケープします。
 * [in]
 *	s		文字列のバイナリデータ
 *	need_escape	アプリケーション定義のエスケープが必要な文字	(NULL=無し)
 *			
 * [out]
 *	戻り値		エスケープされた文字列	呼び出し側にて、free()で開放してください。
 * [note]
 *	- 当関数の名前は、GLibのg_strescapeから取りました。
 *	  関数仕様はg_strescapeと完全互換ではありません。(need_escapeが独自拡張です。)
 *	- 当関数は、以下の処理を行います。
 *	  1. C言語のエスケープシーケンスに相当する文字を、エスケープシーケンスに変換する。
 *	  2. アプリケーション定義のエスケープが必要な文字の前に、'\'を追加する。
 *	  3. 印字可能でない文字を、'\'+8進表記3桁に変換する。
 *	  4. それ以外の文字は、そのまま出力する。
 * [使用例]
 *	- C言語の文字列エスケープ処理
 *	  dst=strescape(src,NULL);
 *	- Tcl言語の文字列エスケープ処理(TclのソースのTcl_ConvertElement()に相当)
 *	  dst=strescape(src," $;[]{}");
 *	- Tcl言語のリスト作成処理(TclのソースのTcl_Merge()に相当)
 *	  *dst='\0';
 *	  for(i=0;i<argc;i++){
 *	    char*tmp=strescape(argv[i]," $;[]{}");
 *	    if(i){strcat(dst," ");}
 *	    strcat(dst,(*tmp)?tmp:"{}");//空要素は{}に置き換えて明示的に格納する
 *	    free(tmp);
 *	  }
 */
char* strescape(const char* s, const char* need_escape);

/* エスケープされた文字列を、文字列のバイナリデータに復元します。
 * [in]
 *	s		エスケープされた文字列
 *	delim		文字列sの処理を終了する文字セットを指定します。	NULLが指定された場合は文字列sの終端まで処理を行います。
 *									endptrと組み合わせて使用することを想定していますが、endptrを指定せずdelim のみ指定することも可能です。
 *	endptr		文字列sの処理を終了した位置を格納します。	NULLが指定された場合は格納しません。
 *									delim と組み合わせて使用することを想定していますが、delim を指定せずendptrのみ指定することも可能です。
 * [out]
 *	戻り値		文字列のバイナリデータ
 * [note]
 *	- 当関数の名前は、GLibのg_strcompressから取りました。
 *	  関数仕様はg_strcompressと完全互換ではありません。(endptr,delimが独自拡張です。)
 *	- 当関数は、以下の処理を行います。
 *	  1. 文字列sから一文字取得し、文字cとする。文字cによって以下2.〜4.のいずれかの処理を行う。
 *	  2. 文字cが'\0',又は,delim(指定されていれば)の文字セットに一致した場合:
 *	    2-1. endptr(指定されていれば)に文字cの位置を格納する。
 *	    2-2. 出力文字列を'\0'で終端する。
 *	    2-3. 処理を終了する。
 *	  3. 文字cが'\'である場合、文字cの次の文字を取得し、以下3-1.〜3-5.のいずれかの処理を行う。
 *	    3-1. '\'にnulが続く場合、'\'を破棄して処理2.を行い終了する。('\'にnulが続くのは'エスケープされた文字列'として不正だが、文字列の終端を超えないように最低限の対策を行うことにした)
 *	    3-2. '\'に続くC言語のエスケープシーケンス文字を、1文字に変換して出力する。
 *	    3-3. '\'に続く8進表記(1〜3桁)を、1文字に変換して出力する。
 *	    3-4. '\'に続く16進表記(1〜∞桁)を、1文字に変換して出力する。
 *	    3-5. '\'に続く改行を、'\'ごと削除する。(Cプリプロセッサ,Python,Tcl,sed,awk,bash,…の行の継続に相当)
 *	    3-6. '\'に続くそれ以外の文字を、'\'を削除して文字のみに変換して出力する。('アプリケーション定義のエスケープが必要な文字'も含む)
 *	  4. 文字cが2.〜3.以外である場合、以下4-1.の処理を行う。
 *	    4-1. 文字cをそのまま出力する。
 *	- endptr,delimは、「エスケープされていない特定の文字を分割文字と見なすリストから、一要素を復元して取得する」ために使用します。
 *	  たとえば、Tclのリストから一要素を復元して取得する場合に使用します。
 *	  Cソース文字列の単純な復元の場合は考慮する必要はありませんので、endptr,delimにNULLを指定してください。
 * [使用例]
 *	- C言語の文字列エスケープ復元処理
 *	  dst=strcompress(src,NULL,NULL);
 *	- Tcl言語のリスト分割処理。(厳密にはTclでは{}でのエスケープも考慮する必要があるが、説明を簡単にするため以下の例では省略する。)
 *	  for(;;){
 *	    src+=strspn(src,"\t\n\v\f\r ");                  //先行するデリミタを飛ばす。
 *	    if(!*src){break;}                                //リスト終端ならば終了する。
 *	    argv[argc++]=strcompress(src,&src,"\t\n\v\f\r ");//一要素を復元して取得する。
 *	  }
 */
char* strcompress(const char* s, char** endptr, const char* delim);

/*****************************************************************************
 *	文字列ポインタ配列
 *****************************************************************************/

/* 文字列ポインタ配列の、メモリを開放する。
 * [in]
 *	str_array		文字列ポインタ配列。	配列はNULLポインタ要素で終端されていること。(main()関数のargv[]と同様です。)
 *							str_array自体にNULLポインタを指定した場合は、当関数は何もせずに処理を返す。
 * [note]
 *	- GLibのg_strfreev()に互換です。
 */
void strfreev(char** str_array);

/* 文字列ポインタ配列の、要素数を取得する。
 * [in]
 *	str_array		文字列ポインタ配列。	配列はNULLポインタ要素で終端されていること。(main()関数のargv[]と同様です。)
 * [out]
 *	戻り値			要素数。		終端のNULLポインタ要素は、要素数に含めない。
 * [note]
 *	- GLibのg_strv_length()に互換です。
 */
size_t strv_length(char** str_array);

/****************************************************************************
 *	書式化文字列
 ****************************************************************************/

/* asprintf()と同様だが、文字列を戻り値とする点が異なる。
 * [in]
 *	fmt			書式文字列。
 *	...			可変引数。
 * [out]
 *	戻り値			文字列。		呼び出し側にて、使用終了後に、free()で開放すること。
 * [note]
 *	- GLibのg_strdup_printf()に互換です。
 */
char* strdup_printf(const char* fmt, ...);

/* vasprintf()と同様だが、文字列を戻り値とする点が異なる。
 * [in]
 *	fmt			書式文字列。
 *	ap			可変引数。
 * [out]
 *	戻り値			文字列。		呼び出し側にて、使用終了後に、free()で開放すること。
 * [note]
 *	- GLibのg_strdup_vprintf() に互換です。
 */
char* strdup_vprintf(const char* fmt, va_list ap);

/*****************************************************************************
 *	連結
 *****************************************************************************/

/* 複数の文字列を、一つの文字列に連結する。
 * [in]
 *	separator		セパレータ。		NULLポインタを指定すると、""を指定したのと同じと見なす。
 *	...			複数の文字列。		NULLポインタで終端すること。
 * [out]
 *	戻り値			文字列。		呼び出し側にて、使用終了後に、free()で開放すること。
 * [note]
 *	- GLibのg_strjoin()に互換です。
 */
char* strjoin(const char* separator, ...);

/* 文字列ポインタ配列を、一つの文字列に連結する。
 * [in]
 *	separator		セパレータ。		NULLポインタを指定すると、""を指定したのと同じと見なす。
 *	str_array		文字列ポインタ配列	配列はNULLポインタ要素で終端されていること。(main()関数のargv[]と同様です。)
 * [out]
 *	戻り値			文字列。		呼び出し側にて、使用終了後に、free()で開放すること。
 * [note]
 *	- GLibのg_strjoinv()に互換です。
 */
char* strjoinv(const char* separator, char** str_array);

/****************************************************************************
 *	分割
 ****************************************************************************/

/* 文字列を、デリミタ文字列を用いて分割する。
 * [in]
 *	s			分割する文字列。
 *	delimiter		デリミタ文字列。	""は指定不可。
 *	max_tokens		最大分割数。		1未満の値を指定すると、無限と見なす。
 * [out]
 *	戻り値			文字列ポインタ配列。	呼び出し側にて、使用終了後に、strfreev()で開放すること。
 * [note]
 *	- GLibのg_strsplit()に互換です。
 */
char** strsplit(const char* s, const char* delimiter, int max_tokens);

/* 文字列を、デリミタ文字セットを用いて分割する。
 * [in]
 *	s			分割する文字列。
 *	delimiters		デリミタ文字セット。	""も指定可能。
 *	max_tokens		最大分割数。		1未満の値を指定すると、無限と見なす。
 * [out]
 *	戻り値			文字列ポインタ配列。	呼び出し側にて、使用終了後に、strfreev()で開放すること。
 * [note]
 *	- GLibのg_strsplit_set()に互換です。
 */
char** strsplit_set(const char* s, const char* delimiters, int max_tokens);

/*****************************************************************************
 *	比較
 *****************************************************************************/

/* 文字列s1のプレフィクス部分が、s2に一致するか調べる。
 * [in]
 *	s1			文字列。
 *	s2			プレフィクス。		""も指定可能。
 * [out]
 *	戻り値			一致しなければ0を返す。
 *				一致したら0以外を返す。
 * [note]
 *	- GLibのg_str_has_prefix()に互換です。
 */
int str_has_prefix(const char* s1, const char* s2);

/* 文字列s1のサフィックス部分が、s2に一致するか調べる。
 * [in]
 *	s1			文字列。
 *	s2			サフィックス。		""も指定可能。
 * [out]
 *	戻り値			一致しなければ0を返す。
 *				一致したら0以外を返す。
 * [note]
 *	- GLibのg_str_has_suffix()に互換です。
 */
int str_has_suffix(const char* s1, const char* s2);

/* Tcl6.7の「string match」に準拠した、文字列パターン比較を行います。
 * [in,out]
 *	│patがstrにマッチするかどうかを確かめます。マッチするならば1を、しないならば0を返します。
 *	│2つの文字列の照合では、patに次の使える特別なシーケンスを除いて、マッチ内容は同一でなければなりません。
 *	│*       空文字列を含むstr内のあらゆる文字シーケンスにマッチします。
 *	│?       str内のあらゆる単独の文字にマッチします。
 *	│[chars] charに与えられたセット内のどれかの文字にマッチします。
 *	│        x-y形式のシーケンスがchars内に現れると、xとyも含まれるxとyの間のいずれかの文字にマッチします。
 *	│        [A-z]は'_'にマッチします。('_'は'Z'と'a'の間にあるので)
 *	│\x      単一の文字xにマッチします。これはpat内の文字*?[]\の特別な解釈を防止する方法を提供します。
 * [note]
 *	- Tcl6.7の「string match」と、一般的な正規表現の相違点として、以下に注意してください:
 *	  一般的な正規表現では、'['の直後の']'は文字クラスを閉じず、文字クラスの一文字と見なされるが、Tcl6.7のstring matchにはこの特例処理が無い。
 *	  一般的な正規表現では、文字クラスの中でも'\'による特殊文字のエスケープやエスケープシーケンスが使えるが、Tcl6.7のstring matchでは使えない。
 *	  行頭を示す'^',行末を示す'$',文字クラス中の'^',グループ化する'(',')',選択する'|'などは有りません。正規表現というよりもVBAのLikeに近いです。
 */
int string_match(const char* pat, const char* str);

#endif/*__CLIP_STR_H__*/
