/* vi: set tabstop=4 nocindent paste: */

#ifndef  __JBXL_TOOLS_HEADER_
#define  __JBXL_TOOLS_HEADER_


/**
汎用ツールヘッダ  tools.h

  依存関係
	  #include "common.h"

 */



#include "common.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <ctype.h>


#ifdef WIN32
	#include <winsock2.h>		// for ntohl, ntohs, htonl, htons
	#ifndef HAVE_TIME_H
		#define  HAVE_TIME_H
	#endif
#else
	#include <unistd.h>	
#endif


#ifdef HAVE_ARPA_INET_H
	#include <arpa/inet.h>
#endif

#ifdef TIME_WITH_SYS_TIME
	#include <time.h>
	#include <sys/time.h>
#else
	#ifdef HAVE_TIME_H 
		#include <time.h>
	#endif 
	#ifdef HAVE_SYS_TIME_H 
		#include <sys/time.h>
	#endif 
#endif

#ifdef HAVE_SYS_PARAM_H 
	#include <sys/param.h>
#endif

#ifdef HAVE_SYSLOG_H
	#include <syslog.h>
#endif

#ifdef HAVE_WAIT_H 
	#include <wait.h>
#endif
#ifdef HAVE_SYS_WAIT_H 
	#include <sys/wait.h>
#endif

#ifdef HAVE_SYS_ERRNO_H 
	#include <sys/errno.h>
#else
	#include <errno.h>
#endif
#include <signal.h>



/**
マクロ

  CR   改行				^M  0x0d
  LF   ラインフィード  	^J  0x0a
  TAB  タブ				^I  0x09			
 */
#define  CR	 	0x0d		// 改行 
#define  LF	 	0x0a		// ラインフィード 
#define  TAB	0x09		// タブ 

#define  US	 	0
#define  EUC	1			//  
#define  SJIS   2			//  
#define  UTF8   3			//  


#define UNKNOWN_ENDIAN 0
#ifndef LITTLE_ENDIAN
	#define  LITTLE_ENDIAN  1234
	#define  BIG_ENDIAN 	4321
	#define  PDP_ENDIAN 	3412
#endif



/**
バイト型 リングバッファ

*/
typedef  struct _ringbuffer {
	unsigned char* buf;
	int   bufsz;			// バッファ部のサイズ
	int   spoint;			// バッファデータの開始点
	int   epoint;			// バッファデータの終点+1 (データの追加点)
	int   npoint;			// 次のメッセージのスタートポイント
	int   datasz;			// 保存されているデータの全体の長さ
	int   datano;			// 格納されているデータの数
	int   state;			// リングバッファの状態
} ringbuffer;


#define  mstream   ringbuffer	// バイト型 メッセージストリーム




/**
大域変数

  int DebugMode;  ON の場合 デバックモードであることを示す．デフォルトはOFF．
  int KanjiCode;  処理用漢字コード．US, SJIS, EDUがある．デフォルトは US．

 */
extern int   DebugMode; 
extern int   KanjiCode;
extern int   UnitTestMode;

extern char  LocalIPNum[4];

extern int	 HostEndian;


#define  LOCAL_IPADDR  "127.0.0.1"



// not C++
#ifndef CPLUSPLUS
	int  isNull(void* p);
	#define freeNull(p)     {if(!isNull(p)) free(p); (p)=NULL;}
#endif




/**/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// 文字（列）操作
char*   get_line(char* str, int n);					// strのバッファ内の n行目を取り出す．改行コードは削除される．要free
char*   awk (char* str, char cc, int n);			// ccを区切り記号として, strのバッファ内の n番目の項目を返す．要free
char*   cawk(char* str, char cc, int n);			// 連続するccを区切り記号として, strのバッファ内の n番目の項目を返す．要free

char*   cut_str(char* buf, int ls, int le);			// buf[ls]〜buf[le] を切り出す．要 free
char*   dup_str(char* buf);							// 文字列を複製する．要 free
char*	skip_char(char* mesg, const char* check);	// check[]中の何れかの文字までポインタをスキップさせる．ただし " ' 内は完全スキップ
char*  	pack_char(char* mesg, char cc);				// 文字列中及び，先頭のcc(複数)，終わりのcc(複数)，CR, LF を削除．要 free
char*  	pack_head_tail_char(char* mesg, char cc);	// 文字の先頭のcc(複数)，TAB, CR, LF．終わりのcc(複数)，TAB, CR, LF を削除．要 free
char*  	change_esc(char* mesg);						// 文字列中の CR, LF を \r, \n に変換する．要 free
char*   chomp(char* str);							// 最初の改行コード以降を無効にする．
char*   double_bs(char* fn);						// 文字列中の \ を \\に置き換えた文字列を返す．要 free
char*   numbering_name(char* fmt, int n);			// フォーマット fmtに従って，nを含む文字列を作り出す．要 free

