/*	
 *	clipstr.h
 *
 *	ユーティリティ：文字列操作
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2015 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()を追加しました。
 *	* Thu Nov 06 00:58:25 JST 2014 Naoyuki Sawa
 *	- strreverse()を追加しました。
 *	* Sat Nov 08 16:50:24 JST 2014 Naoyuki Sawa
 *	- strdupv()を追加しました。
 *	* Tue Nov 11 23:26:40 JST 2014 Naoyuki Sawa
 *	- strconcat()を追加しました。
 *	* Sat Nov 15 20:39:46 JST 2014 Naoyuki Sawa
 *	- str_has_prefix_suffixのバグを修正しました。
 *	  str_has_prefix_suffixの中で%r3を使用しているのに、%r0〜%r2しか退避していないバグでした。
 *	  そのために、str_has_prefix_suffixを呼び出すモジュールが、不正な動作を起こしていました。
 *	  具体的には、cliptcl.cのTcl_GetIndex()が、アドレスエラーで不正終了してしまっていました。
 *	* Sat Mar 07 16:39:40 JST 2015 Naoyuki Sawa
 *	- strstrip(),strchug(),strchomp()を追加しました。
 *	* Sat Mar 07 23:27:25 JST 2015 Naoyuki Sawa
 *	- textwrap()を追加しました。
 *	* Sun Mar 08 10:55:52 JST 2015 Naoyuki Sawa
 *	- strsplit_set()とビットマップGCを併用し、ある程度大きなファイルを分割しようとすると、ビットマップGCがエラー停止する事が有ります。
 *	  この問題について調査した結果を、clipstr.cのstrsplit_set()関数の上に追記しました。
 */
#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);

/* 両端(目的だけならば),又は,左側(strchug),又は,右側(strchomp)の空白文字を除去する。
 * [in]
 *	s		元の文字列
 * [out]
 *	戻り値		引数sをそのまま返す。
 * [note]
 *	- これらの関数は、新しい文字列を作成せずに、元の文字列を直接変更する。
 *	- GLibのg_strstrip(),g_strchug(),g_strchomp()に互換です。
 *	  これらの関数を追加した理由は、GLib互換の関数を用意しておこうと思ったからだけです。
 *	  'トリム'を行う目的だけならば、上のstrtrim()関数の方が高機能です。
 *	  実際のところこれらの関数は内部で、strtrim()関数を呼び出して実装しました。
 */
char* strstrip(char* s);
char* strchug( char* s);
char* strchomp(char* s);

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

/* 文字列のバイナリデータを、印字可能な文字列にエスケープします。
 * [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);

/* 文字列ポインタ配列の、'深い'複製を作成する。
 * [in]
 *	str_array		複製する、文字列ポインタ配列。	配列はNULLポインタ要素で終端されていること。(main()関数のargv[]と同様です。)
 * [out]
 *	戻り値			複製した、文字列ポインタ配列。	呼び出し側にて、strfreev()を使って開放せよ。
 * [note]
 *	- GLibのg_strdupv()に互換です。ただし、以下の一点において、非互換です。
 *	- GLibのg_strdupv()は、引数str_arrayにNULLポインタを指定することができ、g_strdupv()は何もせずにNULLポインタを返します。
 *	  それに対し当実装は、引数str_arrayにNULLポインタを指定することができません。もし指定した場合は、不正な動作となります。
 *	  GLibのg_strdupv()は、独自のg_strdup()が引数にNULLポインタ指定可であることに倣って、g_strdupv()も引数にNULLポインタ指定可としているのだと思いますが、
 *	  g_strdup()やg_strdupv()の引数にNULLポインタ指定可であることは、かえってバグを見つけ辛くなる問題があるように思います。
 *	  従って当実装では、標準的なstrdup()と同様に、引数にNULLポインタ指定不可とすることにしました。
 */
char** strdupv(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]
 *	s, ...			複数の文字列。		NULLポインタで終端すること。
 * [out]
 *	戻り値			文字列。		呼び出し側にて、使用終了後に、free()で開放すること。
 * [note]
 *	- GLibのg_strconcat()に互換です。
 *	- g_strconcat()の仕様では、最初の文字列sは「the first string to add, which must not be NULL」となっているが、
 *	  当関数は、最初の文字列sがNULLも可とし、その場合、当関数は空文字列("")を返すようにした。
 *	  その方が、strjoin()やstrjoinv()と対象性が有り、便利であるし、判り易いと思ったからです。
 */
char* strconcat(const char* s, ...);

/* 複数の文字列を、一つの文字列に連結する。
 * [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);

/* 文字列を一行の長さに折り返して分割します。
 * [in]
 *	s			折り返す文字列。
 *	w			一行の幅。半角文字は1,全角文字は2と数えます。
 * [out]
 *	戻り値			文字列ポインタ配列。	呼び出し側にて、使用終了後に、strfreev()で開放すること。
 * [note]
 *	- Pythonのtextwrap.wrap()の関数仕様を参考にしました。
 *	- 原則的には、分割された個々の文字列の幅はw以下となります。
 *	  ただし、1文字がw以上の文字が存在した場合、w以上の長さとなる場合も有ります。具体的には、
 *	  wに1未満を指定しても、分割された個々の文字列は幅1以上(半角1文字,又は,全角1文字)に成り得ます。
 *	  wに2未満を指定しても、分割された個々の文字列は幅2以上(全角1文字)に成り得ます。
 *	  この仕様は、Pythonのtextwrap.wrap()と同じです。
 *	- 上記の挙動を応用して、wに1以下を指定すれば、文字列を1文字単位に分割する用途にも利用できます。
 *	- 当関数は、禁則処理は行いません。
 *	- □使用例:
 *	  │char** argv=textwrap("12345六78",3);
 *	  │⇒argv[0]="123",argv[1]="45",argv[2]="六7",argv[3]="8"
 *	  │char** argv=textwrap("1二3",0);
 *	  │⇒argv[0]="1",argv[1]="二",argv[2]="3"
 */
char** textwrap(const char* s, int w);

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

/* 文字列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);

/*****************************************************************************
 *	反転
 *****************************************************************************/

/* 文字列を反転する。
 * [in]
 *	s		反転する文字列。
 * [out]
 *	戻り値		引数sをそのまま返す。
 * [note]
 *	- GLibのg_strreverse()に互換です。
 */
char* strreverse(char* s);

#endif/*__CLIP_STR_H__*/
