/* vim: set tabstop=4 paste nocindent noautoindent ff=unix: */ /** @brief 汎用ツールプログラム @file tools.c @author Fumi.Iseki (C) @date 2005 10/10 */ #include "tools.h" int DebugMode = OFF; int UnitTestMode = OFF; int KanjiCode = CODE_EUC; ///< システムの漢字コード int HostEndian = UNKNOWN_ENDIAN; ///< システムの Endian char LocalIPNum[4] = {0x7f, 0x00, 0x00, 0x01}; ///< 127.0.0.1 のバイナリ /////////////////////////////////////////////////////////////////////////////////////////// // // case of C++, isNull() is inline #ifndef CPLUSPLUS /** int isNull(void* p) ポインタが NULLかどうかを検査する.@n Windowsの場合,無効ポインタも検出する. @param p 検査するポインタ. @retval TRUE ポインタがNULL,または無効(Windowsの場合) @retval FALSE ポインタはNULLではなく有効(Windowsの場合)である. @attention JunkBox_LIb++ の場合はこの関数ではなく,inline型の isNull() が使用される. */ int isNull(void* p) { if (p==NULL) return TRUE; #ifdef WIN32 if (p==WIN32_NULL) return TRUE; #endif #ifdef WIN64 if (p==WIN64_NULL) return TRUE; #endif return FALSE; } #endif /////////////////////////////////////////////////////////////////////////////////////////// // /** int is_little_endian(void) エンディアンの動的チェック 一度呼び出すと,大域変数 @b HostEndian に @b LITTLE_ENDIAN か @b BIG_ENDIAN が設定される. @retval TRUE Little Endian @retval FALSE Big Endian @see HostEndian, is_big_endian() */ int is_little_endian(void) { unsigned char x[] = {0x01, 0x00}; if (HostEndian==LITTLE_ENDIAN) return TRUE; else if (HostEndian==BIG_ENDIAN) return FALSE; else { if (*((unsigned short*)x)==1) { HostEndian = LITTLE_ENDIAN; return TRUE; } else { HostEndian = BIG_ENDIAN; return FALSE; } } } /** int is_big_endian(void) エンディアンの動的チェック 一度呼び出すと,大域変数 @b HostEndian に @b LITTLE_ENDIAN か @b BIG_ENDIAN が設定される. @retval TRUE Big Endian @retval FALSE Little Endian @see HostEndian, is_little_endian() */ int is_big_endian(void) { unsigned char x[] = {0x00, 0x01}; if (HostEndian==BIG_ENDIAN) return TRUE; else if (HostEndian==LITTLE_ENDIAN) return FALSE; else { if (*((unsigned short*)x)==1) { HostEndian = BIG_ENDIAN; return TRUE; } else { HostEndian = LITTLE_ENDIAN; return FALSE; } } } /** void check_endian(void) 大域変数 @b HostEndian に @b LITTLE_ENDIAN か @b BIG_ENDIAN を設定する. @see HostEndian */ void check_endian(void) { if (HostEndian==UNKNOWN_ENDIAN) is_little_endian(); } /** double double_from_little_endian(void* ptr) Little Endian形式で格納されている double型の値を取り出す. @param ptr 変数が格納されているメモリへのポインタ @return 取り出した double型の値 */ double double_from_little_endian(void* ptr) { double ret = *((double*)ptr); if (HostEndian==UNKNOWN_ENDIAN) check_endian(); if (HostEndian==BIG_ENDIAN) reverse_str((uByte*)(&ret), 8); return ret; } /** float float_from_little_endian(void* ptr) Little Endian形式で格納されている float型の値を取り出す. @param ptr 変数が格納されているメモリへのポインタ @return 取り出した float型の値 */ float float_from_little_endian(void* ptr) { float ret = *((float*)ptr); if (HostEndian==UNKNOWN_ENDIAN) check_endian(); if (HostEndian==BIG_ENDIAN) reverse_str((uByte*)(&ret), 4); return ret; } /** int int_from_little_endian(void* ptr) Little Endian形式で格納されている int型の値を取り出す. @param ptr 変数が格納されているメモリへのポインタ @return 取り出した int型の値 */ int int_from_little_endian(void* ptr) { int ret = *((int*)ptr); if (HostEndian==UNKNOWN_ENDIAN) check_endian(); if (HostEndian==BIG_ENDIAN) reverse_str((uByte*)(&ret), 4); return ret; } /** short short_from_little_endian(void* ptr) Little Endian形式で格納されている short int型の値を取り出す. @param ptr 変数が格納されているメモリへのポインタ @return 取り出した short int型の値 */ short short_from_little_endian(void* ptr) { short ret = *((short*)ptr); if (HostEndian==UNKNOWN_ENDIAN) check_endian(); if (HostEndian==BIG_ENDIAN) reverse_str((uByte*)(&ret), 2); return ret; } /** double double_from_big_endian(void* ptr) Big Endian形式で格納されている double型の値を取り出す. @param ptr 変数が格納されているメモリへのポインタ @return 取り出した double型の値 */ double double_from_big_endian(void* ptr) { double ret = *((double*)ptr); if (HostEndian==UNKNOWN_ENDIAN) check_endian(); if (HostEndian==LITTLE_ENDIAN) reverse_str((uByte*)(&ret), 8); return ret; } /** float float_from_big_endian(void* ptr) Big Endian形式で格納されている float型の値を取り出す. @param ptr 変数が格納されているメモリへのポインタ @return 取り出した float型の値 */ float float_from_big_endian(void* ptr) { float ret = *((float*)ptr); if (HostEndian==UNKNOWN_ENDIAN) check_endian(); if (HostEndian==LITTLE_ENDIAN) reverse_str((uByte*)(&ret), 4); return ret; } /** int int_from_big_endian(void* ptr) Big Endian形式で格納されている int型の値を取り出す. @param ptr 変数が格納されているメモリへのポインタ @return 取り出した int型の値 */ int int_from_big_endian(void* ptr) { int ret = *((int*)ptr); if (HostEndian==UNKNOWN_ENDIAN) check_endian(); if (HostEndian==LITTLE_ENDIAN) reverse_str((uByte*)(&ret), 4); return ret; } /** short short_from_big_endian(void* ptr) Big Endian形式で格納されている short int型の値を取り出す. @param ptr 変数が格納されているメモリへのポインタ @return 取り出した short int型の値 */ short short_from_big_endian(void* ptr) { short ret = *((short*)ptr); if (HostEndian==UNKNOWN_ENDIAN) check_endian(); if (HostEndian==LITTLE_ENDIAN) reverse_str((uByte*)(&ret), 2); return ret; } /////////////////////////////////////////////////////////////////////////////////////////// // Time char _Local_Time[32]; ///< 作業用(ローカルタイム) /** char* get_local_time(void) ローカルタイムを "年:月:日 時:分:秒" の形式で返す. 返ってきた char* ポインタは freeしてはいけない. @return "年:月:日 時:分:秒" 形式のローカルタイム */ char* get_local_time(void) { struct tm* pt; time_t tm; tm = time(NULL); pt = localtime(&tm); snprintf(_Local_Time, 20, "%04d:%02d:%02d %02d:%02d:%02d", pt->tm_year+1900, pt->tm_mon+1, pt->tm_mday, pt->tm_hour, pt->tm_min, pt->tm_sec); return _Local_Time; } /////////////////////////////////////////////////////////////////////////////////////////// /** char* get_line(char* buf, int n) 文字型データstrのバッファ内の n行目を取り出す.改行コードは削除される. 取り出した行を char型変数のバッファに格納して返す.@n バッファの最後が '\0' で終わっている場合,バッファを越えて行を読もうとした場合は NULL を返す.@n '\0' で終わっていない場合,バッファが何処で終わりかを知る事は(簡単な方法では)できない. 返されたデータは free()する必要がある. @param buf 操作対象文の字列型データ(含む改行) @param n 行の指定.1 から数える. @return 指定された n行目の文字列.改行は含まない.要 free */ char* get_line(char* buf, int n) { int i, j, pos, cnt; char* ret = NULL; if (buf==NULL) return NULL; for(i=0,j=0; j=0) { ret = (char*)malloc(cnt+1); if (ret==NULL) return NULL; for(i=0; i=0) { ret = (char*)malloc(cnt+1); if (ret==NULL) return NULL; int i; for(i=0; i0 && j1>=0 && j2>=0) { if (s1[j1--] != s2[j2--]) return 1; n--; } if (n==0) return 0; else return 1; } /** int strncaservscmp(const char* s1, const char* s2, int n) 文字列 s1と s2を後ろから n文字比較する. @retval 0 一致する @retval 1 一致しない @attention strncmp()の戻り値の定義とは若干異なるので注意すること. */ int strncaservscmp(const char* s1, const char* s2, int n) { int j1, j2; if (s1==NULL || s2==NULL) return 1; j1 = (int)strlen(s1) - 1; j2 = (int)strlen(s2) - 1; while (n>0 && j1>=0 && j2>=0) { if (toupper(s1[j1--]) != toupper(s2[j2--])) return 1; n--; } if (n==0) return 0; else return 1; } /** char* strstrcase(const char* buf, const char* nd) 文字列 bufの中に部分文字列 ndがあるかどうかをチェックする.大文字小文字を区別しない. 大文字小文字を区別しない点を除けば,strstr() と同じ.@n つまり strcasestr() と同じ.標準で strcasestr()が存在しない場合に使用. @param buf 検索対象の文字列 @param nd 検索する部分文字列 @return 部分文字列の開始を指すポインタ.部分文字列が見つからない場合は NULL @see strstr(), strcasestr() */ char* strstrcase(const char* buf, const char* nd) { char* pp; char* pb; char* pn; if (buf==NULL || nd==NULL) return NULL; pb = (char*)malloc(strlen(buf)+1); if (pb==NULL) return NULL; memcpy(pb, buf, (int)strlen(buf)+1); pn = (char*)malloc(strlen(nd)+1); if (pn==NULL) { free(pb); return NULL; } memcpy(pn, nd, (int)strlen(nd)+1); upper_string(pb); upper_string(pn); pp = strstr(pb, pn); if (pp!=NULL) { pp = (pp - pb) + (char*)buf; } free(pb); free(pn); return pp; } /** int ex_strncmp(const char* dat, const char* key, int len) 拡張文字比較 @param dat 比べる文字列1. @param key 比べる文字列2. @param len 1以上: 一致させる長さ. @param len 0: 完全一致. @param len -1: dat の長さに合わせる. @param len -2: key の長さに合わせる. @retval TRUE 一致した @retval FALSE 一致しなかった */ int ex_strncmp(const char* dat, const char* key, int len) { if (dat==NULL || key==NULL) return FALSE; if (len==0) { if (!strcmp(dat, key)) return TRUE; } else if (len>0) { if (!strncmp(dat, key, len)) return TRUE; } else if (len<0) { int sz; if (len==-1) sz = (int)strlen(dat); else sz = (int)strlen(key); if (!strncmp(dat, key, sz)) return TRUE; } return FALSE; } /** int ex_strncasecmp(const char* dat, const char* key, int len) 拡張文字比較.ケース無視. @param dat 比べる文字列1. @param key 比べる文字列2. @param len 1以上: 一致させる長さ. @param len 0: 完全一致. @param len -1: dat の長さに合わせる. @param len -2: key の長さに合わせる. @retval TRUE 一致した @retval FALSE 一致しなかった */ int ex_strncasecmp(const char* dat, const char* key, int len) { if (dat==NULL || key==NULL) return FALSE; if (len==0) { if (!strcasecmp(dat, key)) return TRUE; } else if (len>0) { if (!strncasecmp(dat, key, len)) return TRUE; } else if (len<0) { int sz; if (len==-1) sz = (int)strlen(dat); else sz = (int)strlen(key); if (!strncasecmp(dat, key, sz)) return TRUE; } return FALSE; } /** i int ex_strnrvscmp(const char* dat, const char* key, int len) 拡張文字比較.後ろから比べる. @param dat 比べる文字列1. @param key 比べる文字列2. @param len 1以上: 一致させる長さ. @param len 0: 完全一致. @param len -1: dat の長さに合わせる. @param len -2: key の長さに合わせる. @retval TRUE 一致した @retval FALSE 一致しなかった */ int ex_strnrvscmp(const char* dat, const char* key, int len) { if (dat==NULL || key==NULL) return FALSE; if (len==0) { if (!strcmp(dat, key)) return TRUE; } else if (len>0) { if (!strnrvscmp(dat, key, len)) return TRUE; } else if (len<0) { int sz; if (len==-1) sz = (int)strlen(dat); else sz = (int)strlen(key); if (!strnrvscmp(dat, key, sz)) return TRUE; } return FALSE; } /** int ex_strncaervscmp(const char* dat, const char* key, int len) 拡張文字比較.後ろから比べる.ケース無視. @param dat 比べる文字列1. @param key 比べる文字列2. @param len 1以上: 一致させる長さ. @param len 0: 完全一致. @param len -1: dat の長さに合わせる. @param len -2: key の長さに合わせる. @retval TRUE 一致した @retval FALSE 一致しなかった */ int ex_strncaservscmp(const char* dat, const char* key, int len) { if (dat==NULL || key==NULL) return FALSE; if (len==0) { if (!strcasecmp(dat, key)) return TRUE; } else if (len>0) { if (!strncaservscmp(dat, key, len)) return TRUE; } else if (len<0) { int sz; if (len==-1) sz = (int)strlen(dat); else sz = (int)strlen(key); if (!strncaservscmp(dat, key, sz)) return TRUE; } return FALSE; } /** char* chomp(char* buf) 最初の改行コード以降を無視する.最初の改行コードのある場所に '\0' を代入する. @param[in,out] buf 改行を無効にする文字列. @return 処理された buf[] へのポインタ. */ char* chomp(char* buf) { int i, len; if (buf==NULL) return NULL; len = (int)strlen(buf); for (i=0; i=0) { if (pp[i]==cc) i--; else break; } pp[i+1] = '\0'; return pp; } /** char* change_esc(char* mesg) 文字列中の CR, LF を @\r, @\n に変換する. 返されたデータは free()する必要がある. @param mesg 操作対象の文字列 @return 変換後の文字列.要 free */ char* change_esc(char* mesg) { int i, j; char* pp; if (mesg==NULL) return NULL; pp = (char*)malloc((strlen(mesg)+1)*2); if (pp==NULL) return NULL; i = j = 0; while(mesg[i]!='\0') { if (mesg[i]==CHAR_CR) { pp[j++] = '\\'; pp[j++] = 'r'; } else if (mesg[i]==CHAR_LF) { pp[j++] = '\\'; pp[j++] = 'n'; } else { pp[j++] = mesg[i]; } i++; } pp[j] = '\0'; return pp; } /** char* replace_str(char* buf, int len, char* frm, char* tos) buf中の文字列 frmを tosで置き換える. bufには十分な領域がなければならない.frmは bufとメモリ領域が重なってはいけない.@n 失敗した場合は NULLを返し,bufの内容は変化しない. @param[in] buf 操作対象の文字列 @param[out] buf 変換された文字列 @param len bufの領域の大きさ(長さ) @param frm 変換する文字列 @param tos 変換後の文字列 @return buf へのポインタ.失敗した場合は NULL */ char* replace_str(char* buf, int len, char* frm, char* tos) { char* wrk = NULL; int i, j, k, slen, flen, tlen; if (buf==NULL || frm==NULL || tos==NULL) return NULL; wrk = (char*)malloc(len); if (wrk==NULL) return NULL; slen = (int)strlen(buf); flen = (int)strlen(frm); tlen = (int)strlen(tos); i = j = 0; while (i=len) { free(wrk); return NULL; } wrk[j] = '\0'; for (k=0; k<=j; k++) buf[k] = wrk[k]; free(wrk); return buf; } /** char* cut_str(char* buf, int ls, int le) buf[ls] 〜 buf[le] を切り出してメモリに格納して返す. 返されたデータは free()する必要がある. @param buf 操作対象の文字列 @param ls 切り出し開始の位置 @param le 切り出し終了の位置 @return 切り出した文字列.要 free */ char* cut_str(char* buf, int ls, int le) { int i, len; char* ret; if (buf==NULL) return NULL; ls = Max(ls, 0); le = Min(le, (int)strlen((const char*)buf)); len = le - ls + 1; if (len<=0) return NULL; ret = (char*)malloc(len+1); if (ret==NULL) return NULL; memset(ret, 0, len+1); for (i=0; i='0' && str[i]<='9') { ret = ret*16; ret += (int)(str[i] - '0'); } else if (str[i]>='A' && str[i]<='F') { ret = ret*16; ret += (int)(str[i] - 'A') + 10; } else if (str[i]>='a' && str[i]<='f') { ret = ret*16; ret += (int)(str[i] - 'a') + 10; } else if (str[i]!=' ') { break; } } return ret; } /* ************************************************************************* */ #ifndef WIN32 /** void init_rand(void) /dev/urandom から乱数の系列を初期化する /dev/urandom が読めない場合は,呼び出された時の時間(秒数)によって乱数の系列を初期化する. @attention Windows では使用できない */ void init_rand(void) { FILE* fp; unsigned int seed; fp = fopen("/dev/urandom", "rb"); if (fp==NULL) { srand(time(NULL)); return; } fread(&seed, sizeof(unsigned int), 1, fp); fclose(fp); srand(seed); } #endif /** char* randstr(int n) ランダムに A-Za-z0-9 までの文字を n文字生成する. 返されたデータは free()する必要がある. @param n 出力する文字数. @return ランダムに生成された n文字の文字列.要 free */ char* randstr(int n) { char base[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; char* pass; int i, sz; if (n<=0) return NULL; pass = (char*)malloc(n+1); if (pass==NULL) return pass; sz = (int)strlen(base); for (i=0; i=0xa1 && mesg[i]<=0xfe){ // EUC euc2sjis(&mesg[i], &mesg[i+1]); i = i + 2; } else i++; } } /** void kanji_convert_sjis2euc(unsigned char* mesg) SJISをEUCに変換する. @param[in,out] mesg 変換する文字列を持つ unsigned char*型データ.内容が書き換えられる. */ void kanji_convert_sjis2euc(unsigned char* mesg) { int i = 0; while(mesg[i]!='\0' && mesg[i+1]!='\0'){ // if文が変則的なのは,コンパイラで警告が出るため (GCC) 3.3.2 20031218 if ((mesg[i]>=0x81 && mesg[i]<=0x9f) || (mesg[i]>=0xe0 && mesg[i]<=0xfe) || mesg[i]==0xff) { // SJIS sjis2euc(&mesg[i], &mesg[i+1]); i = i + 2; } else i++; } } /** void euc2sjis(unsigned char *c1, unsigned char *c2) 漢字コード変換.EUC→SJIS @param[in,out] c1 変換する文字の第一バイト.内容が書き換えられる. @param[in,out] c2 変換する文字の第二バイト.内容が書き換えられる. */ void euc2sjis(unsigned char *c1, unsigned char *c2) { if (*c1%2==0) *c2 -= 0x02; else{ *c2 -= 0x61; if (*c2>0x7e) (*c2)++; } if (*c1<0xdf) { (*c1)++; *c1 /= 2; *c1 += 0x30; } else { (*c1)++; *c1 /= 2; *c1 += 0x70; } } /** void sjis2euc(unsigned char *c1, unsigned char *c2) 漢字コード変換.SJIS→EUC @param[in,out] c1 変換する文字の第一バイト.内容が書き換えられる. @param[in,out] c2 変換する文字の第二バイト.内容が書き換えられる. */ void sjis2euc(unsigned char *c1, unsigned char *c2) { if (*c2<0x9f) { if (*c1 < 0xa0) { *c1 -= 0x81; *c1 *= 2; *c1 += 0xa1; } else { *c1 -= 0xe0; *c1 *= 2; *c1 += 0xdf; } if (*c2>0x7f) (*c2)--; *c2 += 0x61; } else { if (*c1<0xa0) { *c1 -= 0x81; *c1 *= 2; *c1 += 0xa2; } else { *c1 -= 0xe0; *c1 *= 2; *c1 += 0xe0; } *c2 += 2; } } /** void upper_string(char* str) str中の小文字を大文字に変換する @param[in,out] str 変換する文字列へのポインタ.内容が書き換えられる. */ void upper_string(char* str) { int i; for (i=0; i<(int)strlen((const char*)str); i++) { if (str[i]>='a' && str[i]<='z') str[i] += 'A' - 'a'; } } /** unsigned char* decode_base64(unsigned char* buf, int* sz) bufを base64からデコードする. 変換は bufの先頭から順次行われる.A-Za-z0-9+/ 以外は無視する(例えば改行コード).@n 入力バッファ部が 4byte(6bit*4)の場合, 出力バッファ部は 3byte(8bit*3)となる. 入力バッファ部のバイト数が 4の倍数でない場合(不正なデータ), 足りない入力バッファ部には '='が挿入されているものとみなす. 返されたデータは free()する必要がある. @param buf base64からデコードする文字列. @param[in,out] sz in: sz デコードされたデータの長さを格納する intへのポインタ.i out: デコードされたデータのサイズ @return base64からデコードされたデータ.要 free @par 例 @code "QQ" をデコードすると 'A',0x00 となる. @endcode */ unsigned char* decode_base64(unsigned char* buf, int* sz) { int i, j, cc=0, bas, lt; unsigned char* dcd; lt = 0; while (buf[lt]!='=' && lt<(int)strlen((const char*)buf)) { lt++; if (lt==(int)strlen((const char*)buf)) break; } *sz = lt/4*3 + (lt%4)*3/4; dcd = (unsigned char*)malloc(*sz); if (dcd==NULL) return dcd; memset(dcd, 0, *sz); for (i=0; i='A' && buf[i]<='Z') cc = buf[i] - 'A'; else if (buf[i]>='a' && buf[i]<='z') cc = buf[i] - 'a' + 26; else if (buf[i]>='0' && buf[i]<='9') cc = buf[i] - '0' + 52; else if (buf[i]=='+') cc = 62; else if (buf[i]=='/') cc = 63; if (cc<64) { bas = 32; for (j=0; j<6; j++) { setBit(dcd, i*6+j, cc/bas); cc = cc%bas; bas = bas/2; } } } return dcd; } /** unsigned char* encode_base64(unsigned char* buf, int sz) バイナリデータ bufを base64にエンコードする. 入力バッファ部が 3byte(8bit*3)の場合, 出力バッファ部は 4byte(6bit*4)となる. 入力バッファ部が 6bit境界でない場合, 6bit境界 まで 0が付加されたと見される.@n 出力バッファ部が 4byte境界でない場合, 4byte境界まで '='を付加して出力する. また,出力バッファ部での 60byte毎の改行は行わない.@n 一般に n byte 入力された場合, base64の出力の文字数は (n+2)/3*4 byte となる. 返されたデータは free()する必要がある. @param buf base64にエンコードするデータ. @param sz データの長さを示す.-1以下の場合は buf は文字列とみなす. @return base64にエンコードされた文字列.要 free @par 例 @code 'A',0x00,0x01 を文字列(sz=1)とみなして符号化すると "QQ==" となる. 'A',0x00,0x01 の 3byteを符号化(sz=3)すると "QQAB" となる. @endcode */ unsigned char* encode_base64(unsigned char* buf, int sz) { unsigned char base[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; unsigned char bas; int i, j, len; unsigned char* ecd; if (buf==NULL) return NULL; if (sz<0) len = (int)strlen((const char*)buf); else len = sz; if (len==0) return NULL; sz = (len + 2)/3*4; ecd = (unsigned char*)malloc(sz+1); if (ecd==NULL) return NULL; memset(ecd, 0, sz+1); for (i=0; i i*6) { for (j=0; j<6; j++) { if (len*8 > i*6+j) setBit(&bas, j+2, getBit(buf, i*6+j)); //else setBit(&bas, j+2, 0); } ecd[i] = base[(int)bas]; } else { ecd[i] = '='; } } return ecd; } /** unsigned char* decode_urlenc(unsigned char* buf, int* sz) buf を URLエンコードからデコードする. 返されたデータは free()する必要がある. @param buf デコードする文字列. @param[out] sz デコードされたデータの長さを格納する変数. @return デコードされたデータ.要 free */ unsigned char* decode_urlenc(unsigned char* buf, int* sz) { int i, j, len; unsigned char* dec; if (buf==NULL) return NULL; len = (int)strlen((const char*)buf) + 1; dec = (unsigned char*)malloc(len); if (dec==NULL) return NULL; memset(dec, 0, len); i = j = 0; while (buf[i]!='\0') { if (buf[i]=='%') { if (buf[i+1]=='\0') return dec; if (buf[i+2]=='\0') return dec; dec[j++] = decode_hex(buf[i+1], buf[i+2]); i += 2; } else { if (buf[i]=='+') dec[j++] = ' '; else dec[j++] = buf[i]; } i++; } *sz = j; return dec; } /** unsigned char* encode_urlenc(unsigned char* buf) バイナリデータ bufを URLエンコードする. エンコードしない文字については色々考え方があるが,最大公約数的に考えてこのプログラムでは以下のようにする.@n エンコードしない文字 0-9, A-Z, a-z, -._ 返されたデータは free()する必要がある. @param buf エンコードするデータ. @param sz エンコードするデータの長さ.-1以下の場合は buf は文字列とみなす. @return エンコードされた文字列.要 free */ unsigned char* encode_urlenc(unsigned char* buf, int sz) { int i, j, len; unsigned char* enc; if (sz<0) sz = (int)strlen((const char*)buf); len = sz*3 + 1; enc = (unsigned char*)malloc(len); if (enc==NULL) return NULL; memset(enc, 0, len); for(i=0, j=0; i=0x30 && buf[i]<=0x39) || // 0-9 (buf[i]>=0x41 && buf[i]<=0x5a) || // A-Z (buf[i]>=0x61 && buf[i]<=0x7a) || // a-z buf[i]=='-' || buf[i]=='.' || buf[i]=='_'){ // - . _ enc[j++] = buf[i]; } else { unsigned char* asc = encode_hex(buf[i]); if (asc==NULL) { free(enc); return NULL; } enc[j++] = '%'; enc[j++] = asc[0]; enc[j++] = asc[1]; free(asc); } } return enc; } /** unsigned char* decode_quoted_printable(unsigned char* buf, int* sz) buf を quoted printableからデコードする. 返されたデータは free()する必要がある. @param buf デコードする文字列. @param[out] sz デコードされたデータの長さを格納する変数. @return デコードされたデータ */ unsigned char* decode_quoted_printable(unsigned char* buf, int* sz) { int i, j, len; unsigned char* dec; len = (int)strlen((const char*)buf) + 1; dec = (unsigned char*)malloc(len); if (dec==NULL) return NULL; memset(dec, 0, len); i = j = 0; while (buf[i]!='\0') { if (buf[i]=='=') { if (buf[i+1]=='\0') return dec; if (buf[i+2]=='\0') return dec; dec[j++] = decode_hex(buf[i+1], buf[i+2]); i += 2; } else { if (buf[i]=='_') dec[j++] = ' '; // RFC2047 else dec[j++] = buf[i]; } i++; } *sz = j; return dec; } /** unsigned char* encode_quoted_printable(unsigned char* buf, int sz) バイナリデータ bufを quoted printable にエンコードする. RFC2047 に従い,' ' は '_' にエンコードする.@n エンコードしない文字 '=', '_' 以外の 0x21-0x7e @n エンコードする文字 '=', '_', 0x00-0x20, 0x7f-0xff 返されたデータは free()する必要がある. @param buf エンコードするデータ. @param sz エンコードするデータの長さ.-1以下の場合は buf は文字列とみなす. @return エンコードされた文字列.要 free */ unsigned char* encode_quoted_printable(unsigned char* buf, int sz) { int i, j, len; unsigned char* enc; if (sz<0) sz = (int)strlen((const char*)buf); len = sz*3 + 1; enc = (unsigned char*)malloc(len); if (enc==NULL) return NULL; memset(enc, 0, len); for (i=0, j=0; i=0x7f) { unsigned char* asc = encode_hex(buf[i]); if (asc==NULL) { free(enc); return NULL; } enc[j++] = '='; enc[j++] = asc[0]; enc[j++] = asc[1]; free(asc); } else { enc[j++] = buf[i]; } } return enc; } /** unsigned char* encode_hex(unsigned char cc) キャラクタを16進コードの文字列に変換する. 返されたデータは free()する必要がある. @param cc 変換するキャラクタ. @return 新しく確保された 3byteの領域 @return [0] 16進コードの上位4Bit. 0-9,A-F @return [1] 16進コードの下位4Bit. 0-9,A-F @return [2] '\0' @retval NULL メモリ不足. @par 例 @code encode_hex(' ') は "20" を返す. @endcode */ unsigned char* encode_hex(unsigned char cc) { unsigned char* ret; unsigned char pp1, pp2; unsigned char base[] = "0123456789ABCDEF"; ret = (unsigned char*)malloc(3); if (ret==NULL) return NULL; pp1 = cc >> 4; pp2 = cc & 0x0f; ret[0] = base[pp1]; ret[1] = base[pp2]; ret[2] = '\0'; return ret; } /** unsigned char decode_hex(unsigned char pp1, unsigned char pp2) 16進コードをキャラクタに変換する.O-9,A-F以外が指定された場合は0とみなす. @param pp1 16進コードの上位4Bit. 0-9,A-F @param pp2 16進コードの下位4Bit. 0-9,A-F @return 指定されたASCIIコードのキャラクタ @code 例:decode_hex('2', '0') は ' ' を返す. @endcode */ unsigned char decode_hex(unsigned char pp1, unsigned char pp2) { unsigned char ret; if (pp1>=0x30 && pp1<=0x39) pp1 -= 0x30; // 0-9 else if (pp1>=0x41 && pp1<=0x46) pp1 -= 0x37; // A-F else if (pp1>=0x61 && pp1<=0x66) pp1 -= 0x57; // a-f else pp1 = 0x00; if (pp2>=0x30 && pp2<=0x39) pp2 -= 0x30; // 0-9 else if (pp2>=0x41 && pp2<=0x46) pp2 -= 0x37; // A-F else if (pp2>=0x41 && pp2<=0x46) pp2 -= 0x57; // a-f else pp1 = 0x00; ret = (pp1<<4) + pp2; return ret; } ////////////////////////////////////////////////////////////////////////////////////////////////////// // // /** void print_message(const char* fmt, ...) バッファリング無しのメッセージ出力(stderr) @param fmt 出力フォーマット.printf() に準拠. @see printf() */ void print_message(const char* fmt, ...) { char* nfmt; int len; va_list args; va_start(args, fmt); len = (int)strlen(fmt); nfmt = (char*)malloc(len + 1); if (nfmt==NULL) return; strncpy(nfmt, fmt, len); nfmt[len] = '\0'; vfprintf(stderr, nfmt, args); fflush(stderr); free(nfmt); va_end(args); return; } /** void fprint_message(FILE *fp, const char* fmt, ...) バッファリング無しのメッセージ出力 @param fp 出力先のファイルポインタ @param fmt 出力フォーマット.printf() に準拠. @see printf() */ void fprint_message(FILE* fp, const char* fmt, ...) { char* nfmt; int len; va_list args; va_start(args, fmt); len = (int)strlen(fmt); nfmt = (char*)malloc(len + 1); if (nfmt==NULL) return; strncpy(nfmt, fmt, len); nfmt[len] = '\0'; vfprintf(fp, nfmt, args); fflush(fp); free(nfmt); va_end(args); return; } /** void print_escape(char* fmt, char* mesg) エスケープ文字を含むメッセージの出力.(stderr) 現在は CR, LF のみ @\r, @\n に変換する.see change_esc() @param fmt 出力フォーマット.printf() に準拠. @param mesg エスケープ文字を含む文字列. @see change_esc(), printf() */ void print_escape(char* fmt, char* mesg) { char* pp; if (fmt==NULL || mesg==NULL) return; pp = change_esc(mesg); if (pp==NULL) return; print_message(fmt, pp); free(pp); } /** void fprint_escape(FILE* fp, char* fmt, char* mesg) エスケープ文字を含むメッセージの出力. 現在は CR, LF のみ @\r, @\n に変換する. @param fp 出力先のファイルポインタ @param fmt 出力フォーマット.printf() に準拠. @param mesg エスケープ文字を含む文字列. @see change_esc(), printf() */ void fprint_escape(FILE* fp, char* fmt, char* mesg) { char* pp; if (fmt==NULL || mesg==NULL) return; pp = change_esc(mesg); if (pp==NULL) return; fprint_message(fp, fmt, pp); free(pp); } /** void fdump(FILE* fp, unsigned char* mesg, int n) デバッグ用 16進ダンプ出力. mesgの nバイトを16進表示する.n<0 の場合は 文字列とみなす. @param fp 出力するファイルへのポインタ.NULLの場合は stderr @param mesg 表示するデータ. @param n 表示するバイト数 */ void fdump(FILE* fp, unsigned char* mesg, int n) { int i, j, mod, len; char ascii[16]; if (fp==NULL) fp = stderr; if (mesg==NULL) { fprintf(fp, "(Dump Data is NULL)\n"); return; } if (n<0) len = (int)strlen((const char*)mesg); else len = n; memset(ascii, 0x2e, 16); for (i=0, j=0; i=0x20 && mesg[i]<=0x7e) ascii[j] = mesg[i]; j++; if (j==16) { fprintf(fp, " "); for (j=0; j<16; j++) { fprintf(fp, "%c ", ascii[j]); } fprintf(fp, "\n"); memset(ascii, 0x2e, 16); j = 0; } } mod = len%16; if (mod>0) { for (i=0; i<17-mod; i++) fprintf(fp, " "); for (i=0; ibuf); free(*rb); *rb = NULL; } } /** ringbuffer init_ringbuffer() 期化された ringbuffer変数を返す. @return 期化された ringbuffer変数 @see ringbuffer */ ringbuffer init_ringbuffer() { ringbuffer rb; memset(&rb, 0, sizeof(ringbuffer)); //rb.bufsz = -1; return rb; } /** ringbuffer make_ringbuffer(int sz) バッファ部が存在するリングバッファを作り出す. バッファ部は free()する必要がある. @param sz リングバッファのバッファ部のサイズ @return 作成された ringbuffer変数.バッファ部は 要 free */ ringbuffer make_ringbuffer(int sz) { ringbuffer rb; memset(&rb, 0, sizeof(ringbuffer)); if (sz>0) { rb.buf = (unsigned char*)malloc(sz); if (rb.buf==NULL) return rb; memset(rb.buf, 0, sz); rb.bufsz = sz; } return rb; } /** void free_ringbuffer(ringbuffer* rb) リングバッファのバッファ部を開放する. @param rb リングバッファへのポインタ */ void free_ringbuffer(ringbuffer* rb) { if (rb!=NULL) { freeNull(rb->buf); memset(rb, 0, sizeof(ringbuffer)); } } /** void clear_ringbuffer(ringbuffer* rb) リングバッファ rb のデータをクリア(初期化)する. @param rb リングバッファへのポインタ */ void clear_ringbuffer(ringbuffer* rb) { if (rb!=NULL) { int sz = rb->bufsz; unsigned char* ptr = rb->buf; memset(rb->buf, 0, rb->bufsz); memset(rb, 0, sizeof(ringbuffer)); rb->buf = ptr; rb->bufsz = sz; } } /** int put_ringbuffer(ringbuffer* rb, unsigned char* pp, int sz) リングバッファ rb へデータを szバイト格納する. @param[in] rb メッセージストリームへのポインタ. @param[out] rb @b state 0: バッファは正常状態.-1: バッファは異常な状態にある. @param pp 格納するデータへのポインタ. @param sz 格納するデータのサイズ(Byte) @retval 0以上 書き込んだバイト数. @retval -1 引数にNULLのデータがある. @retval -2 バッファ(データ格納)部の領域がない. @retval -3 バッファ(データ格納)部の大きさがたりない.データはputされなかった. */ int put_ringbuffer(ringbuffer* rb, unsigned char* pp, int sz) { if (rb==NULL) return -1; rb->state = 0; if (pp==NULL) return -1; if (rb->buf==NULL) return -2; if (rb->datasz+sz>rb->bufsz) { rb->state = -1; return -3; } if (rb->epoint+sz<=rb->bufsz) { memcpy(&((rb->buf)[rb->epoint]), pp, sz); rb->epoint = rb->epoint + sz; if (rb->epoint==rb->bufsz) rb->epoint = 0; } else { memcpy(&(rb->buf[rb->epoint]), pp, rb->bufsz-rb->epoint); memcpy(rb->buf, &(pp[rb->bufsz-rb->epoint]), sz-(rb->bufsz-rb->epoint)); rb->epoint = rb->epoint + sz - rb->bufsz; } rb->datasz += sz; return sz; } /** unsigned char* get_ringbuffer(ringbuffer* rb, int sz) リングバッファ rb から szバイトのデータを取り出す. 返されたデータは free()する必要がある. @param[in] rb リングバッファへのポインタ @param[out] rb @b state 0: バッファは正常状態.-1: バッファは異常な状態にある. @param sz 取り出すバイト数. @retval NULL以外 取り出したデータへのポインタ.要 free @retval NULL データ取得失敗.現在有効なデータサイズはszより小さい.または単に失敗した. */ unsigned char* get_ringbuffer(ringbuffer* rb, int sz) { unsigned char* pp; if (rb==NULL) return NULL; rb->state = 0; if (rb->buf==NULL) return NULL; if (sz>rb->datasz) return NULL; pp = (unsigned char*)malloc(sz+1); if (pp==NULL) { rb->state = -1; return NULL; } memset(pp, 0, sz+1); if (rb->spoint+sz<=rb->bufsz) { memcpy(pp, &(rb->buf[rb->spoint]), sz); rb->spoint = rb->spoint + sz; if (rb->spoint==rb->bufsz) rb->spoint = 0; } else { memcpy(pp, &(rb->buf[rb->spoint]), rb->bufsz-rb->spoint); memcpy(&(pp[rb->bufsz-rb->spoint]), rb->buf, sz-(rb->bufsz-rb->spoint)); rb->spoint = rb->spoint + sz - rb->bufsz; } rb->datasz -= sz; return pp; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // バイト型 メッセージストリームバッファ // /** int put_mstream(mstream* sb, unsigned char* mesg) メッセージ(文字列)ストリーム sb へメッセージ(の一部)を格納する.@n ここで,メッセージとは @\r@\n, @\r または @\n で区切られている文字列でのことである. @param[in] sb メッセージストリームへのポインタ @param[out] sb @b state 0: ストリームは正常状態.-1: ストリームは異常な状態にある. @param mesg 格納するメッセージ,またはその一部 @retval 0以上 書き込んだバイト数(CRLFを含む) @retval -1 引数にNULLのデータがある. @retval -2 バッファ(データ格納)部の領域がない. @retval -3 バッファ(データ格納)部の大きさがたりない. */ int put_mstream(mstream* sb, unsigned char* mesg) { int i, n, m, cc, np=0, len; if (sb==NULL) return -1; sb->state = 0; if (mesg==NULL) return -1; if (sb->buf==NULL) return -2; len = (int)strlen((const char*)mesg); for (i=0, n=0, m=0; idatano==0 && n>=1) np = (sb->epoint + m + 1) % sb->bufsz; cc = put_ringbuffer(sb, mesg, len); if (cc>=0) { if (sb->datano==0 && n>=1) sb->npoint = np; sb->datano += n; } if (cc<0) sb->state = -1; return cc; } /** unsigned char* get_mstream(mstream* sb) メッセージ(文字列)ストリーム sb から次のメッセージを取り出す.改行コードは削除される.@n ここで,メッセージとは @\r@\n, @\r または @\n で区切られている文字列でのことである. @param[in] sb メッセージストリームへのポインタ @param[out] sb @b state 0: ストリームは正常状態.-1: ストリームは異常な状態にある.(未実装) @retval NULL以外 取り出したストリームデータへのポインタ.要 free @retval NULL データ取得失敗.現在有効なメッセージデータは無い.または単に失敗した. */ unsigned char* get_mstream(mstream* sb) { int n, len; unsigned char* pp; if (sb==NULL) return NULL; sb->state = 0; if (sb->buf==NULL) return NULL; if (sb->datano==0) return NULL; len = sb->npoint - sb->spoint; if (len==0) return NULL; else if (len<0) len += sb->bufsz; pp = get_ringbuffer(sb, len); if (pp==NULL) { sb->state = -1; return NULL; } chomp((char*)pp); sb->datano += -1; sb->spoint = sb->npoint; if (sb->datano>=1) { int m; n = sb->spoint; while (n!=sb->epoint) { m = (n + 1) % sb->bufsz; if (sb->buf[n]==CHAR_LF || (sb->buf[n]==CHAR_CR && sb->buf[m]!=CHAR_LF)) { sb->npoint = m; break; } n = m; } } return pp; } /** unsigned char* fgets_mstream(unsigned char* mesg, mstream* sb) メッセージストリームからのメッセージ(一行)取り出し. メッセージ mesg はメッセージストリームに一旦バッファリングされ,この関数により一行ずつ読み出される. 結果が返される時,行中の改行コードは削除され,行末には必ず \0 が入る.@n メッセージストリームのバッファ部が確保されていない場合は,最初に呼び出された時点で確保される. 一旦この関数を使用して,受信データをバッファリングしたら,最後まで読み取りには必ず同じストリームを使用して この関数を呼び出さばければならない.そうで無い場合は受信データの整合性は保証されない. @param mesg バッファに一旦格納されるメッセージ.NULLでも可. @param[in] sb ストリームバッファ(リングバッファ型のストリームバッファ). @param[out] sb @b buf バッファ部が確保さえていなければ,自動的に確保される. @param[out] sb @b state 負数: メッセージストリーム操作中は異常な状態にある. @param[out] sb @b state 1: メッセージストリーム中に有効なデータがない.return は NULL @return 取り出した文字列へのポインタ */ unsigned char* fgets_mstream(unsigned char* mesg, mstream* sb) { int state=0; unsigned char* pp; if (sb==NULL) return NULL; if (sb->buf==NULL) { *sb = make_mstream(RECVBUFSZ); if (sb->buf==NULL) return NULL; } if (mesg!=NULL) put_mstream(sb, mesg); if (sb->state<0) state = sb->state; if (sb->datano==0) { sb->state = 1; return NULL; } pp = get_mstream(sb); if (sb->state>=0 && state<0) sb->state = state; return pp; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // // /** unsigned char* uuid2guid(unsigned char* p) バイナリの UUID を テキストのGUIDに変換する.要 free() @param p バイナリの UUID. 128bit @return テキストの GUID. 要 free */ unsigned char* uuid2guid(unsigned char* p) { unsigned char* guid; if (p==NULL) return NULL; guid = (unsigned char*)malloc(LGUID); // 40 = 32+4+1(\0) + α if (guid==NULL) return NULL; snprintf((char*)guid, 37, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8],p[9],p[10],p[11],p[12],p[13],p[14],p[15]); return guid; } /** unsigned char* guid2uuid(unsigned char* p) テキストのGUID をバイナリのUUID に変換する.要 free @n 入力が GUIDの形式でない時は,処理結果は保証されない. @param p テキストの GUID @return バイナリの UUIDへのポインタ.128bit. 要 free */ unsigned char* guid2uuid(unsigned char* p) { int i, j; unsigned char* uuid; if (p==NULL) return NULL; uuid = (unsigned char*)malloc(16); if (uuid==NULL) return NULL; i = j = 0; while (p[i]!='\0' && j<16) { if (p[i]!='-' && p[i+1]!='\0') { unsigned char hb, lb; if (p[i]>='0' && p[i]<='9') hb = p[i] - '0'; else if (p[i]>='a' && p[i]<='f') hb = p[i] - 'a' + 10; else if (p[i]>='A' && p[i]<='F') hb = p[i] - 'A' + 10; else hb = '\0'; if (p[i+1]>='0' && p[i+1]<='9') lb = p[i+1] - '0'; else if (p[i+1]>='a' && p[i+1]<='f') lb = p[i+1] - 'a' + 10; else if (p[i+1]>='A' && p[i+1]<='F') lb = p[i+1] - 'A' + 10; else lb = '\0'; uuid[j] = (hb<<4) + lb; i++; j++; } i++; } return uuid; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // シグナル処理 // #ifndef WIN32 #ifdef SIGCHLD /** void set_sigterm_child(void (*handler)(int)) child プロセス終了時の処理を設定. @param (*handler)() チャイルドプロセス終了時に呼び出される関数へのポインタ @attention シグナル関係の関数は Windowsでは使用できない */ void set_sigterm_child(void (*handler)(int)) { struct sigaction sa; if (handler!=NULL) sa.sa_handler = handler; else sa.sa_handler = sigterm_child; sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGINT); sigaddset(&sa.sa_mask, SIGHUP); sigaddset(&sa.sa_mask, SIGTERM); sigaction(SIGCHLD, &sa, NULL); } /** void set_sigsegv_handler(void (*handler)(int)) セグメンテーションエラー時のハンドラを設定.@n 引数に NULLを指定した場合は,ハンドラ関数として trap_segmentation_falt() を使用. @param (*handler)() セグメンテーションエラー時に呼び出される関数へのポインタ @see trap_segmentation_falt() */ void set_sigsegv_handler(void (*handler)(int)) { struct sigaction sa; if (handler!=NULL) sa.sa_handler = handler; else sa.sa_handler = trap_segmentation_falt; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sigaction(SIGSEGV, &sa, NULL); } /** void trap_segmentation_falt(int signal) セグメンテーションエラー時にデフォルトで呼び出される関数. @param signal ハンドラのシグナル番号.システムによって設定される. */ void trap_segmentation_falt(int signal) { print_message("****************************************************************\n"); print_message("* Segmentation Falt in [%d] !!!!!\n", getpid()); print_message("****************************************************************\n"); exit(signal); } /** void ignore_sigterm_child() 以後 child プロセスの終了を無視する. */ void ignore_sigterm_child() { struct sigaction sa; sa.sa_handler = SIG_IGN; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sigaction(SIGCHLD, &sa, NULL); } /** void sigterm_child(int signal) child プロセス終了時の処理 @param signal ハンドラのシグナル番号.システムによって設定される. */ void sigterm_child(int signal) { pid_t pid = 0; int ret; DEBUG_MESG("%d is waiting for children. signal = %d\n", getpid(), signal); do { // チャイルドプロセスの終了を待つ pid = waitpid(-1, &ret, WNOHANG); } while(pid>0); } #endif // SIGCHLD #endif // NOT WIN32 /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // for Windows // #ifdef WIN32 /* see common.h void bzero(char* p, unsigned int n) { for (unsigned int i=0; i