char*	ltostr(long int n);							// long int を文字に変換する．free は不要	
char*	ultostr(unsigned long int n);				// unsigned long int を文字に変換する．free は不要	
char*	ftostr(float n);							// float を文字に変換する．free は不要	

int 	hexstr2i(const char* str);					// 16進の文字列を整数に変換する．

void	swap_byte(void* p, int s, int b);			// sの長さのpのバイト順序をbバイト毎に逆順にする．
short   swaps(short p);								// 16bit の上下8bitを入れ替える．
int	 	swapl(int   p);								// 32bit pを8bitづつ逆順にする
void	reverse_str(uByte* p, int s);				// バイト(octet)列を逆順にする．
void	upper_string(char* str);
//void	int_swap(int* p, int* s);					// データを入れ替える．
#define int_swap(p, s) 	{int swap=(p); (p)=(s); (s)=swap;}



// 比較
int  	bincmp(unsigned char* b1, unsigned char* b2, int n);		// バイナリデータを n Byte比べる
int	 	strnrvscmp(const char* s1, const char* s2, int n);			// 文字列 s1と s2を後ろから n文字比較する．
int	 	strncaservscmp(const char* s1, const char* s2, int n);		// 文字列 s1と s2を後ろから n文字比較する．
char*   strstrcase(const char* buf, const char* nd);				// 文字列 bufの中に文字列 ndがあるかどうかをチェックする．大文字小文字は区別しない．

int	 	ex_strncmp(const char* s1, const char* s2, int n);			// 文字列 s1とs2を拡張比較する．
int	 	ex_strncasecmp(const char* s1, const char* s2, int n);	  	// 文字列 s1とs2を拡張比較する．
int	 	ex_strnrvscmp(const char* s1, const char* s2, int n);		// 文字列 s1とs2を後ろから拡張比較する．
int	 	ex_strncaservscmp(const char* s1, const char* s2, int n);	// 文字列 s1とs2を後ろから拡張比較する．


// エンディアン  (マクロ isBigEndianは ntohs() を使用したもの）
int 	is_little_endian(void);
int 	is_big_endian(void);
void 	check_endian(void);

double 	double_from_little_endian(void* ptr);
float 	float_from_little_endian(void* ptr);
int  	int_from_little_endian(void* ptr);
short 	short_from_little_endian(void* ptr);
double 	double_from_big_endian(void* ptr);
float 	float_from_big_endian(void* ptr);
int  	int_from_big_endian(void* ptr);
short 	short_from_big_endian(void* ptr);


// 時間
char*   get_local_time(void);


// 入出力
void	print_escape(char* format, char* mesg);			// エスケープ文字を含むメッセージの出力（stderr）
void	fdump(FILE* fp, unsigned char* mesg, int n);	// 16進ダンプを吐き出す
void	print_16x(FILE* fp, unsigned char* mesg, int n);// 16進ダンプを吐き出す（１行）


// 漢字コード
void	kanji_convert(unsigned char* mesg);				// 大域変数 KnjiCodeに従って漢字コードを変換する．
void	kanji_convert_euc2sjis(unsigned char* mesg);	// EUCをSJISに変換する．
void	kanji_convert_sjis2euc(unsigned char* mesg);	// SJISをEUCに変換する．
void	euc2sjis(unsigned char *c1, unsigned char *c2);	// EUC  -> SJIS
void	sjis2euc(unsigned char *c1, unsigned char *c2);	// SJIS -> EUC


// ファイル
int		file_from_to(char* s, char* d, char* mode);		// modeに従って,ファイル sを dにコピーする．
int		fp_from_to(FILE* s, FILE* d, long int sz);		// ファイル sを dにコピーする．
char*   get_file_name(char* str);						// フルパスからファイル名へのポインタを取り出す．
unsigned long file_size(char* fn);						// ファイルの大きさを返す．
int	 	file_exist(char* fn);							// ファイルの存在を検査する．
FILE* 	file_chmod_open(char* fn, char* fm, mode_t mode);
char*   temp_filename(const char*, int);

unsigned char* 	read_file (char* fname, unsigned long int* size);
long int  		write_file(char* fname, unsigned char* buf, unsigned long int size);



// 乱数
void	init_rand(void);								// /dev/urandom からデータで乱数の系列を初期化する
char*   randstr(int n);									// ランダムに A-Za-z0-9 までの文字を n文字生成する．
unsigned char* randbit(int n);							// ランダムに n bitのバイナリを生成する．
#define random_str(n)   temp_filename(NULL, (n))


// Base64
unsigned char*  encode_base64(unsigned char* str, int  sz);
unsigned char*  decode_base64(unsigned char* str, int* sz);
unsigned char*  encode_urlenc(unsigned char* str, int  sz);
unsigned char*  decode_urlenc(unsigned char* str, int* sz);
unsigned char*  encode_quoted_printable(unsigned char* str, int  sz);
unsigned char*  decode_quoted_printable(unsigned char* str, int* sz);
unsigned char*  encode_hex(unsigned char cc);
unsigned char	decode_hex(unsigned char c1, unsigned char c2);


