/* vim: set tabstop=4 paste nocindent noautoindent ff=unix: */ /** @brief 汎用拡張ツールプログラム @file xtools.c @version 1.1 @author Fumi.Iseki (C) @date 2009 2/13 @par 内容 主に,Buffer型, tList型とネットワークのライブラリ @see Buffer, _tList */ #include "xtools.h" ////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Networks // /** int udp_recv_Buffer(int sock, Buffer* str, struct sockaddr_in* sv_addr) recvform()をラッピングした関数.UDPデータを受信する. @param sock ソケット記述子 @param str 受信用メッセージバッファへのポインタ.予めバッファ部を確保しておく. @param sv_addr サーバの情報が格納された sockaddar_in 構造体へのポインタ. @return 受信が正常に行われればそのバイト数. 失敗すれば-1を返す. @see recvform() */ int udp_recv_Buffer(int sock, Buffer* str, struct sockaddr_in* sv_addr) { int cc, cadlen; cadlen = sizeof(*sv_addr); memset(str->buf, 0, str->bufsz); str->vldsz = 0; cc = recvfrom(sock, (char*)str->buf, str->bufsz, 0, (struct sockaddr*)sv_addr, (socklen_t*)&cadlen); if (cc>=0) str->vldsz = cc; return cc; } /** int udp_send_Buffer(int sock, Buffer* str, struct sockaddr_in* sv_addr) sendto() をラッピングした関数.UDP経由でデータを送る. @param sock ソケット記述子 @param str 送信するデータ @param sv_addr サーバの情報を格納する sockaddar_in 構造体へのポインタ. @return 送信が正常に行われればそのバイト数. 失敗すれば-1を返す. @see sendto() */ int udp_send_Buffer(int sock, Buffer* str, struct sockaddr_in* sv_addr) { int cc; if (str->vldsz<0) str->vldsz = (int)strlen((const char*)str->buf); cc = sendto(sock, (char*)str->buf, str->vldsz, 0, (struct sockaddr*)sv_addr, sizeof(*sv_addr)); return cc; } /** int tcp_recv_Buffer(int sock, Buffer* str) TCP経由でデータを受信する.バッファリングなし. @param sock ソケット記述子 @param str 受信用メッセージバッファへのポインタ.予めバッファ部を確保しておく. @return 受信が正常に行われればそのバイト数.失敗すれば-1を返す. */ int tcp_recv_Buffer(int sock, Buffer* str) { int cc; memset(str->buf, 0, str->bufsz); str->vldsz = 0; cc = recv(sock, (char*)str->buf, str->bufsz, 0); if (cc>=0) str->vldsz = cc; return cc; } /** int tcp_send_Buffer(int sock, Buffer* str) TCP経由でデータを送信する. @param sock ソケット記述子 @param str 送信用データバッファ. @return 成功した場合はその送信バイト数.失敗した場合には-1が返る (send()の戻り値). */ int tcp_send_Buffer(int sock, Buffer* str) { int cc; if (str->vldsz<0) str->vldsz = (int)strlen((const char*)str->buf); cc = send(sock, (char*)str->buf, str->vldsz, 0); return cc; } /** int udp_send_sBuffer(int sock, Buffer* str, struct sockaddr_in* sv_addr) UDP経由で文字列データを送る. @param sock ソケット記述子 @param str 送信するデータ @param sv_addr サーバの情報を格納する sockaddar_in 構造体へのポインタ. @return 送信が正常に行われればそのバイト数.失敗すれば-1を返す. */ int udp_send_sBuffer(int sock, Buffer* str, struct sockaddr_in* sv_addr) { int cc; cc = sendto(sock, (char*)str->buf, (int)strlen((const char*)str->buf), 0, (struct sockaddr*)sv_addr, sizeof(*sv_addr)); return cc; } /** int tcp_recv_Buffer_wait(int sock, Buffer* str, int tm) TCP経由で文字列データを受信する. タイムアウトの設定が可能.タイムアウトに 0を指定した場合, recv_wait()関数を呼び出した時点で 読み込み可能データがなければすぐにタイムアウトとなる (RECV_TIMEOUTED が返る). @param sock ソケット記述子 @param str 受信用メッセージバッファへのポインタ.予めバッファ部を確保しておく. @param tm タイムアウト時間.秒単位. @retval 1以上 受信されたバイト数. @retval 0 受信エラー.おそらくは相手側がセッションをクローズした. @retval -1 受信エラー. @retval RECV_TIMEOUTED タイムアウト. */ int tcp_recv_Buffer_wait(int sock, Buffer* str, int tm) { int cc; str->vldsz = 0; cc = tcp_recv_wait(sock, (char*)str->buf, str->bufsz, tm); if (cc>=0) str->vldsz = cc; return cc; } /** int udp_recv_Buffer_wait(int sock, Buffer* str, struct sockaddr_in* sv_addr, int tm) UDP経由で文字列データを受信する. タイムアウトの設定が可能.タイムアウトに 0を指定した場合, recv_wait()関数を呼び出した時点で読み込み可能データがなければすぐにタイムアウト となる (RECV_TIMEOUTED が返る). @param sock ソケット記述子 @param str 受信用メッセージバッファ.予めメモリを確保しておく. @param sv_addr サーバの情報が格納された sockaddar_in 構造体へのポインタ. @param tm タイムアウト時間.秒単位. @retval 0以上 受信したバイト数. @retval -1 受信失敗. @retval RECV_TIMEOUTED タイムアウト. */ int udp_recv_Buffer_wait(int sock, Buffer* str, struct sockaddr_in* sv_addr, int tm) { int cc; str->vldsz = 0; cc = udp_recv_wait(sock, (char*)str->buf, str->bufsz, sv_addr, tm); if (cc>=0) str->vldsz = cc; return cc; } /** int tcp_send_sBuffer(int sock, Buffer* str) TCP経由で文字列データを送信する. @param sock ソケット記述子 @param str 送信用データバッファ. @retval 0以上 送信バイト数. @retval -1 失敗 (send()の戻り値). */ int tcp_send_sBuffer(int sock, Buffer* str) { int cc; cc = send(sock, (char*)str->buf, (int)strlen((const char*)str->buf), 0); return cc; } /** int tcp_send_sBufferln(int sock, Buffer* str) TCPメッセージ(文字列)に改行(@\r@\n)を付け加えて送信する. @param sock ソケット記述子 @param str 送信用メッセージバッファ. @retval 0以上 送信バイト数(改行を含む). @retval - 1 失敗 (send()の戻り値). */ int tcp_send_sBufferln(int sock, Buffer* str) { int cc; Buffer buf; buf = dup_Buffer(*str); cat_s2Buffer("\r\n", &buf); cc = send(sock, (char*)buf.buf, (int)strlen((const char*)buf.buf), 0); free_Buffer(&buf); return cc; } /** int tcp_recv_mstreamBuffer(int sock, Buffer* mesg, mstream* sb, int tm) TCP経由でメッセージ(文字列)を受信する. 受信メッセージはメッセージストリーム に一旦バッファリングされ,この関数により一行ずつ読み出される. mesgに格納される時,行中の改行コードは削除され,行末には必ず \0 が入る. タイムアウトの設定が可能でタイムアウトに 0を指定した場合, 呼び出した時点で 読み込み可能データがなければすぐにタイムアウトとなる (RECV_TIMEOUTED が返る). メッセージストリームのバッファ部が確保されていない場合は,最初に呼び出された時点で確保される. 一旦この関数を使用して,受信データをバッファリングしたら,ソケットを クローズするまで,読み取りには必ず同じストリームを使用してこの関数を呼び出さばければならない. そうで無い場合は受信データの整合性は保証されない. @param sock ソケット記述子 @param mesg 受信用データバッファ.バッファ部を確保する必要はない. @param sb メッセージバッファ(リング型のストリームバッファ) バッファ部が確保さえていなければ,自動的に確保される. @param tm タイムアウト時間.秒単位. @retval 1以上 mesgに格納したメッセージのバイト数. @retval 0 おそらくは相手側がセッションをクローズした. @retval -1 受信エラー. @retval -2 引数に NULLのデータがある. @retval -3 メッセージバッファ部が無いので確保しようとしたが,確保に失敗した. @retval -4 メッセージバッファにデータは存在するはずだが,原因不明の理由により獲得に失敗した. @retval RECV_TIMEOUTED タイムアウト. */ int tcp_recv_mstreamBuffer(int sock, Buffer* mesg, mstream* sb, int tm) { int cc; unsigned char* pp; if (mesg==NULL || sb==NULL) return -2; *mesg = make_Buffer(LBUF); if (sb->buf==NULL) { *sb = make_mstream(RECVBUFSZ); if (sb->buf==NULL) return -3; } while (sb->datano==0) { cc = tcp_recv_Buffer_wait(sock, mesg, tm); if (cc<=0) { free_Buffer(mesg); return cc; } put_mstream(sb, mesg->buf); clear_Buffer(mesg); } pp = get_mstream(sb); if (pp==NULL) return -4; copy_s2Buffer((char*)pp, mesg); free(pp); return mesg->vldsz; } /** int tcp_recv_linesBuffer(int sock, Buffer* mesg, int tm) TCP経由でメッセージ(文字列)を受信する. 複数行分(\nで終わることが保証される)のデータを取り出さすことのできる簡易バッファ機能付き. ここからさらに一行分のデータを取り出すには,get_line() などを使用する.@n また,ネットワークより直接一行づつ取り出すには,tcp_recv_mstreamBuffer() を使うほうが良い. @param sock ソケット記述子 @param mesg 受信用データバッファ.予めメモリを確保しておく. @param tm タイムアウト時間.秒単位. @retval 1以上 受信されたバイト数. @retval 0 おそらくは相手側がセッションをクローズした. @retval -1 受信エラー. @retval -2 bufがNULL @retval RECV_TIMEOUTEDタイムアウト. @bug 受信データが必ず LFで終わることが保障されている場合にしか使用できない. つまり汎用的には「使えない」 */ int tcp_recv_linesBuffer(int sock, Buffer* mesg, int tm) { int cc; Buffer buf; if (mesg==NULL) return -2; buf = make_Buffer(LBUF); cc = tcp_recv_Buffer_wait(sock, &buf, tm); while (cc>0) { cat_Buffer(&buf, mesg); if (buf.buf[cc-1]==CHAR_LF) break; clear_Buffer(&buf); cc = tcp_recv_Buffer_wait(sock, &buf, tm); } free_Buffer(&buf); if (cc<=0) { free_Buffer(mesg); return cc; } return mesg->vldsz; } /** Buffer comp_hostport(char* host, unsigned short port) ホスト名とポート番号から,"ホスト名:ポート番号" の文字列を生成する. @param host ホスト名,またはIPアドレス @param port ポート番号 @return "ホスト名:ポート番号" の文字列が格納されたバッファ型データ. */ Buffer comp_hostport(char* host, unsigned short port) { Buffer buf; char hostport[LBUF]; hostport[0] = '\0'; if (host!=NULL) { if (port!=0) snprintf(hostport, LBUF-1, "%s:%d", host, port); else snprintf(hostport, LBUF-1, "%s", host); } else { if (port!=0) snprintf(hostport, LBUF-1, "%d", port); } buf = make_Buffer_bystr(hostport); return buf; } /** int decomp_hostport(Buffer buf, Buffer* host, unsigned short* port) "ホスト名:ポート番号" 形式の文字列から,ホスト名とポート番号を分離する. @param buf "ホスト名:ポート番号" 形式の文字列の入ったBufferデータ @param[out] host "ホスト名" が格納されて返る. @param[out] port ポート番号 が格納されて返る. @retval TRUE 分離成功 @retval FALSE 分離失敗 */ int decomp_hostport(Buffer buf, Buffer* host, unsigned short* port) { if (buf.buf==NULL) return FALSE; if (port!=NULL) { int i = 0; while (buf.buf[i]!='\0' && buf.buf[i]!=':') i++; if (buf.buf[i]!='\0') *port = (unsigned short)atoi((char*)&buf.buf[i+1]); else *port = 0; } if (host!=NULL) { Buffer hostport = dup_Buffer(buf); int i = 0; while (hostport.buf[i]!='\0' && hostport.buf[i]!=':') i++; hostport.buf[i] = '\0'; hostport.vldsz = (int)strlen((char*)hostport.buf); *host = hostport; } return TRUE; } /** Buffer comp_url(char* protocol, char* host, unsigned short port, char* dir) "プロトコル://ホスト名:ポート番号/ディレクトリ名" の文字列を生成する. @param protocol プロトコル名 @param host ホスト名 @param port ポート番号 @param dir ディレクトリ @return "プロトコル名://ホスト名:ポート番号/ディレクトリ名" の文字列が格納されたバッファ型データ. */ Buffer comp_url(char* protocol, char* host, unsigned short port, char* dir) { Buffer url; char num[20]; url = make_Buffer(LNAME); if (protocol!=NULL) { copy_s2Buffer(protocol, &url); cat_s2Buffer("://", &url); } cat_s2Buffer(host, &url); if (port!=0) { snprintf(num, 10, ":%d", port); cat_s2Buffer(num, &url); } if (dir!=NULL) { if (dir[0]!='/') cat_s2Buffer("/", &url); cat_s2Buffer(dir, &url); } return url; } /** int decomp_url(Buffer url, Buffer* srvurl, Buffer* protocol, Buffer* srvfqdn, unsigned short* sport, Buffer* srvdir) URLを分解する. 分解できるURLの形式は - protocol://www.xxx.yyy.zzz:80/AA/BB - www.xxx.yyy.zzz:80/AA/BB 必要ない情報には NULLを指定可能. @param url 分解するURLの入った Buffer変数. url が https://AAA.BBB.CCC:80/xxx/yyy/zzz の場合 @param[out] srvurl https://AAA.BBB.CCC:80 要 free @param[out] protocol https 要 free @param[out] srvfqdn AAA.BBB.CCC 要 free @param[out] sport 80 @param[out] srvdir /xxx/yyy/zzz 要 free @retval TRUE 分解成功 @retval FALSE 分解失敗 */ int decomp_url(Buffer url, Buffer* srvurl, Buffer* protocol, Buffer* srvfqdn, unsigned short* sport, Buffer* srvdir) { Buffer item1, item2, item3, item4, wrk; if (srvurl !=NULL) *srvurl = init_Buffer(); if (protocol!=NULL) *protocol = init_Buffer(); if (srvfqdn !=NULL) *srvfqdn = init_Buffer(); if (srvdir !=NULL) *srvdir = init_Buffer(); if (sport !=NULL) *sport = 0; if (url.buf ==NULL) return FALSE; item1 = init_Buffer(); item2 = init_Buffer(); item3 = init_Buffer(); item4 = init_Buffer(); if (strstr((char*)url.buf, "://")!=NULL) { // http(s)://www.tuis.ac.jp:8100/..... item1 = awk_Buffer(url, '/', 1); // http(s): item2 = awk_Buffer(url, '/', 3); // www.tuis.ac.jp:8100 if (protocol!=NULL) { *protocol = dup_Buffer(item1); protocol->buf[protocol->vldsz-1] = '\0'; protocol->vldsz--; } } else { // www.tuis.ac.jp:8100/..... item2 = awk_Buffer(url, '/', 1); // www.tuis.ac.jp:8100 } if (item2.buf!=NULL) { item3 = awk_Buffer(item2, ':', 1); // www.tuis.ac.jp if (item3.buf==NULL) { free_Buffer(&item1); free_Buffer(&item2); return FALSE; } item4 = awk_Buffer(item2, ':', 2); // 8100 } else { free_Buffer(&item1); return FALSE; } if (item4.buf!=NULL && sport!=NULL) { *sport = (unsigned short)atoi((char*)item4.buf); } wrk = make_Buffer(LBUF); if (item1.buf!=NULL) { copy_Buffer(&item1, &wrk); cat_s2Buffer("//", &wrk); } cat_Buffer(&item2, &wrk); if (item3.buf!=NULL) { if (srvfqdn!=NULL) *srvfqdn = item3; else free_Buffer(&item3); } if (srvdir!=NULL) { *srvdir = make_Buffer_bystr((char*)(url.buf+strlen((char*)(wrk.buf)))); if ((srvdir->buf)[0]=='\0') copy_s2Buffer("/", srvdir); } if (srvurl!=NULL) *srvurl = wrk; else free_Buffer(&wrk); free_Buffer(&item1); free_Buffer(&item2); free_Buffer(&item4); return TRUE; } /** struct sockaddr_in get_sockaddr_Buffer(Buffer buf) FQDN:port または IPaddress:port の形式の Buffer変数から ソケット情報を得る.@n get_sockaddr() (in network.c) の Buffer版 @param buf "FQDN:ポート番号" または "IPアドレス:ポート番号" 形式のデータ. @return sockaddr_in 構造体型のソケット情報 @see get_sockaddr() */ struct sockaddr_in get_sockaddr_Buffer(Buffer buf) { int i, port = 0; struct sockaddr_in addr; memset(&addr, 0, sizeof(struct sockaddr_in)); if (buf.buf==NULL) return addr; i = 0; while (buf.buf[i]!='\0' && buf.buf[i]!=':') i++; buf.buf[i] = '\0'; port = atoi((char*)&buf.buf[i+1]); addr = get_sockaddr((char*)buf.buf, port); return addr; } Buffer get_hostport_sockaddr(struct sockaddr_in addr) { Buffer buf; char hostport[LBUF]; char* ip = get_ipaddr(addr.sin_addr); unsigned short port = ntohs(addr.sin_port); snprintf(hostport, LBUF, "%s:%d", ip, port); buf = make_Buffer_bystr(hostport); return buf; } /////////////////////////////////////////////////////////////////////////////////////////////////////////// // // File I/O // /** int save_taggedBuffer(Buffer buf, FILE* fp, unsigned int mode, int prfm) Bufferを指定された形式に従ってタグ付きでファイルに保存する. @param buf 保存する情報. @param fp ファイルポインタ. @param mode 保存するデータの種別と保存方法を FBRTL_ マクロで指定する. ただし,保存方法は現在のところ @b FBRTL_ORIGINAL, @b FBRTL_BASE64 のみサポート. @param prfm 保存方法に @b FBRTL_ORIGINAL 以外を指定した場合,その形式に変換するかどうかを指定する. この関数外で,既に変換が完了している場合に FALSE を指定する. (TERUE: 変換する. FALSE: 変換しない) @retval TRUE 成功. @retval FALSE 失敗.ファイルの内容は保証されない. @attention 結局どの形式で保存されるかは,プログラマが保証しなければならない. できるだけデータ形式を指定すべきである. 参考: @code tag部  tag.buf[0] 保存データの種別 tag.buf[1] 保存形式   FBRTL_ORIGINAL, FBRTL_BASE64 をサポート @endcode @see xtool.h */ int save_taggedBuffer(Buffer buf, FILE* fp, unsigned int mode, int prfm) { int cc; Buffer tag, enc; tag = make_Buffer(2); if (tag.buf==NULL) return FALSE; tag.buf[0] = mode & 0x0f; // データの種別 tag.buf[1] = mode & 0xf0; // データの形式 // FBRTL_ORIGINAL, FBRTL_BASE64 以外は未サポート if (tag.buf[1]==FBRTL_ORIGINAL || !prfm) { enc = dup_Buffer(buf); } else if (tag.buf[1]==FBRTL_BASE64) { enc = encode_base64_Buffer(buf); } else { enc = dup_Buffer(buf); } tag.vldsz = 2; cc = save_Buffer2_fp(tag, enc, fp); free_Buffer(&enc); free_Buffer(&tag); if (!cc) return FALSE; return TRUE; } /** Buffer read_taggedBuffer(FILE* fp, unsigned int* mode) Bufferをタグに従ってファイルから読み込む. @param fp ファイルポインタ. @param[in] mode 読み出したいデータの種別と読み出し時のデータ形式を FBRTL_ マクロで指定する. 保存方されているデータと読み出したいデータの種別が一致しない場合は,データを返さない. ただし,@b FBRTL_ANY を指定した場合は一致しなくともデータを返す. @param[out] mode 読み出し時のデータ形式は現在のところ @b FBRTL_ORIGINAL, @b FBRTL_BASE64 のみサポート. リターン時に,保存されていたデータの種別のが FBRTL_ マクロで格納される. @retval TRUE 成功. @retval FALSE 失敗. @attention データ形式が,FBRTL_ORIGINAL, FBRTL_BIN, FBRTL_DER等で保存されている場合は,そのデータ形式に 対して結局はプログラマが責任を持たなければならない. 参考: @code tag部  tag.buf[0] 保存データの種別 tag.buf[1] 保存形式   FBRTL_ORIGINAL, FBRTL_BASE64 をサポート @endcode @see xtool.h */ Buffer read_taggedBuffer(FILE* fp, unsigned int* mode) { unsigned char mthd, kind; Buffer tmp, tag, enc, buf; buf = init_Buffer(); if (mode==NULL) return buf; if (!read_Buffer2_fp(&tag, &enc, fp)) return buf; kind = *mode & 0x0f; // データの種別 mthd = *mode & 0xf0; // データの形式 if (kind!=tag.buf[0] && kind!=FBRTL_ANY) { free_Buffer(&enc); free_Buffer(&tag); return buf; } // FBRTL_ORIGINAL, FBRTL_BASE64 以外は未サポート if (mthd==tag.buf[1]) { // 保存形式と呼び出し形式は同じ buf = dup_Buffer(enc); } else { // 保存データをオリジナルへ if (tag.buf[1]==FBRTL_BASE64) { tmp = decode_base64_Buffer(enc); } else { tmp = dup_Buffer(enc); } // オリジナルを呼び出し形式へ if (mthd==FBRTL_BASE64) { buf = encode_base64_Buffer(tmp); } else { buf = dup_Buffer(tmp); } free_Buffer(&tmp); } *mode = (unsigned int)tag.buf[0]; // データ種別 free_Buffer(&enc); free_Buffer(&tag); return buf; } /** Buffer fgets_mstreamBuffer(Buffer buf, mstream* sb) メッセージ buf.buf はメッセージストリームに一旦バッファリングされ,この関数により一行ずつ読み出される.@n 結果が返される時,行中の改行コードは削除され,行末には必ず @\0 が入る. メッセージストリームのバッファ部が確保されていない場合は,最初に呼び出された時点で確保される.@n 一旦この関数を使用して,受信データをバッファリングしたら,最後まで読み取りには 必ず同じストリームを使用してこの関数を呼び出さばければならない.そうで無い場合は受信データ の整合性は保証されない. @param buf バッファに一旦格納されるメッセージの入ったBuffer型変数.buf.bufはNULLでも可. @param[in] sb ストリームバッファ(リングバッファ型のストリームバッファ).バッファ部が確保さえていなければ,自動的に確保される. @param[out] sb @b state -1: メッセージストリーム操作中にエラー. 1: メッセージストリーム中に有効なデータがない.return は NULL @return 取り出した文字列へのポインタ */ Buffer fgets_mstreamBuffer(Buffer buf, mstream* sb) { Buffer ret; unsigned char* pp; ret = init_Buffer(); pp = fgets_mstream(buf.buf, sb); if (pp!=NULL) { ret = make_Buffer(LBUF); copy_s2Buffer((char*)pp, &ret); free(pp); } return ret; } ///////////////////////////////////////////////////////////////////////////////////////////////// // // Run Length // /** int get_runlength_byte(unsigned char* buf, int len, int pos) 圧縮されていない状態で pos(Byte)の位置が,0の連長圧縮されているデータではどの位置に来るかを計算する. @param buf 連長圧縮(0)されているバイナリデータ @param len buf の長さ @param pos 圧縮されていない場合の位置. @return 0以上 連長圧縮されているデータでの位置. @retval -1 0x00 で終わっている @retval -2 0x00, 0x00 が存在する(連長圧縮のデータではないのでは?) */ int get_runlength_byte(unsigned char* buf, int len, int pos) { int i, sz; sz = -1; for (i=0; i=len) return -1; if (buf[i+1]==0x00) return -2; sz += buf[i+1]; if (sz>=pos) return i; i++; } else sz++; if (sz>=pos) return i; } return -1; } /** Buffer decode_runlength(unsigned char* buf, int len, int sz) 0の連長圧縮された bufから szバイトの通常のデータを取り出す. @param buf 連長圧縮(0)されているバイナリデータ @param len buf の長さ(チェック用) @param sz 取り出すサイズ.0の場合は全て. @return 解凍されたデータを含んだ Buffer型変数 */ Buffer decode_runlength(unsigned char* buf, int len, int sz) { int i, j, k; Buffer ret = init_Buffer(); // 長さを数える i = j = 0; if (sz<=0) { while (jldat.key.buf!=NULL) { nn++; lt = lt->next; } if (nn==0) return NULL; mx = nn; buf = ret = (Buffer*)malloc(sizeof(Buffer)*mx); if (ret==NULL) return NULL; nn = 0; while(lp!=NULL && lp->ldat.key.buf!=NULL) { *buf = dup_Buffer(lp->ldat.key); buf->state = mx - nn; nn++; buf++; lp = lp->next; } return ret; } /** Buffer* get_Buffer_dim_tList_value(tList* lp) リストを分解して,バリュー部の配列を造る @param lp 処理対象リスト @return リストのバリュー部をコピーしたBuffer型配列へのポインタ. 各要素の stateにその要素以降の要素数(自分も含む)が格納される. すなわち,0番目の要素の stateには配列の大きさが可能される. */ Buffer* get_Buffer_dim_tList_value(tList* lp) { int nn, mx; tList* lt; Buffer* buf; Buffer* ret; if (lp==NULL) return NULL; lt = lp; nn = 0; while(lt!=NULL && lt->ldat.val.buf!=NULL) { nn++; lt = lt->next; } if (nn==0) return NULL; mx = nn; buf = ret = (Buffer*)malloc(sizeof(Buffer)*mx); if (ret==NULL) return NULL; nn = 0; while(lp!=NULL && lp->ldat.val.buf!=NULL) { *buf = dup_Buffer(lp->ldat.val); buf->state = mx - nn; nn++; buf++; lp = lp->next; } return ret; } /** Buffer* awk_Buffer_dim(Buffer buf, char cc) ccを区切り記号として, バッファ内の項目を配列にして返す. @param buf 処理対象 Buffer型変数. @param cc 区切り文字. @return ccで区切られた項目をbuf部に格納したBuffer型配列へのポインタ. 各要素の stateにその要素以降の要素数(自分も含む)が格納される. すなわち,0番目の要素の stateには配列の大きさが可能される. @see awk() */ Buffer* awk_Buffer_dim(Buffer buf, char cc) { Buffer* bf = NULL; tList* lp = awk_Buffer_tList(buf, cc); if (lp!=NULL) bf = get_Buffer_dim_tList(lp); del_all_tList(&lp); return bf; } /** Buffer* cawk_Buffer_dim(Buffer buf, char cc) ccを区切り記号として, バッファ内の項目を配列にして返す. 連続する cc(区切り)は一つの区切りとみなす. @param buf 処理対象 Buffer型変数. @param cc 区切り文字. @return ccで区切られた項目をbuf部に格納したBuffer型配列へのポインタ. 各要素の stateにその要素以降の要素数(自分も含む)が格納される. すなわち,0番目の要素の stateには配列の大きさが可能される. @see cawk() */ Buffer* cawk_Buffer_dim(Buffer buf, char cc) { Buffer* bf = NULL; tList* lp = cawk_Buffer_tList(buf, cc); if (lp!=NULL) bf = get_Buffer_dim_tList(lp); del_all_tList(&lp); return bf; } /** Buffer* decompline_Buffer_dim(Buffer buf, int mode) buf を行に分解する.行の区切りは CRLF, CR, LF バイナリデータが混じっている場合は,バイナリデータと思われるデータ以降を一行として返す. 従って最後のデータはバイナリである可能性がある. @param buf 分解するデータの入っている Buffer変数 @param mode @b ON: 行末の CR, LFを削除しない.@b OFF: 行末の CR, LFを削除する. @return 行へのポインタが格納された配列へのポインタ.各データの state に配列の大きさが入る. 使い終わったら del_Buffer_dim()でメモリを解放する. */ Buffer* decompline_Buffer_dim(Buffer buf, int mode) { Buffer* dim; int i, n, m; if (buf.buf==NULL) return NULL; n = i = 0; while(buf.buf[i]!='\0' && istate; for (i=0; istate; if (nn<=0) free_Buffer(buf); for (i=0; i0) { lp = strncasecmp_tList(list, key, 0, no); if (lp!=NULL) { int rep = set_item_tList_node(lp, deli, nm, value); if (rep) cn = 1; } } else { // no<=0 int nn = 1; cn = 0; lp = strncasecmp_tList(list, key, 0, nn); while (lp!=NULL) { int rep = set_item_tList_node(lp, deli, nm, value); if (rep) cn++; lp = strncasecmp_tList(list, key, 0, ++nn); } } return cn; } int set_item_tList_node(tList* lp, char deli, int nm, char* value) { int rep = FALSE; char dl[2] = " "; Buffer* bp; if (lp==NULL || value==NULL) return FALSE; dl[0] = deli; bp = cawk_Buffer_dim(lp->ldat.val, deli); if (bp!=NULL && bp->state>=nm) { Buffer buf = make_Buffer_bystr(value); free_Buffer(&bp[nm-1]); bp[nm-1] = buf; free_Buffer(&lp->ldat.val); lp->ldat.val = join_Buffer_dim(bp, dl); rep = TRUE; } del_Buffer_dim(&bp); return rep; } /** int replace_item_tList(tList* list, char* key, int no, char deli, int nm, char* srcval, char* value) key をキーにした no番目のノードの値の中で,deliを区切りにした nm番目の項目(文字列)の srcval部分を valueで置き換える. @param list 検索対象のヘッダ情報を格納したリスト @param key ヘッダ種別. @param no 同じヘッダ種別が複数ある場合,何番目のノードかを指定する.1から数える. noが 0以下の場合は keyが一致する全てのノードに対して操作を行う. @param deli ノード値(文字列)の区切り文字. @param nm deli を区切り文字として何番目の項目か? 1から数える. @param srcval 置き換え対象の文字列.NULLなら指定した項目の文字列全体 @param value 置き換える文字列. @return 置き換えを行ったノード数. */ int replace_item_tList(tList* list, char* key, int no, char deli, int nm, char* srcval, char* value) { int cn = 0; tList* lp; if (list==NULL || key==NULL || value==NULL) return -1; if (srcval==NULL) { return set_item_tList(list, key, no, deli, nm, value); } if (no>0) { lp = strncasecmp_tList(list, key, 0, no); if (lp!=NULL) { int rep = replace_item_tList_node(lp, deli, nm, srcval, value); if (rep) cn = 1; } } else { // no<=0 int nn = 1; cn = 0; lp = strncasecmp_tList(list, key, 0, nn); while (lp!=NULL) { int rep = replace_item_tList_node(lp, deli, nm, srcval, value); if (rep) cn++; lp = strncasecmp_tList(list, key, 0, ++nn); } } return cn; } int replace_item_tList_node(tList* lp, char deli, int nm, char* srcval, char* value) { int rep = FALSE; char dl[2] = " "; Buffer* bp; Buffer buf; if (lp==NULL || value==NULL) return FALSE; if (nm<=0) nm = 1; if (srcval==NULL) { return set_item_tList_node(lp, deli, nm, value); } dl[0] = deli; bp = cawk_Buffer_dim(lp->ldat.val, deli); if (bp!=NULL && bp->state>=nm) { buf = replace_sBuffer(bp[nm-1], srcval, value); free_Buffer(&bp[nm-1]); bp[nm-1] = buf; free_Buffer(&lp->ldat.val); lp->ldat.val = join_Buffer_dim(bp, dl); rep = TRUE; } del_Buffer_dim(&bp); return rep; } /////////////////////////////////////////////////////////////////////////////////////////////////////// // // General Tools // /** tList* get_dir_files(const char* dirn) 指定されたディレクトリにあるファイル名の一覧を取得.@n Windows の場合は 非 Unicode専用 @param dirn ディレクトリ名 @return ファイル名をバッファ部(ldat.val)に格納したリストへのポインタ. @attention ファイルの種類は区別しない. カレントディレクトリ'.', 親ディレクトリ'..' もリストに入る. */ tList* get_dir_files(const char* dirn) { tList* lp = NULL; #ifdef WIN32 tList* ln = NULL; // WIN32_FIND_DATA FindFileData; WIN32_FIND_DATAA FindFileData; HANDLE hFind; Buffer buf; buf = make_Buffer_bystr(dirn); cat_s2Buffer("\\*", &buf); // hFind = FindFirstFile((LPCTSTR)(buf.buf), &FindFileData); hFind = FindFirstFileA((LPCSTR)(buf.buf), &FindFileData); if (hFind!=INVALID_HANDLE_VALUE) { Buffer tmp; do { tmp = make_Buffer_bystr(dirn); cat_s2Buffer("\\", &tmp); cat_s2Buffer(FindFileData.cFileName, &tmp); ln = add_tList_node_str(ln, NULL, tmp.buf); if (lp==NULL) lp = ln; free_Buffer(&tmp); } while (FindNextFileA(hFind, &FindFileData)); FindClose(hFind); } free_Buffer(&buf); #else tList* ln=NULL; DIR *dp; struct dirent *dir; dp = opendir(dirn); if (dp!=NULL ){ Buffer tmp; dir = readdir(dp); while (dir != NULL ){ tmp = make_Buffer_bystr((char*)dirn); cat_s2Buffer("/", &tmp); cat_s2Buffer(dir->d_name, &tmp); ln = add_tList_node_str(ln, NULL, (char*)tmp.buf); if (lp==NULL) lp = ln; dir = readdir(dp); free_Buffer(&tmp); } closedir(dp); } #endif return lp; }