// バイト型リングバッファー
ringbuffer* 	new_ringbuffer(void);
ringbuffer  	init_ringbuffer(void);
ringbuffer  	make_ringbuffer(int sz);
void  			del_ringbuffer  (ringbuffer** pp);
void  			free_ringbuffer (ringbuffer* pp);
void  			clear_ringbuffer(ringbuffer* pp);
int   			put_ringbuffer(ringbuffer* rb, unsigned char* pp, int sz);
unsigned char* 	get_ringbuffer(ringbuffer* rb, int sz);

#define  char_ringbuffer(b, n)		(b).buf[((n)%((b).bufsz))]


// メッセージストリーム
int   			put_mstream(mstream* sb, unsigned char* pp);
unsigned char* 	get_mstream(mstream* sb);
unsigned char* 	fgets_mstream(unsigned char* mesg, mstream* sb);

#define  init_mstream()		init_ringbuffer()
#define  new_mstream()		new_ringbuffer()
#define  make_mstream(s)  	make_ringbuffer((s))
#define  free_mstream(s)  	free_ringbuffer((s))
#define  del_mstream(s)   	del_ringbuffer((s))
#define  clear_mstream(s) 	clear_ringbuffer((s))


// UUID
unsigned char*  uuid2guid(unsigned char* p);
unsigned char*  guid2uuid(unsigned char* p);


#ifndef WIN32
// プロセス
void  	set_sigterm_child(void (*handler)(int));
void  	sigterm_child(int signal);

void  	ignore_sigterm_child(void);

void	set_sigsegv_handler(void (*handler)(int));
void	trap_segmentation_falt(int signal);

#define  set_sigseg_handler(h)    set_sigsegv_handler((h))

#endif


///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// for Windows

#ifdef WIN32

//void  bzero(char* p, unsigned int n);
//void  bcopy(char* f, char* t, unsigned int n);

#endif   // WIN32



/**/

////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// マクロ関数
//

/**
	copy_file(src, dst)	 srcから dsへファイルをコピーする．
	cat_file (src, dst)	 srcから dstへファイルを catする．
*/
#define copy_file(src, dst)  file_from_to((src), (dst), "wb");
#define cat_file(src, dst)   file_from_to((src), (dst), "ab");



//#define  isBigEndian	((sWord)1==htons((sWord)1))
//#define  isLittleEndian ((sWord)1!=htons((sWord)1))

#define  isBigEndian	(is_big_endian())
#define  isLittleEndian (is_little_endian())


/**
  ntoh_st(p, s)   network形式から host形式へ．構造体pに対して sバイトづつ変換．
  hton_st(p, s)   host形式から network形式へ．構造体pに対して sバイトづつ変換．
  ntoh_ar(p, s)   network形式から host形式へ．長さsバイトの配列pに対して変換．
  hton_ar(p, s)   host形式から network形式へ．長さsバイトの配列pに対して変換．
  ntoh_data(p, s, c) network形式から host形式へ. 長さsバイトのデータp に対して cバイトづつ変換する．
  hton_data(p, s, c) host形式から network形式へ. 長さsバイトのデータp に対して cバイトづつ変換する．
 */
#define  ntoh_st(p, s) {if (!isBigEndian) swap_byte((void*)(p), sizeof(*(p)), (s));}
#define  hton_st(p, s) {if (!isBigEndian) swap_byte((void*)(p), sizeof(*(p)), (s));}
#define  ntoh_ar(p, s) {if (!isBigEndian) swap_byte((void*)(p), (s), sizeof(*(p)));}
#define  hton_ar(p, s) {if (!isBigEndian) swap_byte((void*)(p), (s), sizeof(*(p)));}

#define  ntoh_data(p, s, c) {if (!isBigEndian) swap_byte((void*)(p), (s), (c));}
#define  hton_data(p, s, c) {if (!isBigEndian) swap_byte((void*)(p), (s), (c));}



/////////////////////////////////////////////////////////////////////////////////////
// for Debug

/**
エラーメッセージ関数
	DEBUG_MESG, DEBUG_ESCP:
    	-DEBUG オプションつきでコンパイルされた時に出力される．
		静的に制御する場合に使用．つまり作成時のデバッグで使用する場合に使用し，製品版では削除可能．
*/

void	print_message(char*, ...);					// バッファリングなしのメッセージ出力（stderr）
void	fprint_message(FILE*, char*, ...);			// バッファリングなしのメッセージ出力

#define   print_mesg  print_message
#define  fprint_mesg fprint_message


#ifdef _DEBUG
	#ifndef EBUG
		#define EBUG
	#endif
#endif


#ifdef EBUG
	#define DEBUG_MESG  print_message
	#define DEBUG_ESCP  print_escape
	#ifndef _DEBUG
		#define _DEBUG
	#endif
#else
	#define DEBUG_MESG(f, ...)  {}
	#define DEBUG_ESCP(f, ...)  {}
#endif


#define  DEBUG_MODE  if(DebugMode==ON)


#endif

