グローバル関数 ローカル関数 DEFINE,マクロ
TTprintTree
mssCloseFPR
mssCloseFPU
mssFreeFRD
mssFreeFRK
mssFreeFRM
mssFreeFldRec
mssFreeRec
mssGetFileInfo
mssGetFldCntOnData
mssInitFRD
mssInitFRK
mssInitFRM
mssInitFldRec
mssInitRec
mssKeyBreak
mssOpenFPR
mssOpenFPU
mssReadFRD
mssReadFRK
mssReadFRM
mssReadFldRec
mssReadFldRecFRK
mssReadRandFldRec
mssReadRec
mssReopenFPRsort
mssSeekTopFPR
mssSeekTopFRK
TTevaluate
TTfree
TTinit
TTinsert
TTptree
TTsetLeaf
cmpKeyQst
cmpKeyStr
endPreSort
fileOpenErr
fldCntErr
freeSD
getFname
initSD
isEOF
isReadEndTT
keyBreakFRK
mergeTT
needFileRead
preSort
readFPRfile
readTTkey
setConv
setFirstLineTT
sort
sort2
strChrCpy
strToken
writeBuf
writeRecFRK
NextQue
PrevQue
0001: /**
0002: * # CHAPTER #
0003: * ============================================================================
0004: * MUSASHIで用いられるXMLtableデータの入力関連の関数
0005: * ============================================================================
0006: */
0007:
0008: #include <mssHeader.h>
0009: #include <mssXtTag.h>
0010: #include <mssInput.h>
0011:
0012: #include <stdio.h>
0013: #include <stdlib.h>
0014: #include <string.h>
0015: #include <ctype.h>
0016: #include <fcntl.h>
0017: #include <unistd.h>
0018: #include <time.h>
0019: #include <math.h>
0020: #include <errno.h>
0021: #include <limits.h>
0022: #include <sys/types.h>
0023: #include <sys/stat.h>
0024: #include <dirent.h>
0025: #include <signal.h>
0026: #include <float.h>
0027: #include <zlib.h>
0028:
0029: #include <fnmatch.h>
0030: #include <sys/time.h>
0031:
0032: /**
0033: * # MACRO #
0034: * リングバッファにおいて、指定のキュー(a)の次のキュー番号を計算する。
0035: * bにはキューの数を指定する。bは2の累乗でなければならない。
0036: */
0037: #define NextQue(a,b) ((a+1)&(b-1))
0038:
0039: /**
0040: * # MACRO #
0041: * リングバッファにおいて、指定のキュー(a)の前のキュー番号を計算する。
0042: * bにはキューの数を指定する。bは2の累乗でなければならない。
0043: */
0044: #define PrevQue(a,b) ((a-1)&(b-1))
0045:
0046: /* ############ グローバル変数 ##############*/
0047: /*ファイルからの読み込みがEOFとなったときの番兵*/
0048: /*実体ではなくアドレスとして利用している。*/
0049: static char readEnd[2]={0xff,0};
0050:
0051: /*一時ファイル名*/
0052: static char TFname[MssFileNameMaxLen];
0053:
0054: extern struct mssGlobalVariables mssGV;
0055:
0056: /**
0057: * # SECTION #
0058: * ----------------------------------------------------------------------------
0059: * ソート関連
0060: * ----------------------------------------------------------------------------
0061: * あるコマンドでxmlTableを処理する際に事前にソートすることが必要な時、
0062: * mssReopenFPR関数を呼び出すだけで、裏で時動的に並べ換えることができる。
0063: * その際に裏で実行されるソート関連の関数。全てstatic変数で、ライブラリ利用者
0064: * はこれらの関数を意識する必要はない。
0065: * mssReopenFPR関数が呼び出されると、大まかに以下に示すような処理が行われる。
0066: * 1. 入力データをある一定件数読み込む
0067: * 2. その部分データをquickソートする
0068: * 3. 入力データを全て読み込むまで1,2の処理を繰り返し、
0069: * 結果としてn個のソート済ファイルが出来上がる。
0070: * 4. n個のファイルを、ファイル数が"PWayS"個以下になるまでマージする。
0071: * 一回のマージでPWayS個のファイルをマージする。
0072: * その際、トーナメントツリーをプライオリティキューとして利用する。
0073: * 上記の処理を行った後、ユーザは、mssReadFldRecなどのデータ読み込み関数を利用
0074: * でき、ソートを意識せず、通常ファイルと全く同様に扱うことができるようになる。
0075: *
0076: * 【トーナメントツリーの考え方】
0077: * Algorithm by N.Katoh in Maui 2001/06/16-22
0078: *
0079: * 下図では、6つのファイルをマージすることを想定している。
0080: * 1. リーフには各ファイルのカレント行のキーの値がセットされる(図a)。
0081: * 初期状態ではノードには値はセットされていない。
0082: * 2. 次に、トーナメント戦を行い、優勝者を決める(図b)。
0083: * 3. 優勝者のデータを書き出す。
0084: * 4. 優勝者のリーフに次の行のキー値をセットする(図c)。
0085: * 5. 新たにセットされたリーフのみトーナメント戦を行い優勝者を決める(図d)。
0086: * 6. 全データを読み切るまで3-5の処理を繰り返す。
0087: *
0088: * ( ) (a) (a) (b)
0089: * +---+---+ +---+---+ +---+---+ +---+---+
0090: * | | | | | | | |
0091: * ( ) ( ) (a) (b) (a) (b) (e) (b)
0092: * +-+-+ +-+-+ +-+-+ +-+-+ +-+-+ +-+-+ +-+-+ +-+-+
0093: * | | | | | | | | | | | | | | | |
0094: * g a c b g a c b g [e] c b g e c b
0095: * [図a] [図b] [図d] [図d]
0096: */
0097:
0098: static int CmpRevNum; /*ソートにおけるキー比較を*/
0099: /* 0:単純な先頭からの文字列比較で行う*/
0100: /* 1:数値、逆順を考慮して比較を行う*/
0101: struct mssFields *SortFld; /*ソート項目構造体(initSDでセット)*/
0102:
0103: /**
0104: * # FUNCTION #
0105: * キー比較ルーチン
0106: * CmpRevNumがOnの時はs1,s2は(char **)にキャストして利用している。
0107: * s1が勝ちの場合-1 s2が勝ちの場合1を返す 同点の場合は0を返す
0108: * トーナメントツリーにおいて利用される。
0109: */
0110: static int cmpKeyStr(char *s1, char *s2)
0111: {
0112: int i;
0113: int no; /*項目番号*/
0114: int cmp; /*strcmpの結果*/
0115: double n1,n2;
0116:
0117: if(!CmpRevNum){
0118: /*通常の場合はstrcmpの結果が勝ち負けと等しくなる*/
0119: /*s1<s2 -> -1 , s1>s2 -> 1, s1==s2 -> 0*/
0120: return(strcmp(s1,s2));
0121: }else{
0122: if(s1==readEnd) return(1); /*s1が終了ならs2の勝ち*/
0123: if(s2==readEnd) return(-1); /*s2が終了ならs1の勝ち*/
0124: for(i=0; i<SortFld->cnt; i++){
0125: no=MssFlds2num(SortFld,i);
0126: if(MssFlds2numFlg(SortFld,i)){
0127: if(MssIsNull(*((char **)s1+no))) n1=-DBL_MAX;
0128: else n1=atof(*((char **)s1+no));
0129: if(MssIsNull(*((char **)s2+no))) n2=-DBL_MAX;
0130: else n2=atof(*((char **)s2+no));
0131:
0132: if(n1 > n2){
0133: /*数値大きい順の時 n1>n2 -> n1の勝ち*/
0134: if(MssFlds2revFlg(SortFld,i)) return(-1);
0135: /*数値小さい順の時 n1>n2 -> n2の勝ち*/
0136: else return(1);
0137: }else if(n1 < n2){
0138: /*数値大きい順の時 n1<n2 -> n2の勝ち*/
0139: if(MssFlds2revFlg(SortFld,i)) return(1);
0140: /*数値小さい順の時 n1<n2 -> n1の勝ち*/
0141: else return(-1);
0142: }
0143: }else{
0144: /*文字の場合はstrcmpの結果が勝ち負けと等しくなる*/
0145: if(0 != (cmp=strcmp( *((char **)s1+no),*((char **)s2+no))) ){
0146: if(MssFlds2revFlg(SortFld,i)) return(cmp*(-1));
0147: else return(cmp);
0148: }
0149: }
0150: }
0151: }
0152: return(0);
0153: }
0154:
0155: /**
0156: * # FUNCTION #
0157: * キー比較ルーチン(quickソート関数用)
0158: * CmpRevNumがOnの時はs1,s2は(char **)にキャストして利用している。
0159: * s1が勝ちの場合-1 s2が勝ちの場合1を返す 同点の場合は0を返す
0160: */
0161: static int cmpKeyQst(const void **s1,const void **s2)
0162: {
0163: register int i,no,cmp;
0164: double n1,n2;
0165:
0166: if(!CmpRevNum){
0167: return (strcmp( *s1,*s2));
0168: }else{
0169: for(i=0; i<SortFld->cnt; i++){
0170: no=MssFlds2num(SortFld,i);
0171: if(MssFlds2numFlg(SortFld,i)){
0172: if(MssIsNull(*((char **)s1+no))) n1=-DBL_MAX;
0173: else n1=atof(*((char **)s1+no));
0174: if(MssIsNull(*((char **)s2+no))) n2=-DBL_MAX;
0175: else n2=atof(*((char **)s2+no));
0176: if(n1 > n2){
0177: /*数値大きい順の時 n1>n2 -> n1の勝ち*/
0178: if(MssFlds2revFlg(SortFld,i)) return(-1);
0179:
0180: /*数値小さい順の時 n1>n2 -> n2の勝ち*/
0181: else return(1);
0182: }else if(n1 < n2){
0183: /*数値大きい順の時 n1<n2 -> n2の勝ち*/
0184: if(MssFlds2revFlg(SortFld,i)) return(1);
0185: /*数値小さい順の時 n1<n2 -> n1の勝ち*/
0186: else return(-1);
0187: }
0188: }else{
0189: /*文字の場合はstrcmpの結果が勝ち負けと等しくなる*/
0190: if(0 != (cmp=strcmp( *((char **)s1+no),*((char **)s2+no))) ){
0191: if(MssFlds2revFlg(SortFld,i)) return(cmp*(-1));
0192: else return(cmp);
0193: }
0194: }
0195: }
0196: }
0197: return(0);
0198: }
0199:
0200: /**
0201: * # FUNCTION #
0202: * トーナメントツリー(ヒープ)の初期化
0203: * トーナメントツリー(以下TT)の各ノードはTTnode構造体。
0204: * リーフの下図を引数cntで与え、TTを生成し、そのトップノードを返す。
0205: * TTの構造は以下の通り。
0206: *
0207: * a(1)
0208: * +-------+--------+
0209: * | |
0210: * a(2) k(3)
0211: * +-----+------+ +---+--+
0212: * | | | |
0213: * a(4) b(5) z(6) k(7)
0214: * +--+--+ +--+--+
0215: * | | | |
0216: * d(8) a(9) c(10) b(11)
0217: * 親子兄弟の関係
0218: * 本人の番号 = n とすると
0219: * 親の番号 = int(n/2) ex) 5の親=int(5/2)=2 8の親=int(8/2)=4
0220: * 兄弟の番号 = もしnが偶数ならば n+1 基数ならば n-1
0221: * トーナメントはリーフから比較していくので、子から親をたどることとなる。
0222: * よって親から見た子どもの番号は知っている必用はない。
0223: */
0224: static struct TTnode *TTinit(int cnt)
0225: {
0226: int i;
0227:
0228: struct TTnode *top; /*ツリーのトップとなるアドレス*/
0229:
0230: /*ノードとキーのメモリ確保*/
0231: top =mssMalloc(sizeof(struct TTnode)*(2*cnt),"ttInitNode");
0232: top->key=mssMalloc(sizeof(struct TTkey) *(2*cnt),"ttInitKey");
0233:
0234: /*トップノード*/
0235: (top+1)->parent = NULL;
0236: (top+1)->brother = NULL;
0237: (top+1)->num = 1;
0238: (top+1)->key = top->key+1;
0239: (top+1)->key->str = NULL;
0240: (top+1)->key->bkt = 0;
0241:
0242: for(i=2; i<=2*cnt-1; i++){
0243: /*--------初期化*/
0244: (top+i)->num = i;
0245: (top+i)->key = top->key+i;
0246: (top+i)->key->str = NULL;
0247: (top+i)->key->bkt = 0;
0248:
0249: /*--------親ノード*/
0250: (top+i)->parent = top+i/2;
0251:
0252: /*--------兄弟ノード*/
0253: if(i==i/2*2){ /*偶数*/
0254: (top+i)->brother=top+i+1;
0255: }else{ /*奇数*/
0256: (top+i)->brother=top+i-1;
0257: }
0258: }
0259:
0260: return(top);
0261: }
0262:
0263: /**
0264: * # FUNCTION #
0265: * TTnode構造体のメモリ領域開放*
0266: * TTツリーのトップとなるアドレスを引数で与える
0267: */
0268: static void TTfree(struct TTnode *top)
0269: {
0270: mssFree(top->key);
0271: mssFree(top);
0272: }
0273:
0274: /**
0275: * # FUNCTION #
0276: *トーナメントツリーのリーフにデータをセットする。
0277: * ポインタ操作を行うだけで、データの実体は別の場所にあることが前提。
0278: */
0279: static void TTsetLeaf(
0280: struct TTkey *key, /*セットされる文字列などの情報*/
0281: struct TTnode *node,/*トップノード*/
0282: int num){ /*ツリー全体で何番目のノードにセットするか*/
0283:
0284: (node+num)->key->bkt=key->bkt;
0285: (node+num)->key->str=key->str;
0286: }
0287:
0288: /**
0289: * # FUNCTION #
0290: *トーナメントツリーに新しいデータを入れる
0291: * insertとあるが実際には既存のあるリーフ(num)に新しいデータをセットし、
0292: * そのリーフから始まる試合を行うだけで、新しいリーフが挿入されるのではない。
0293: * 新しいリーフが負けた時点で、それ以上試合を行うことは無意味であり、
0294: * 試合を行わないことにより、弱冠の高速化が期待できるが、今回は未実装。
0295: */
0296: static void TTinsert(
0297: struct TTkey *key, /*セットされる文字列などの情報*/
0298: struct TTnode *node,/*トップノード*/
0299: int num){ /*ツリー全体で何番目のノード(リーフ)にセットするか*/
0300:
0301: TTsetLeaf(key,node,num);
0302:
0303: while(num>=2){
0304: /*試合を行い、小さい方が勝ち(親ノードに登録する)。*/
0305: /*左が勝ち(-1) 右が勝ち(0or1)*/
0306: if( 0>cmpKeyStr((node+num)->key->str, (node+num)->brother->key->str) ){
0307: (node+num)->parent->key=(node+num)->key;
0308: }else{
0309: (node+num)->parent->key=(node+num)->brother->key;
0310: }
0311: num=(node+num)->parent->num;
0312: }
0313: }
0314:
0315: /**
0316: * # FUNCTION #
0317: *最初にリーフにデータをセットした時に、全てのトーナメント戦を行う関数
0318: * TTinsertの時には、そのインサートされたリーフからのみ試合を行えばよい
0319: * のでこの関数は使われない
0320: */
0321: static void TTevaluate(
0322: struct TTnode *node,/*トップノード*/
0323: int cnt){ /*葉っぱの数*/
0324: int i;
0325:
0326: /*試合を行い、小さい方が勝ち(親ノードに登録する)。*/
0327: for(i=cnt*2-1; i>=3; i=i-2){
0328: if( 0>cmpKeyStr((node+i)->key->str, (node+i)->brother->key->str) ){
0329: (node+i)->parent->key=(node+i)->key;
0330: }else{
0331: (node+i-1)->parent->key=(node+i)->brother->key;
0332: }
0333: }
0334: }
0335:
0336: /**
0337: * # FUNCTION #
0338: * TTnodeの表示(デバッグ用)
0339: * TTprintTree関数から呼び出される。
0340: */
0341: static void TTptree(
0342: struct TTnode *p,
0343: int num, /*ノード番号*/
0344: int h, /*木の深さ*/
0345: int max) { /*ノード番号の最大値(不変)*/
0346: int i;
0347:
0348: if(num<=max){
0349: TTptree(p, num*2, h+1, max);
0350:
0351: for(i=1; i<=h; i++) printf(" ");
0352: if( (p+num)->key->str == readEnd ){
0353: printf("%d NULL\n",(p+num)->num);
0354: }else{
0355: if(CmpRevNum){
0356: printf("%d ", (p+num)->num);
0357: for(i=0; i<4; i++){
0358: printf("'%s'",*((char **)(p+num)->key->str+i));
0359: }
0360: printf(" %d\n", (p+num)->key->bkt);
0361: }else{
0362: printf("%d '%s' %d\n",
0363: (p+num)->num,(p+num)->key->str,(p+num)->key->bkt);
0364: }
0365: }
0366:
0367: TTptree(p, num*2+1, h+1, max);
0368: }
0369: }
0370:
0371: /**
0372: * # FUNCTION #
0373: * TTツリーの表示(デバッグ用)
0374: */
0375: void TTprintTree(
0376: char *s,
0377: struct TTnode *top,
0378: int cnt){ /*葉っぱの数*/
0379: printf("%s\n",s);
0380: TTptree(top,1,0,cnt*2-1);
0381: printf("------end\n");
0382: }
0383:
0384: /**
0385: * # FUNCTION #
0386: * データを全て読み切った時には、各リーフに番兵がセットされる。
0387: * 引数で与えた文字列が番兵かどうかを検出するための関数。
0388: */
0389: static int isReadEndTT(char *str)
0390: {
0391: if(str==readEnd) return(1);
0392: else return(0);
0393: }
0394:
0395: /**
0396: * # FUNCTION #
0397: *末尾に付ける文字を指定できるstrcpy(返値はコピー後の次のアドレス)
0398: * 新たに領域は確保しないので、文字列toには文字列fromをコピーするに十分な領域
0399: * があることが前提。
0400: */
0401: static char *strChrCpy(
0402: char *to, /*コピーされるメモリ領域*/
0403: char *from, /*コピーする文字*/
0404: char end){ /*末尾に付ける文字*/
0405:
0406: while(*from!='\0'){
0407: *to++=*from++;
0408: }
0409: *to++=end;
0410: return(to);
0411: }
0412:
0413: /**
0414: * # FUNCTION #
0415: *一時ファイル名の取得
0416: */
0417: static char *getFname(char *prefix, int num)
0418: {
0419: sprintf(TFname,"%s%d",prefix,num);
0420: return(TFname);
0421: }
0422:
0423: /**
0424: * # FUNCTION #
0425: * qsortの結果を一時ファイルに書き込む関数
0426: * wrkPntに各行の先頭アドレス、そしてwrkCnt行
0427: */
0428: static void writeBuf(char **wrkPnt,int wrkCnt, char *fname)
0429: {
0430: int i;
0431: struct mssFPW *outFile;
0432:
0433: outFile=mssOpenFPW(fname,0,0);
0434: for(i=0; i<wrkCnt; i++){
0435: mssWriteStr(*(wrkPnt+i),outFile);
0436: mssWriteRet(outFile);
0437: }
0438: mssCloseFPW(outFile);
0439: }
0440:
0441: /**
0442: * # FUNCTION #
0443: * ttKeyに一行読み込む
0444: * 複数のバケットのうちbkt番のファイルから rec構造体に読み込み
0445: * そのアドレスをTTkey構造体にセットする。
0446: * in setFirstLineTT,mergeTT,readFPRfile
0447: */
0448: static void readTTkey(
0449: struct TTkey *ttKey,
0450: struct mssSortDat *sd,
0451: int bkt){
0452:
0453: /*逆順、数値ソートの場合*/
0454: if(CmpRevNum){
0455: if(EOF==mssReadFldRec(sd->iFile[bkt],sd->fr[bkt])){
0456: ttKey->str=readEnd; /*EOFの時は番兵を入れる*/
0457: ttKey->bkt=bkt; /*バケット番号のセット*/
0458: }else{
0459: /*ここではコンパイラの警告を避けるために一旦char **からchar **/
0460: /*にキャストしておく。実際の比較ルーチン(cmpKeyStr)では、*/
0461: /*このアドレスを再びchar **にキャストして、項目ごとの比較を行っている。*/
0462: ttKey->str=(char *)sd->fr[bkt]->pnt; /*読みこんだ文字の先頭アドレス*/
0463: ttKey->bkt=bkt; /*バケット番号のセット*/
0464: }
0465: /*文字列ソートの場合*/
0466: }else{
0467: if(EOF==mssReadRec(sd->iFile[bkt],sd->rec[bkt])){
0468: ttKey->str=readEnd; /*EOFの時は番兵を入れる*/
0469: ttKey->bkt=bkt; /*バケット番号のセット*/
0470: }else{
0471: ttKey->str=sd->rec[bkt]->pnt; /*読みこんだ文字の先頭アドレス*/
0472: ttKey->bkt=bkt; /*バケット番号のセット*/
0473: }
0474: }
0475: }
0476:
0477:
0478: /**
0479: * # FUNCTION #
0480: * 項目を並べ換える時の、元の並びと新しい並びの対応リストを作成する関数
0481: * データ項目名:a b c d k=b,d の時
0482: * 項目を b d a c に項目を並べ換える、そこで
0483: *
0484: * conv[0..3]
0485: * 0 -> b-> 1
0486: * 1 -> d-> 3
0487: * 2 -> a-> 0
0488: * 3 -> c-> 2
0489: */
0490: static void setConv(struct mssSortDat *sd)
0491: {
0492: int i,j;
0493: int tmp[MssFieldMaxLen];
0494:
0495: for(i=0; i<sd->fldCnt; i++) tmp[i]=0;
0496: for(i=0; i<sd->flds->cnt; i++){
0497: tmp[MssFlds2num(sd->flds,i)]=1;
0498: }
0499:
0500: for(i=0; i<sd->fldCnt; i++){
0501: if(i<sd->flds->cnt){
0502: sd->conv[i]=MssFlds2num(sd->flds,i);
0503: }else{
0504: for(j=0; j<sd->fldCnt; j++){
0505: if(tmp[j]==0){
0506: tmp[j]=1;
0507: break;
0508: }
0509: }
0510: sd->conv[i]=j;
0511: }
0512: }
0513: }
0514:
0515: /**
0516: * # FUNCTION #
0517: * 各バケットの最初の行をTTキューに読み込み
0518: * mergeTT,preSortから呼び出される
0519: * iFromからiToまでのファイルの先頭行をTTキューに入れる
0520: */
0521: static void setFirstLineTT(
0522: struct mssSortDat *sd, /*iFile,ttをセットする*/
0523: int iFrom, /*開始ファイル番号*/
0524: int iTo){ /*終了ファイル番号*/
0525:
0526: struct TTkey ttKey; /*TTキューに入れるデータの構造体*/
0527: int bkt; /*現在処理中のバケット番号(0から始まる)*/
0528: int i;
0529:
0530: /*バケット数の設定*/
0531: sd->bktCnt=iTo-iFrom+1;
0532:
0533: /*トーナメントツリーの初期化*/
0534: sd->tt=TTinit(sd->bktCnt);
0535:
0536: bkt=0;
0537: for(i=iFrom; i<=iTo; i++){
0538: /*i番目のバケットのオープン*/
0539: sd->iFile[bkt]=mssOpenFPR(getFname(sd->prefix,i),4);
0540: /*バケットから一行読み込みttKeyにセット*/
0541: readTTkey(&ttKey, sd, bkt);
0542:
0543: /*セットしたttKeyをトーナメントツリーにリーフとしてセット*/
0544: /*全ノード数:2*sd->bktCnt-1, 葉っぱ数:sd->bktCnt;*/
0545: /*よって葉っぱの最初のノード番号:2*sd->bktCnt-1-sd->bktCnt+1=sd->bktCnt*/
0546: TTsetLeaf(&ttKey,sd->tt,sd->bktCnt+bkt);
0547: bkt++;
0548: }
0549:
0550: /*トーナメントツリーで、優勝者を決める*/
0551: TTevaluate(sd->tt,sd->bktCnt);
0552:
0553: /*TTprintTree("############ before",sd->tt,sd->bktCnt);*/
0554: }
0555:
0556: /**
0557: * # FUNCTION #
0558: * TTキューを用いたPWayマージ
0559: * 既に並べ変わっているバケット(iCnt個)を併合していく
0560: * 最後の一つになるまで併合はしない
0561: * PWayS個より少なくなったときに併合を止める
0562: */
0563: static void mergeTT( struct mssSortDat *sd )
0564: {
0565:
0566: int bkt; /*PWay併合のバケット番号*/
0567: struct TTkey ttKey; /*プライオリティキューのデータ構造体*/
0568: struct TTnode *node; /*popにて取りだしたノードを格納*/
0569:
0570: struct mssFPW *oFile; /*出力ワークファイルポインタ*/
0571:
0572: int iStart; /*入力ワークファイルの開始番号(ファイル名の一部)*/
0573: int iEnd; /*入力ワークファイルの終了番号(ファイル名の一部)*/
0574: int oStart; /*出力ワークファイルの開始番号(ファイル名の一部)*/
0575: int oEnd; /*出力ワークファイルの終了番号(ファイル名の一部)*/
0576: int iFrom,iTo; /*併合する時のファイル番号*/
0577: int k;
0578: int i;
0579:
0580: /*次のループでin,outをswapするので、ここでは逆に定義*/
0581: iStart=sd->iEnd+1;
0582: iEnd =sd->iEnd+1;
0583: oStart=sd->iStart;
0584: oEnd =sd->iEnd;
0585:
0586: /*ファイルを併合するループ iCntがPWayS個より大きい場合まわり続ける*/
0587: while(1){
0588: mssSwapInt(&iStart,&oStart);
0589: mssSwapInt(&iEnd ,&oEnd );
0590: oEnd=oStart;
0591:
0592: /*入力ファイル数がPWayS以下ならば終了*/
0593: if(iEnd-iStart+1 <= PWayS){
0594: sd->iStart = iStart;
0595: sd->iEnd = iEnd;
0596: break;
0597: }
0598:
0599: /* "Pway個のiFileを一つのoFileに書き出す"を繰り返すループ*/
0600: k=0;
0601: while(1){
0602:
0603: /*各バケットの最初行をキューに入れる*/
0604: iFrom= k *PWayS+iStart;
0605: iTo =(k+1)*PWayS+iStart-1;
0606: if(iTo>iEnd) iTo=iEnd;
0607: setFirstLineTT(sd, iFrom,iTo);
0608:
0609: /*出力ファイルオープン*/
0610: oFile=mssOpenFPW(getFname(sd->prefix,oEnd),0,0);
0611:
0612: /*各バケットから一行づつ読み込み書き出すループ*/
0613: while(1) {
0614: node=sd->tt+1; /*キューから一行取り出し*/
0615: if(isReadEndTT(node->key->str)) break; /*readEnd(番兵)なら終了*/
0616: bkt=node->key->bkt; /*取り出し元のバケット番号*/
0617: /*一行書き出し*/
0618: if(CmpRevNum){
0619: mssWriteFld((char **)node->key->str,sd->fldCnt,"\n",oFile);
0620: }else{
0621: mssWriteStr(node->key->str,oFile);
0622: mssWriteRet(oFile);
0623: }
0624: readTTkey(&ttKey, sd, bkt); /*次の行を読み込む*/
0625: TTinsert(&ttKey,sd->tt,sd->bktCnt+bkt); /*それをキューに追加*/
0626: /*TTprintTree("############ before",sd->tt,sd->bktCnt);*/
0627: }
0628:
0629: TTfree(sd->tt); /*キューの開放*/
0630: for(i=0; i<=iTo-iFrom; i++) /*入力ファイルのクローズ*/
0631: mssCloseFPR(sd->iFile[i]);
0632: mssCloseFPW(oFile); /*出力ファイルのクローズ*/
0633: if(iTo==iEnd)break; /*最後のバケットまでいけば終了*/
0634: oEnd++; /*出力ファイル番号カウントアップ*/
0635: k++; /*併合回数カウントアップ*/
0636: }
0637:
0638: /*入力ワークファイルの削除*/
0639: for(i=iStart; i<=iEnd; i++){
0640: unlink(getFname(sd->prefix,i));
0641: }
0642: }
0643: }
0644:
0645: /**
0646: * # FUNCTION #
0647: * iCntのバケットを各々quick sortする。
0648: * strChrCpyでバッファ領域にコピーせずに、ファイルバッファをそのまま使えば
0649: * 高速化できる可能性がある。しかし項目を並べ換えるのが問題。
0650: */
0651: static void sort(
0652: struct mssSortDat *sd, /*convは入力として使う、その他は終了状態の記録用*/
0653: struct mssFPR *inFile){
0654:
0655: struct mssFldRec *fr; /*入力ファイルをキー順に並べ換えるためのバッファ*/
0656: int rf; /*入力ファイルからの読み込み文字数*/
0657: int iCnt; /*入力ワークファイルのカウントアップ用変数*/
0658: int wrkCnt; /*buffer行数*/
0659: char *wrkBuf; /*データ本体のbuffer*/
0660: char **wrkPnt; /*データ本体に対するポインタ配列*/
0661: char *curBuf; /*入力ファイルをwrkBufにコピーする際のcurrent位置*/
0662: int i;
0663:
0664: /*データ本体用メモリ領域確保*/
0665: wrkBuf=mssMalloc((MaxMemS+MssRecordMaxLen)*sizeof(char ),"sorting error");
0666: /*データへのポインタ用メモリ領域確保*/
0667: wrkPnt=mssMalloc( MaxLineS * sizeof(char *),"sorting error");
0668:
0669: /*---------------------------------------------*/
0670: /*各バケットのソート(qsort)*/
0671: /*---------------------------------------------*/
0672: /*データをバケット分割し、各バケット内で並べ換える*/
0673: /*iCntにファイル数が入る*/
0674: curBuf=wrkBuf;
0675: iCnt=0;
0676: wrkCnt=0;
0677: fr=mssInitFldRec(sd->fldCnt); /*FldRecの初期化*/
0678: while(1){
0679: /*データの読み込み*/
0680: rf = mssReadFldRec(inFile,fr);
0681:
0682: /*ワークファイルへの書き出し*/
0683: if( curBuf-wrkBuf >= MaxMemS || wrkCnt >= MaxLineS || rf==EOF){
0684: qsort(wrkPnt,wrkCnt,sizeof(char *),
0685: (int (*)(const void *,const void *))cmpKeyQst); /*cmp*/
0686: writeBuf(wrkPnt,wrkCnt,getFname(sd->prefix,iCnt));
0687: iCnt++;
0688: wrkCnt=0; curBuf=wrkBuf;
0689: if(rf==EOF) break;
0690: }
0691:
0692: sd->recCnt++; /*レコード数カウントアップ*/
0693:
0694: /*バッファへのコピー*/
0695: *(wrkPnt+wrkCnt)=curBuf;
0696: wrkCnt++;
0697:
0698: for(i=0; i<sd->fldCnt-1; i++){
0699: curBuf=strChrCpy(curBuf,*(fr->pnt+sd->conv[i]),MssFieldDelim);
0700: }
0701: curBuf=strChrCpy(curBuf,*(fr->pnt+sd->conv[i]),'\0');
0702: }
0703: mssFreeFldRec(fr);
0704: mssFree(wrkBuf);
0705: mssFree(wrkPnt);
0706:
0707: sd->iStart = 0;
0708: sd->iEnd = iCnt-1;
0709: }
0710:
0711: /**
0712: * # FUNCTION #
0713: *iCntのバケットを各々quick sortする。(数値、逆順指定バージョン)
0714: *strChrCpyでバッファ領域にコピーせずに、ファイルバッファをそのまま使えば
0715: *高速化できる可能性がある。しかし項目を並べ換えるのが問題。
0716: */
0717: static void sort2(
0718: struct mssSortDat *sd, /*convは入力として使う、その他は終了状態の記録用*/
0719: struct mssFPR *inFile){
0720:
0721: struct mssFPW *fpw;
0722: struct mssFldRecMax *frm; /*入力ファイルをキー順に並べ換えるためのバッファ*/
0723: int iCnt; /*入力ワークファイルのカウントアップ用変数*/
0724: int i;
0725:
0726: /*---------------------------------------------*/
0727: /*各バケットのソート(qsort)*/
0728: /*---------------------------------------------*/
0729: /*データをバケット分割し、各バケット内で並べ換える*/
0730: /*iCntにファイル数が入る*/
0731: iCnt=0;
0732: frm=mssInitFRM(sd->fldCnt); /*FldRecの初期化*/
0733: while(EOF != mssReadFRM(inFile,frm) ){
0734:
0735: sd->recCnt+=frm->recCnt; /*レコード数カウントアップ*/
0736:
0737: qsort(frm->pnt, frm->recCnt, sizeof(char *)*frm->fldCnt,
0738: (int (*)(const void *,const void *))cmpKeyQst);
0739:
0740: fpw=mssOpenFPW(getFname(sd->prefix,iCnt),0,0);
0741: for(i=0; i<frm->recCnt; i++){
0742: mssWriteFld(frm->pnt+i*frm->fldCnt,frm->fldCnt,"\n",fpw);
0743: }
0744: mssCloseFPW(fpw);
0745: iCnt++;
0746: }
0747: mssFreeFRM(frm);
0748:
0749: sd->iStart = 0;
0750: sd->iEnd = iCnt-1;
0751: }
0752:
0753: /*
0754: 同一コマンドで複数のmssReopenFPRsortを実行するとpidでワークファイルを識別
0755: できなくなる。そのため、initSDを呼び出す毎にsecNumをカウントアップし、
0756: その番号をワークファイル名の一部に含め、この問題を回避する。
0757: */
0758: int secNum=0;
0759:
0760: /**
0761: * # FUNCTION #
0762: * mssSortDat構造体の初期化
0763: */
0764: static struct mssSortDat *initSD(struct mssFields *flds, int fldCnt, char *tmpDir)
0765: {
0766: struct mssSortDat *sd;
0767: int i;
0768: int pid; /*プロセスID(ファイル名の一部)*/
0769:
0770: /*逆順、数値ソート指定があればOn(Global)*/
0771: CmpRevNum=0;
0772: for(i=0; i<flds->cnt; i++){
0773: if( MssFlds2revFlg(flds,i) || MssFlds2numFlg(flds,i) ){
0774: CmpRevNum=1;
0775: }
0776: }
0777:
0778: /*グローバル変数にセット*/
0779: SortFld=flds;
0780:
0781: sd=mssCalloc(sizeof(struct mssSortDat),"initSD");
0782:
0783: sd->flds=flds; /*ソート項目構造体のセット*/
0784:
0785: /*逆順、数値ソートの場合はFldRec構造体を使う*/
0786: if(CmpRevNum){
0787: for(i=0; i<PWayS; i++) sd->fr[i]=mssInitFldRec(fldCnt);
0788:
0789: /*文字列ソートの場合はRec構造体を使う*/
0790: }else{
0791: for(i=0; i<PWayS; i++) sd->rec[i]=mssInitRec();
0792: }
0793:
0794: sd->fldCnt=fldCnt;
0795:
0796: /*ファイル名のプレフィックスの設定*/
0797: pid=getpid();
0798: if(tmpDir==NULL){
0799: mssShowErrMsg("path name of work directory is null");
0800: mssEnd(mssErrorNoDefault);
0801: }
0802: if(strlen(tmpDir) > MssFileNameMaxLen - 50 ) {
0803: mssShowErrMsg("length of path name must be less than %d",MssFileNameMaxLen-50);
0804: mssEnd(mssErrorNoDefault);
0805: }
0806: sprintf(sd->prefix,"%s/xt##%d-%d-PreSrt-",tmpDir,pid,secNum);
0807:
0808: /*シグナルハンドラの設定*/
0809: mssGV.usedTempFileFlg=1;
0810: mssSetSignalHandler();
0811:
0812: secNum++;
0813: return(sd);
0814: }
0815:
0816: /**
0817: * # FUNCTION #
0818: *mssSortDat構造体の開放
0819: */
0820: static void freeSD(struct mssSortDat *sd)
0821: {
0822: int i;
0823:
0824: TTfree(sd->tt); /*トーナメントツリーのキューの開放*/
0825:
0826: if(CmpRevNum){
0827: for(i=0; i<PWayS; i++) mssFreeFldRec(sd->fr[i]);
0828: }else{
0829: for(i=0; i<PWayS; i++) mssFreeRec(sd->rec[i]);
0830: }
0831:
0832: mssFree(sd);
0833: }
0834:
0835: /**
0836: * # FUNCTION #
0837: * マージソートで使った一時ファイルの削除
0838: */
0839: static void endPreSort(struct mssSortDat *sd)
0840: {
0841: int i;
0842:
0843: /*バッファ管理のために、入力ファイルはここで初めてクローズする*/
0844: for(i=0; i<=sd->iEnd-sd->iStart; i++){
0845: mssCloseFPR(sd->iFile[i]);
0846: }
0847:
0848: /*ファイルの削除*/
0849: for(i=sd->iStart; i<=sd->iEnd; i++){
0850: unlink(getFname(sd->prefix,i));
0851: }
0852: }
0853:
0854:
0855: /**
0856: * # FUNCTION #
0857: * バケット毎のqsort+トーナメントツリーによるPWayマージソート
0858: */
0859: static void preSort(
0860: struct mssSortDat *sd,
0861: struct mssFPR *inFile){
0862:
0863:
0864: if(CmpRevNum){/*逆順、数値ソート指定があれば initSDでセット*/
0865: sort2(sd,inFile);
0866: }else{
0867: setConv(sd);
0868: sort(sd,inFile);
0869: }
0870: mergeTT(sd);
0871: setFirstLineTT(sd, sd->iStart,sd->iEnd);
0872: }
0873:
0874: /**
0875: * # SECTION #
0876: * ----------------------------------------------------------------------------
0877: * 入力ファイル関連の関数
0878: * ----------------------------------------------------------------------------
0879: */
0880:
0881: /**
0882: * # FUNCTION #
0883: * ファイル情報の取得
0884: * fNameで与えられたxmlTableファイルについて、maxCnt行を読み込み
0885: * mssFileInfo構造体の行数や項目数などをセットし、その構造体のアドレスを返す。
0886: */
0887: struct mssFileInfo *mssGetFileInfo(char *fName, int maxCnt)
0888: {
0889:
0890: int cnt; /*レコード数をカウント*/
0891: struct mssFileInfo *fi;
0892: struct stat fStat;
0893: struct mssFPR *fpr; /*入力ファイル構造体*/
0894: struct mssHeader *hdi; /*入力ファイル用headerタグ格納構造体*/
0895: struct mssRec *rec=NULL; /*行バッファ構造体*/
0896:
0897: fi=mssMalloc(sizeof(struct mssFileInfo),"chkFile");
0898: if(-1 == stat(fName,&fStat)){
0899: mssShowErrMsg("cannot get file status:%s",fName);
0900: mssEnd(mssErrorNoDefault);
0901: }
0902:
0903: fi->maxCnt = maxCnt;
0904: fi->fName = fName;
0905: fi->totalSize = fStat.st_size;
0906: fi->readEnd = 1;
0907:
0908: fpr=mssOpenFPR(fName,4); /*ファイルオープン*/
0909: hdi=mssReadHeader(fpr); /*項目名情報の読み込み*/
0910: fi->fldCnt = hdi->flds->cnt;
0911: mssFreeHeader(hdi); /*入力ヘッダ領域開放*/
0912:
0913: rec=mssInitRec();
0914: cnt=0;
0915: fi->bodySize=0;
0916: while(EOF != mssReadRec(fpr,rec)){
0917: fi->bodySize += rec->chrCnt;
0918: if(maxCnt<=++cnt && maxCnt!=0){
0919: fi->readEnd = 0;
0920: break;
0921: }
0922: }
0923: fi->recCnt =cnt;
0924: mssFreeRec(rec);
0925: mssCloseFPR(fpr);
0926:
0927: return(fi);
0928: }
0929:
0930: /**
0931: * # FUNCTION #
0932: * mssFPR構造体fpの入力データを全て読み込んだかどうか(EOF)を検出する。
0933: * 返値:1=EOF, 0:not EOF
0934: */
0935: static int isEOF(struct mssFPR *fp)
0936: {
0937: if( fp->last ){ /*eofを含む読み込みをしたか?*/
0938: if(*fp->curPnt=='\0' || 0==strncmp(fp->curPnt,MssEndBodyString,10)){
0939: return(1);
0940: }
0941: }
0942: return(0);
0943: }
0944:
0945: /**
0946: * # FUNCTION #
0947: * 項目数が異なるerrorメッセージの表示&終了
0948: */
0949: static void fldCntErr(char **pnt, int fldCnt, int j, struct mssFPR *fp)
0950: {
0951: if(fp->fName==NULL){
0952: mssShowErrMsg("detected different number of fields in line %d(header has %d, but a record has %d) : %s",mssGV.inCnt+1,fldCnt,j,"stdin");
0953: mssEnd(mssErrorNoDefault);
0954: }else{
0955: mssShowErrMsg("detected different number of fields in line %d(header has %d, but a record has %d) : %s",mssGV.inCnt+1,fldCnt,j,fp->fName);
0956: mssEnd(mssErrorNoDefault);
0957: }
0958: }
0959:
0960: /**
0961: * # FUNCTION #
0962: * mssFPRのリングバッファの現在位置の行でスペースをdelimitorとしてトークン分割
0963: * トークン分割された項目値(文字列)は、*(pnt+i)に格納される。
0964: * よって、pnt変数は、この関数を呼び出す前に、領域確保しておく必要がある。
0965: * 文字列の最後の文字は'\n'でも'\0'でもOK
0966: * -> '\0'はやめるべき。(連続'\0'をスキップするのは危険だから)
0967: * なお、連続する'\n'もしくは'\0'はスキップされる。
0968: * 項目数が異なればエラー終了
0969: * 次の行の先頭位置を返す
0970: */
0971: static char *strToken(char **pnt, int fldCnt, int *chrCnt, struct mssFPR *fp)
0972: {
0973: char *str=fp->curPnt;
0974: int j;
0975:
0976:
0977: /*通常ファイルの場合もしくはソートファイルで数値、逆順ソートの場合*/
0978: if(fp->sd==NULL || CmpRevNum){
0979: j=0; /*項目数カウンタ*/
0980: while(1){
0981: switch(*str){
0982: case MssFieldDelim:
0983: *str='\0';
0984: str++;
0985: break;
0986: case '\n':
0987: case '\0':
0988: if(fldCnt != j){
0989: fldCntErr(pnt,fldCnt,j,fp);
0990: }
0991: *str='\0';
0992: str++;
0993: *chrCnt+=str-fp->curPnt; /*文字数の更新*/
0994: return(str);
0995: break;
0996: default:
0997: /*項目位置を登録*/
0998: if(j<fldCnt) *(pnt+j)=str;
0999: j++;
1000: /*次のMssFieldDelim(もしくはEOL)までスキップ*/
1001: while(*str!=MssFieldDelim && *str!='\n' && *str!='\0') str++;
1002: break;
1003: }
1004: }
1005:
1006: /*ソートファイルの場合*/
1007: }else{
1008: j=0; /*ソートファイル上の項目番号 conv[j]で元のファイル番号*/
1009: while(1){
1010: switch(*str){
1011: case MssFieldDelim:
1012: *str='\0';
1013: str++;
1014: break;
1015: case '\n':
1016: case '\0':
1017: if(fldCnt != j){
1018: fldCntErr(pnt,fldCnt,j,fp);
1019: }
1020: *str='\0';
1021: str++;
1022: *chrCnt+=str-fp->curPnt; /*文字数の更新*/
1023: return(str);
1024: break;
1025: default:
1026: /*項目位置を登録*/
1027: if(j<fldCnt) *(pnt+fp->sd->conv[j]) = str;
1028: j++;
1029: /*次のMssFieldDelim(もしくはEOL)までスキップ*/
1030: while(*str!=MssFieldDelim && *str!='\n' && *str!='\0') str++;
1031: break;
1032: }
1033: }
1034: }
1035:
1036: /*このreturnはあり得ないがコンパイル警告を防ぐため*/
1037: return(str);
1038: }
1039:
1040: /**
1041: * # FUNCTION #
1042: * リングバッファへの入力データ読み込み
1043: * ringBuffer
1044: *
1045: * buf[0] buf[1] .... buf[n]
1046: * +------+ +------+
1047: * A| | +-->| x |
1048: * +------+ | +------+ +
1049: * B| | copy | | |
1050: * | | | | | | 新に読み込み
1051: * +------+ | +------+ |
1052: * C| x |--+ | | |
1053: * +------+ +------+ +
1054: * x:fp->curPnt
1055: *
1056: * read関数にて読み込む領域 : B+C -> BktSize * BktCnt = ReadSize
1057: * fp->curPntがCの領域にあれば、次のバッファに移る。
1058: * その際、Cを次のバッファのAにコピーし、同時にcurPntも移動する。
1059: *
1060: * buf[0]
1061: * buf[n] buf[1] +---->fp->deq
1062: * buf[.] buf[2]
1063: * buf[.] buf[3]+---->fp->cuq
1064: * buf[4]+------>fp->enq
1065: *
1066: * deq : 保存しておくべきバッファの開始位置
1067: * enq : 次にデータを読み込むバッファ位置
1068: * cuq : 現在対象となっているバッファ位置(curPntが含まれる領域)
1069: *
1070: * この関数でeofの検出は行わない
1071: * サイズがReadSizeより少ない時に'\0'を追加
1072: * バッファがfull状態の時に読み込もうとしたら-1を返す。その他の場合は1を返す。
1073: */
1074: static int readFPRfile(struct mssFPR *fp)
1075: {
1076:
1077: /*通常ファイルで利用*/
1078: register int size; /*read関数で読みこんだサイズ*/
1079: register int i;
1080:
1081: /*sortファイルで利用*/
1082: struct TTnode *node; /*popにて取りだしたノードを格納*/
1083: struct TTkey ttKey; /*プライオリティキューのデータ構造体*/
1084: int bkt;
1085:
1086: /*キューがfull*/
1087: if(fp->full) return(-1);
1088:
1089: /*通常ファイルの場合*/
1090: if(!fp->sort){
1091: /*enqが先頭ならばバッファ最後のMssRecordMaxLen文字をバッファの先頭にコピー*/
1092: if(fp->enq==0){
1093: memcpy(fp->buf, fp->buf+fp->queSize*fp->queCnt, MssRecordMaxLen);
1094: fp->curPnt=fp->curPnt-fp->queSize*fp->queCnt; /*curPntの移動*/
1095: }
1096: /*ファイルの読み込み*/
1097: for(i=0; i<ReadCnt; i++){
1098: if(fp->zflg){
1099: size = gzread(fp->zfd,
1100: fp->buf+fp->enq*fp->queSize+PipeSize*i+MssRecordMaxLen,
1101: PipeSize);
1102: }else{
1103: size = fread(fp->buf+fp->enq*fp->queSize+PipeSize*i+MssRecordMaxLen,
1104: sizeof(char) ,PipeSize, fp->fp);
1105: }
1106:
1107: if( 0 > size ) {
1108: mssShowErrMsg("file read error");
1109: mssEnd(mssErrorNoDefault);
1110: }
1111:
1112: /*eofを含む読み込みの場合、eofの印のために'\0'を追加*/
1113: if(size<PipeSize){
1114: *(fp->buf+fp->enq*fp->queSize+PipeSize*i+MssRecordMaxLen+size) = '\0';
1115: fp->last=1;
1116: break;
1117:
1118: /*sizeが0より小さいときは、読み取りエラー*/
1119: }else if(size<0){
1120: mssShowErrMsg("file read error");
1121: mssEnd(mssErrorNoDefault);
1122: }
1123: }
1124:
1125: /*enqueue対象バッファを1つ進める*/
1126: fp->enq=NextQue(fp->enq,fp->queCnt);
1127:
1128: /*バッファfullの判定*/
1129: if(fp->enq == fp->deq) fp->full=1;
1130:
1131: /*sortファイルの場合*/
1132: /*通常ファイルと同等の働きをする*/
1133: /*異なる点は、行単位での読み込みのため、queSizeを越えたデータは次のque*/
1134: /*に読みこまれる。そのため、bufferIsFullの判定はdeq+2==enqの時になる。*/
1135: /*また、bufferの最後のqueの次にはoverFlowBufferがあることが前提となる。*/
1136: }else{
1137: /*enqが先頭ならばバッファ最後のMssRecordMaxLen*2文字をバッファ先頭にコピー*/
1138: if(fp->enq==0){
1139: /*MssRecordMaxLen*2の2はoverFlowBufferの分*/
1140: memcpy(fp->buf, fp->buf+fp->queSize*fp->queCnt, MssRecordMaxLen*2);
1141: fp->curPnt =fp->curPnt -fp->queSize*fp->queCnt; /*curPntの移動*/
1142: fp->readPnt=fp->readPnt-fp->queSize*fp->queCnt; /*curPntの移動*/
1143: }
1144:
1145: /*トーナメントツリーからの読み込み(queSizeを越えるまでstrcpyする)*/
1146: while(1){
1147: /*readPntがenq領域を越えたら読み込み終了*/
1148: if(fp->readPnt>=fp->buf+(fp->enq+1)*fp->queSize+MssRecordMaxLen){
1149: break;
1150: }
1151:
1152: node=fp->sd->tt+1; /*キューから一行取り出し*/
1153: if(isReadEndTT(node->key->str)){ /*readEnd(番兵)を取り出したら終了*/
1154: *fp->readPnt='\0';
1155: fp->last=1;
1156: break;
1157: return(1); /*取りあえず*/
1158: }
1159: bkt=node->key->bkt; /*取り出し元のバケット番号*/
1160:
1161: /*数値、逆順ソートの場合はtnTreeが既に項目を区切っているので戻す*/
1162: /*この処理は無駄のように思えるが、mssReadRec,mssReadFldRecなどの*/
1163: /*上位のread関数を通常と同等に扱えるのでメンテナンスが楽。*/
1164: if(CmpRevNum){
1165: for(i=0; i<fp->sd->fldCnt-1; i++){
1166: fp->readPnt=strChrCpy(fp->readPnt,*((char **)node->key->str+i),
1167: MssFieldDelim);
1168: }
1169: fp->readPnt=strChrCpy(fp->readPnt,*((char **)node->key->str+i),'\n');
1170: }else{
1171: fp->readPnt=strChrCpy(fp->readPnt,node->key->str,'\n');
1172: }
1173: readTTkey(&ttKey, fp->sd, bkt); /*次の行を読み込む*/
1174: TTinsert(&ttKey,fp->sd->tt,fp->sd->bktCnt+bkt);/*キューに追加*/
1175: }
1176: /*enqueue対象バッファを1つ進める*/
1177: fp->enq=NextQue(fp->enq,fp->queCnt);
1178:
1179: /*バッファfullの判定(enqの次のバッファにもデータがかかっているので)*/
1180: if(NextQue(fp->enq,fp->queCnt) == fp->deq) fp->full=1;
1181: }
1182: return(1); /*とりあえず*/
1183: }
1184:
1185: /**
1186: * # FUNCTION #
1187: * readFileする必用があるかどうか
1188: */
1189: static int needFileRead(struct mssFPR *fp)
1190: {
1191:
1192: if(fp->last)return(0);
1193:
1194: /*MssRecordMaxLenは先頭の共通領域があるので、+-で消える*/
1195: if(fp->curPnt >= fp->buf+(PrevQue(fp->enq,fp->queCnt)+1)*fp->queSize)
1196: return(1);
1197: else
1198: return(0);
1199: }
1200:
1201: /**
1202: * # SECTION #
1203: * ----------------------------------------------------------------------------
1204: * 行単位の読み込み関数関連
1205: * ----------------------------------------------------------------------------
1206: * xmlTableのデータを読み込む方法を以下の5種類用意している。
1207: * 1.一行単位での読み込み(mssReadRec)
1208: * 一行ごとに読み込む。項目のトークン分割は行わないので高速である。
1209: * 2.一行項目単位の読み込み(mssReadFldRec)
1210: * 一行ごとに読み込み、項目もトークン分割される。
1211: * 3.二行項目単位の読み込み(mssReadFRD)
1212: * 常にデータ行を二行キープしながら読み込む。キーブレーク処理に便利。
1213: * 4.キー単位の読み込み(mssReadFRK)
1214: * 同じキー値のデータを一旦全て読み込む。
1215: * データ量が大きければ一時ファイルを使う。
1216: * 5.指定されたバイト数まで読み込む(mssReadFRM)
1217: * リングバッファがいっぱいになるまで読み込まれる。
1218: */
1219:
1220: /**
1221: * # FUNCTION #
1222: * mssRec構造体の初期化
1223: */
1224: struct mssRec *mssInitRec(void)
1225: {
1226: struct mssRec *rec;
1227: rec=mssMalloc(sizeof(struct mssRec), "initRec");
1228: rec->chrCnt=0;
1229: rec->eof =0;
1230: return(rec);
1231: }
1232:
1233: /**
1234: * # FUNCTION #
1235: * mssRec構造体の開放
1236: */
1237: void mssFreeRec(struct mssRec *rec)
1238: {
1239: mssFree(rec);
1240: }
1241:
1242: /**
1243: * # FUNCTION #
1244: * mssRec構造体へデータを一行読み込む
1245: * 読み込まれたデータへは、rec->pntで参照可能。
1246: * 行末の改行は省かれる。
1247: */
1248: int mssReadRec(struct mssFPR *fp, struct mssRec *rec)
1249: {
1250: register int i; /*高速化のためにregister変数を利用*/
1251:
1252: /*現在位置がバッファ最後のMssRecordMaxLen文字内にかかっていたらファイル読み込み*/
1253: if(needFileRead(fp)){
1254: readFPRfile(fp);
1255: /*行単位の読み込みの場合は常にdeqはenqの1つ前*/
1256: fp->deq=PrevQue(fp->enq,fp->queCnt);
1257: }
1258: /*eofの検知*/
1259: if(isEOF(fp)){
1260: rec->eof=1;
1261: return(EOF);
1262: }
1263:
1264: /* '\n'をdelimitorとして一行を切り出す*/
1265: rec->pnt=fp->curPnt;
1266: i=0;
1267: while( '\n' != *fp->curPnt++ ){
1268: if(i++>=MssRecordMaxLen){
1269: mssShowErrMsg("exceed %d characters per record\n",MssRecordMaxLen);
1270: mssEnd(mssErrorNoDefault);
1271: }
1272: }
1273: *(fp->curPnt-1)='\0';
1274:
1275: fp->chrCnt+=i+1;
1276: fp->recCnt++;
1277: rec->chrCnt=fp->curPnt-rec->pnt;
1278:
1279: return(1); /*とりあえず*/
1280: }
1281:
1282: /**
1283: * # FUNCTION #
1284: * mssFldRec構造体の初期化
1285: * 引数に項目数を与える。実際に読み込む際に項目数が異なればエラー終了する。
1286: */
1287: struct mssFldRec *mssInitFldRec(int fldCnt)
1288: {
1289: struct mssFldRec *fr;
1290: fr=mssMalloc(sizeof(struct mssFldRec), "initFldRec");
1291: fr->pnt=mssCalloc(sizeof(char *)*fldCnt,"initFldRec");
1292: fr->fldCnt=fldCnt;
1293: fr->chrCnt=0;
1294: fr->eof =0;
1295: return(fr);
1296: }
1297:
1298: /**
1299: * # FUNCTION #
1300: * mssFldRec構造体の開放
1301: */
1302: void mssFreeFldRec(struct mssFldRec* fr)
1303: {
1304: if(fr==NULL) return;
1305: mssFree(fr->pnt);
1306: mssFree(fr);
1307: }
1308:
1309: /**
1310: * # FUNCTION #
1311: * mssFldRec構造体にデータを一行読み込む
1312: * 読み込まれたデータへは、*(rec->pnt+i)で参照可能(iは0から始まる項目番号)。
1313: * 行末の改行は省かれる。
1314: */
1315: int mssReadFldRec(struct mssFPR *fp, struct mssFldRec *fr)
1316: {
1317:
1318: /*現在位置がバッファ最後のMssRecordMaxLen文字内にかかっていたら
1319: ファイル読み込み*/
1320: if(needFileRead(fp)){
1321: readFPRfile(fp);
1322: /*行単位の読み込みの場合は常にdeqはenqの1つ前*/
1323: fp->deq=PrevQue(fp->enq,fp->queCnt);
1324: }
1325:
1326: /*eofの検知*/
1327: if(isEOF(fp)){
1328: fr->eof=1;
1329: return(EOF);
1330: }
1331:
1332: /*スペースをdelimitorとしてトークン分割*/
1333: fp->recCnt++;
1334: fp->curPnt=strToken(fr->pnt, fr->fldCnt, &fp->chrCnt, fp);
1335:
1336: /*文字数をセット(最後の\0含む:コピー用)*/
1337: fr->chrCnt=fp->curPnt-*fr->pnt;
1338: return(1); /*とりあえず*/
1339: }
1340:
1341: /**
1342: * # FUNCTION #
1343: * 固定長ファイルの指定された一行をFldRec構造体に読み込む
1344: * いわゆるランダムアクセス(FPR構造体に固定長アクセスフラグをつくるべき?)
1345: */
1346: int mssReadRandFldRec(
1347: struct mssFPR *fp,
1348: struct mssFldRec *fr,
1349: int recNo, /*seekするレコード番号*/
1350: int datTop, /*データの先頭位置*/
1351: int recLen) /*レコード長*/
1352: { /*レコード長*/
1353:
1354: char *buf;
1355: int cnt;
1356:
1357: buf=mssMalloc(sizeof(char)*MssRecordMaxLen,"readRandFldRec");
1358:
1359: fp->curPnt=buf; /*あまりよくない方法(呼び出し側でmssFreeする)*/
1360: fseek(fp->fp,datTop+recLen*recNo,SEEK_SET);
1361: fread(buf,sizeof(char),MssRecordMaxLen,fp->fp);
1362:
1363: strToken(fr->pnt, fr->fldCnt, &cnt, fp);
1364:
1365: return(1);
1366: }
1367:
1368: /**
1369: * # FUNCTION #
1370: * mssFldRecDbl構造体の初期化
1371: */
1372: struct mssFldRecDbl *mssInitFRD(int fldCnt)
1373: {
1374:
1375: struct mssFldRecDbl *frd;
1376:
1377: frd=mssMalloc(sizeof(struct mssFldRecDbl),"initFRD");
1378: frd->pnt[0]=mssCalloc(sizeof(char *)*fldCnt,"initFRD");
1379: frd->pnt[1]=mssCalloc(sizeof(char *)*fldCnt,"initFRD");
1380:
1381: frd->eof=0;
1382:
1383: frd->new=0;
1384: frd->old=1;
1385:
1386: frd->newChrCnt=0;
1387: frd->oldChrCnt=0;
1388:
1389: /*最初の行を読みこむときだけセットされる*/
1390: frd->firstRead=1;
1391:
1392: frd->fldCnt=fldCnt;
1393:
1394: return(frd);
1395: }
1396:
1397: /**
1398: * # FUNCTION #
1399: * mssFldRecDbl構造体の開放
1400: */
1401: void mssFreeFRD(struct mssFldRecDbl *frd)
1402: {
1403:
1404: mssFree(frd->pnt[0]);
1405: mssFree(frd->pnt[1]);
1406: mssFree(frd);
1407: }
1408:
1409: /**
1410: * # FUNCTION #
1411: * mssFldRecDbl構造体によるデータ読み込みのキーブレイク判定
1412: * 返値 1:キーブレーク 0:キーブレークでない
1413: * 先頭行の読み込み時はキーブレークと判定しない。
1414: * EOFの読み込み時はキーブレークと判定しする。
1415: * opeKey->diffSame が1の場合(全行異なるキー値と見る場合)は常に1を返す。
1416: * opeKey->diffSame が0の場合(全行同じキー値と見る場合)は常に0を返す。
1417: */
1418: int mssKeyBreak(struct mssFldRecDbl *frd, MssOptKEY *optKey)
1419: {
1420: int i,fn;
1421:
1422: /*最初行の時はキーブレークでない*/
1423: if(frd->firstRead){
1424: /*multi keyに対応するために以下のif文を追加*/
1425: if(frd->new){
1426: return(0);
1427: }else{
1428: frd->firstRead=0;
1429: }
1430: }
1431:
1432: /*最終行の時はキーブレーク*/
1433: if(frd->eof == 1) return(1);
1434:
1435: switch(optKey->diffSame){
1436:
1437: /*キーを全て異なる値と見る場合はキーブレーク*/
1438: case 1:
1439: return(1);
1440:
1441: /*キー全て同じ値と見る場合はキーブレーク*/
1442: case 2:
1443: return(0);
1444:
1445: default:
1446: for(i=0; i<optKey->flds->cnt; i++){
1447: fn=MssFlds2num(optKey->flds,i);
1448: if( 0 != strcmp(*(frd->pnt[frd->new]+fn),*(frd->pnt[frd->old]+fn)) )
1449: return(1);
1450: }
1451:
1452: /*上記の条件をクリアしたということはキーブレークでない*/
1453: /*(key->cntが0ということは、-kの指定がないのでキーブレークでない)*/
1454: return(0);
1455: }
1456: }
1457:
1458:
1459: /**
1460: * # FUNCTION #
1461: * mssFldRecDbl構造体にデータを一行読み込む
1462: * 読み込まれたデータのカレント行へは、*(frd->pnt[frd->new]+i)
1463: * 一行前の行へは*(frd->pnt[frd->old]+i) で参照可能(iは0から始まる項目番号)。
1464: * 先頭行を読み込んだとき、一行前は存在しないので*(frd->pnt[frd->old]+i)は、
1465: * NULLとなる。
1466: * EOFを読み込んだときは、EOFを返す。
1467: */
1468: int mssReadFRD(struct mssFPR *fp, struct mssFldRecDbl *frd)
1469: {
1470: char *start;
1471:
1472: if(frd->eof) return(EOF);
1473:
1474: /*現在位置がバッファ最後のMssRecordMaxLen文字内にかかっていたらファイル読み込み*/
1475: if(needFileRead(fp)){
1476: readFPRfile(fp);
1477: /*二行単位の読み込みでも、queCntは最低4つ必用*/
1478: fp->deq=PrevQue(fp->enq,fp->queCnt);
1479: }
1480:
1481: /*eofの検知 最初にサイズ比較するのは、strcmpの比較を減らすため*/
1482: if(isEOF(fp)){ /* 現在の読み込みポインタが</body>ならば*/
1483: if(frd->newChrCnt==0)return(EOF); /*データ行がないときに引っかかる*/
1484: frd->eof=1;
1485: mssSwapInt(&frd->new,&frd->old);
1486: return(1);
1487: }
1488:
1489: /*newに新しい行の項目位置をいれるために、newとoldを入れ換える*/
1490: mssSwapInt(&frd->new,&frd->old);
1491:
1492: /*スペースをdelimitorとしてトークン分割*/
1493: start=fp->curPnt; /*現在の位置を確保*/
1494: fp->recCnt++;
1495: fp->curPnt=strToken(frd->pnt[frd->new], frd->fldCnt,&fp->chrCnt,fp);
1496:
1497: /*new,old行の文字数をセット(最後の\0含む:コピー用)*/
1498: frd->oldChrCnt=frd->newChrCnt;
1499: frd->newChrCnt=start-*frd->pnt[frd->new]+1;
1500:
1501: return(1); /*とりあえず*/
1502: }
1503:
1504: /**
1505: * # FUNCTION #
1506: * mssFldRecMax構造体の初期化
1507: */
1508: struct mssFldRecMax *mssInitFRM(int fldCnt)
1509: {
1510: struct mssFldRecMax *frm;
1511: frm=mssMalloc(sizeof(struct mssFldRecMax),"initFRM");
1512: frm->fldCnt=fldCnt;
1513: frm->chrCnt=0;
1514: frm->eof =0;
1515: frm->recCnt=0;
1516: frm->recMax=MaxPntSize/(fldCnt*sizeof(char *));
1517:
1518: /*ポインタ領域の確保(freeのために最低一行分のみ確保)*/
1519: frm->pnt=mssMalloc(sizeof(char *)*frm->fldCnt*frm->recMax,"initFRM");
1520: return(frm);
1521: }
1522:
1523: /**
1524: * # FUNCTION #
1525: * mssFldRecMax構造体の開放
1526: */
1527: void mssFreeFRM(struct mssFldRecMax *frm)
1528: {
1529: mssFree(frm->pnt);
1530: mssFree(frm);
1531: }
1532:
1533: /**
1534: * # FUNCTION #
1535: * mssFldRecMax構造体に次のいずれの条件も満たしている間、データを読み込み続ける。
1536: * 1. 指定された最大レコード数(MaxPntSize/(項目数*sizeof(char *)))を超えない。
1537: * 2. リングバッファ(サイズはmssOpenFPR関数で決まる)がFULLでない。
1538: * 読み込まれたデータは、項目単位でfrm->pntに蓄積されていく。
1539: * 例えば "a b c","x y z"の2行のデータを読み込んだ場合、
1540: * *(pnt+0)="a",*(pnt+1)="b",*(pnt+2)="c",*(pnt+3)="x",*(pnt+4)="y",*(pnt+5)="z"
1541: * となる。そこで、n行目(0から始まる)のm項目目(0から始まる)にアクセスしたい
1542: * 場合は、*(frm->pnt+frm->fldCnt*n+m)とする。
1543: * 先頭行としてEOFを読み込んだときは、EOFを返す。
1544: */
1545: int mssReadFRM(struct mssFPR *fp, struct mssFldRecMax *frm)
1546: {
1547:
1548: if(frm->eof){
1549: return(EOF);
1550: }
1551:
1552: frm->recCnt=0;
1553:
1554: while(1){
1555:
1556: /*ポインタバッファがfullであればリターン*/
1557: if(frm->recCnt>=frm->recMax){
1558: fp->deq = PrevQue(fp->enq,fp->queCnt);
1559: fp->full=0;
1560: return(1);
1561: }
1562:
1563: /*現在位置がバッファ最後のMssRecordMaxLen文字内にかかっていたらファイル読み込み*/
1564: if(needFileRead(fp)){
1565: /*データバッファがfullであれば終了*/
1566: if(-1==readFPRfile(fp)){
1567: fp->deq = PrevQue(fp->enq,fp->queCnt);
1568: fp ->full=0;
1569: return(1);
1570: }
1571: }
1572:
1573: /*データのeofの検知*/
1574: if(isEOF(fp)){
1575: frm->eof=1;
1576: return(1);
1577: }else{
1578: /*スペースをdelimitorとしてトークン分割*/
1579: fp->recCnt++;
1580: fp->curPnt=strToken(frm->pnt+frm->recCnt*frm->fldCnt, frm->fldCnt,&fp->chrCnt,fp);
1581: frm->recCnt++;
1582: }
1583: }
1584: return(1);
1585: }
1586:
1587: /**
1588: * # FUNCTION #
1589: * mssFldRecKey構造体の初期化
1590: */
1591: struct mssFldRecKey *mssInitFRK(int fldCnt, MssOptKEY *optKey, char *path)
1592: {
1593:
1594: struct mssFldRecKey *frk;
1595: int pid;
1596:
1597: /*FRK構造体領域の確保*/
1598: frk=mssMalloc(sizeof(struct mssFldRecKey),"initFRK");
1599:
1600: /*初期化*/
1601: frk->frPnt = NULL;
1602: frk->pnt = mssMalloc(sizeof(char *)*fldCnt,"readFldRecFRK");
1603: frk->fldCnt = fldCnt;
1604: frk->chrCnt = 0;
1605: frk->eof = 0;
1606: frk->keyRecCnt = 0;
1607: frk->keyNo = 0;
1608: frk->firstRead = 1;
1609: frk->alcRecCnt = 0;
1610: frk->recPnt = 0;
1611: frk->optKey = optKey;
1612: frk->byFile = 0;
1613: frk->curRecNo = 0;
1614: frk->fpw = NULL;
1615: frk->fpr = NULL;
1616: frk->fr = NULL;
1617:
1618: pid=getpid();
1619: sprintf(frk->fName,"%s/xt##%d-FRK",path,pid);
1620:
1621: /*シグナルハンドラの設定*/
1622: mssGV.usedTempFileFlg=1;
1623: mssSetSignalHandler();
1624:
1625: return(frk);
1626: }
1627:
1628: /**
1629: * # FUNCTION #
1630: * mssFldRecKey構造体の開放
1631: */
1632: void mssFreeFRK(struct mssFldRecKey *frk)
1633: {
1634: if(frk==NULL) return;
1635: if(0==access(frk->fName,R_OK & W_OK)) unlink(frk->fName);
1636: mssFree(frk->pnt);
1637: mssFree(frk->frPnt);
1638: mssFree(frk);
1639: mssFreeFldRec(frk->fr);
1640: mssCloseFPR(frk->fpr);
1641: }
1642:
1643: /**
1644: * # FUNCTION #
1645: * readFRK内部で利用するキーブレーク判定
1646: * 同じキーの値を持つ最初の行と現在読み込んだ行を比較する。
1647: */
1648: static int keyBreakFRK(struct mssFldRecKey *frk)
1649: {
1650: int i,fn;
1651:
1652: /*初回の読み込みはキーブレークでない*/
1653: if(frk->firstRead){
1654: frk->firstRead=0;
1655: return(0);
1656: }
1657:
1658: /*最終行の時はキーブレーク*/
1659: if(frk->eof == 1) return(1);
1660:
1661: switch(frk->optKey->diffSame){
1662:
1663: /*k=#allDiff#の場合はキーブレーク*/
1664: case 1:
1665: return(1);
1666:
1667: /*k=#allSame#の場合はnotキーブレーク*/
1668: case 2:
1669: return(0);
1670:
1671: default:
1672: for(i=0; i<frk->optKey->flds->cnt; i++){
1673: fn=MssFlds2num(frk->optKey->flds,i);
1674: if( 0 != strcmp(*(frk->frPnt+(frk->recPnt-1)*frk->fldCnt+fn) ,
1675: *(frk->frPnt+(frk->recPnt )*frk->fldCnt+fn)) )
1676: return(1);
1677: }
1678:
1679: /*上記の条件をクリアしたということはキーブレークでない*/
1680: return(0);
1681: }
1682: }
1683:
1684: /**
1685: * # FUNCTION #
1686: * mssFldRecKey構造体のfrPntバッファにおける,recNo番目のレコードを書き出す。
1687: */
1688: static void writeRecFRK(struct mssFldRecKey *frk,int recNo)
1689: {
1690: int j;
1691:
1692: for(j=0; j<frk->fldCnt; j++){
1693: mssWriteStr(*(frk->frPnt+frk->fldCnt*recNo+j),frk->fpw);
1694: if(frk->fldCnt-1 == j) mssWriteRet(frk->fpw);
1695: else mssWriteDlm(frk->fpw);
1696: }
1697: }
1698:
1699: /**
1700: * # FUNCTION #
1701: * mssFldRecKey構造体に指定のキー項目が同じ値の行を全て読み込む
1702: * ファイルバッファがFULLになれば、一時ファイルに書き出す。
1703: * よって、一時ファイルを利用するかどうかは、openFPRで指定したqueサイズに依存。
1704: * 読み込まれたデータへは、mssReadFldRecFRKにてアクセスできる。
1705: * EOFを読み込んだときは、EOFを返す。
1706: *
1707: * frPntへのデータの蓄積について
1708: * 例えば "a b c","x y z"の2行のデータを読み込んだ場合、
1709: * *(frPnt+0)="a",*(frPnt+1)="b",*(frPnt+2)="c",*(frPnt+3)="x",*(frPnt+4)="y",*(frPnt+5)="z"
1710: * となる。
1711: * この関数では同じキーの値を持つ行を全て読み込むため、行数の上限は事前に
1712: * わからない。そこで、realloc関数にて動的に領域を確保する。
1713: * frk->alcRecCntに現在alloc関数で確保した行数を記録している。
1714: * alcRecCntは、この関数の呼び出し毎にクリアされることはない。
1715: */
1716: int mssReadFRK(struct mssFPR *fp, struct mssFldRecKey *frk)
1717: {
1718: int i;
1719:
1720: if(frk->eof) return(EOF);
1721:
1722: /*初期化*/
1723: frk->keyRecCnt=0;
1724: frk->byFile=0;
1725: frk->curRecNo=0;
1726: mssCloseFPR(frk->fpr);
1727: frk->fpr=NULL;
1728: mssFreeFldRec(frk->fr);
1729:
1730: /*前回の最終レコードをfrPntの先頭にコピーする。*/
1731: if(!frk->firstRead){
1732: for(i=0; i<frk->fldCnt; i++){
1733: *(frk->frPnt+i)=*(frk->frPnt+frk->fldCnt*frk->recPnt+i);
1734: }
1735: frk->keyRecCnt=1;
1736:
1737: /*読み込み位置はfrPnt+1から*/
1738: frk->recPnt=1;
1739: }
1740:
1741: while(1){
1742:
1743: /*データの読み込み*/
1744: if(needFileRead(fp)){
1745: /*データバッファがfull(-1)であればファイル書き出し*/
1746: if(-1==readFPRfile(fp)){
1747: /*初回のwrite時にファイルオープン*/
1748: if(!frk->byFile) {
1749: frk->fpw=mssOpenFPW(frk->fName,0,0);
1750: }
1751:
1752: /*frPntの内容を最終行を除いて一時ファイルにwrite*/
1753: for(i=0; i<frk->recPnt-1; i++){
1754: writeRecFRK(frk, i);
1755: }
1756:
1757: /*frPnt最終行はfrPnt先頭行にコピー(keyBreakのため)*/
1758: for(i=0; i<frk->fldCnt; i++){
1759: *(frk->frPnt+i)=*(frk->frPnt+frk->fldCnt*(frk->recPnt-1)+i);
1760: }
1761: fp->deq = PrevQue(fp->enq,fp->queCnt);
1762: frk->byFile=1;
1763: fp->full=0;
1764: frk->recPnt=1; /*次の読み込みはfrPntの2行目から*/
1765: continue;
1766: }
1767: }
1768:
1769: /*eofの検知*/
1770: if(isEOF(fp)){
1771: frk->eof=1;
1772: if(frk->firstRead) return(EOF); /*NULL データの場合*/
1773: }else{
1774: /*スペースをdelimitorとしてトークン分割*/
1775: if(frk->alcRecCnt<=frk->recPnt){
1776: frk->frPnt=mssRealloc(frk->frPnt,
1777: sizeof(char *)*(frk->recPnt+1)*frk->fldCnt,
1778: "readFRK");
1779: frk->alcRecCnt++;
1780: }
1781: fp->curPnt=strToken(frk->frPnt+frk->recPnt*frk->fldCnt, frk->fldCnt,
1782: &fp->chrCnt,fp);
1783: fp->recCnt++;
1784: }
1785:
1786: if(keyBreakFRK(frk)){
1787: if(frk->byFile){
1788: for(i=0; i<frk->recPnt; i++){
1789: writeRecFRK(frk, i);
1790: }
1791: mssCloseFPW(frk->fpw);
1792: frk->fpr=mssOpenFPR(frk->fName,4);
1793: frk->fr=mssInitFldRec(frk->fldCnt);
1794: }
1795:
1796: fp->deq = PrevQue(fp->enq,fp->queCnt);
1797: frk->keyNo++; /*キーの通し番号をカウントアップ*/
1798: frk->curRecNo=0;
1799: return(1);
1800: }
1801:
1802: /*frk->frPntの読み込み行位置をカウントアップ*/
1803: frk->recPnt++;
1804:
1805: /*キー内のレコード数をカウントアップ*/
1806: frk->keyRecCnt++;
1807: }
1808: return(1);
1809: }
1810:
1811: /**
1812: * # FUNCTION #
1813: * mssFldRecKey構造体において、一行読み込みpntに各項目文字列をセットする。
1814: * 読み込むデータがなければEOFを返す。
1815: */
1816: int mssReadFldRecFRK(struct mssFldRecKey *frk){
1817: int i;
1818:
1819: if(frk->curRecNo>=frk->keyRecCnt)return(EOF);
1820:
1821: if(frk->byFile){
1822: if(EOF==mssReadFldRec(frk->fpr,frk->fr)){
1823: return(EOF);
1824: }else{
1825: for(i=0; i<frk->fldCnt; i++){
1826: *(frk->pnt+i)=*(frk->fr->pnt+i);
1827: }
1828: }
1829:
1830: }else{
1831: for(i=0; i<frk->fldCnt; i++){
1832: *(frk->pnt+i)=*(frk->frPnt+frk->curRecNo*frk->fldCnt+i);
1833: }
1834: }
1835: frk->curRecNo++;
1836: return(1);
1837: }
1838:
1839: /**
1840: * # FUNCTION #
1841: * mssFldRecKey構造体において、先頭にシークする
1842: */
1843: void mssSeekTopFRK(struct mssFldRecKey *frk)
1844: {
1845: frk->curRecNo=0;
1846: if(frk->byFile){
1847: mssCloseFPR(frk->fpr);
1848: frk->fpr=mssOpenFPR(frk->fName,4);
1849: mssFreeFldRec(frk->fr);
1850: frk->fr=mssInitFldRec(frk->fldCnt);
1851: }
1852: }
1853:
1854: /**
1855: * # FUNCTION #
1856: * データの先頭行を読み込み、項目数を返す。EOFを読み込んだときはEOFを返す。
1857: * データの読み込みをおこなうがfp->curを動かさない
1858: * よってこの関数の次にmssReadFldRecなどで読みこめば、もう一度トップ行から
1859: * 読みこまれることになる
1860: * fpのバッファはいっさい変更しない。
1861: * そのかわり、新にメモリをmallocで確保し、そこへのポインタをrec構造体
1862: * にセットする。
1863: */
1864: int mssGetFldCntOnData(struct mssFPR *fp)
1865: {
1866: char *start;
1867: int spcCnt;
1868: register int i; /*高速化のためにregister変数を利用*/
1869:
1870: /*現在位置がバッファ最後のMssRecordMaxLen文字内にかかっていたらファイル読み込み*/
1871: if(needFileRead(fp)){
1872: readFPRfile(fp);
1873: /*行単位の読み込みの場合は常にdeqはenqの1つ前*/
1874: fp->deq=PrevQue(fp->enq,fp->queCnt);
1875: }
1876:
1877: /*eofの検知*/
1878: if(isEOF(fp)) return(EOF);
1879:
1880: start=fp->curPnt; /*fp->curは動かせないので*/
1881: spcCnt=0;
1882: i=1;
1883: while( *start != '\n' ){
1884: if(*start==MssFieldDelim) spcCnt++;
1885: start++; i++;
1886: if(i>=MssRecordMaxLen){
1887: mssShowErrMsg("exceed %d characters per record\n",MssRecordMaxLen);
1888: mssEnd(mssErrorNoDefault);
1889: }
1890: }
1891:
1892: return(++spcCnt); /*スペースの数+1が項目数*/
1893: }
1894:
1895: /**
1896: * # FUNCTION #
1897: * 先頭行にシークする(ファイルの先頭ではない)。
1898: * 標準入力に対しては、この関数を利用するとエラーとなる。
1899: * ただし、mssReopenFPRsort関数の利用後であれば利用可能。
1900: */
1901: void mssSeekTopFPR(struct mssFPR *fp)
1902: {
1903:
1904: if(0==fp->fName && !fp->sort){
1905: mssShowErrMsg("can not seek on stdin");
1906: mssEnd(mssErrorNoDefault);
1907: }
1908: fp->curPnt = 0;
1909:
1910: /*エンキュー、デキューポインタの初期化*/
1911: /*enq==deq then 空, deq-1=enq then full*/
1912: fp->deq =0;
1913: fp->enq =0;
1914: fp->full=0;
1915: fp->last=0;
1916:
1917: fp->recCnt = 0;
1918: fp->chrCnt = 0;
1919:
1920: /*カレントポインターのセット*/
1921: fp->curPnt=fp->buf+fp->queSize*fp->queCnt+MssRecordMaxLen;
1922:
1923: if(fp->sort){
1924: fp->readPnt=fp->curPnt;
1925: setFirstLineTT(fp->sd, fp->sd->iStart,fp->sd->iEnd);
1926: }else{
1927: gzseek(fp->zfd, 0, 0);
1928: mssSkipToBody(fp);
1929: }
1930: }
1931:
1932: /**
1933: * # SECTION #
1934: * ----------------------------------------------------------------------------
1935: * ファイルオープンクローズ関連
1936: * ----------------------------------------------------------------------------
1937: * MUSASHIでは、XMLtableの扱いに関して、以下の3つの機能を実現している。
1938: * 1. 大量データを高速に扱うためのリングバッファの実装
1939: * 2. 圧縮ファイルの自動解凍(この機能により、圧縮ファイルであっても、
1940: * 通常ファイルと同様の扱いが可能となる。)
1941: * 3. キーブレーク処理やファイル間のマッチング処理のために、あるキー項目
1942: * による並べ換えを裏で時動的に実行する。
1943: * これらの処理は全て、各種open関数で初期化もしくは実行される。
1944: * mssOpenFPR、mssOloseFPRは、1,2の機能を実装しており、mssReopenFPRsortは3の
1945: * 機能を担う。
1946: *
1947: * さらに、MUSASHIでは、mssOpenFPU関数で更新ファイルの扱いもサポートしている。
1948: */
1949:
1950: /**
1951: * # FUNCTION #
1952: * ファイルのオープンエラーの表示および停止。
1953: */
1954: static void fileOpenErr(char *fName)
1955: {
1956: mssShowErrMsg("file open error :\"%s\"",fName);
1957: mssEnd(mssErrorNoDefault);
1958: }
1959:
1960: /**
1961: * # FUNCTION #
1962: * 読み込みオープン
1963: * ファイル名(fileName)がNULLならば、標準入力のオープンとなる。
1964: * queCnt: リングバッファにおけるキューの数
1965: * キューのサイズは、ReadCnt(default:4)*PipeSize(default:4096)で決まる。
1966: * すなわち、デフォルトでは16K*queCntバイトのバッファとなる。
1967: * queCntは2の巾乗でなければならない,ex. 2,4,8,16...
1968: * queCntを4と設定すれば、デフォルトで16K*4=64Kバイトのデータをバッファ
1969: * を確保することになる。
1970: */
1971: struct mssFPR *mssOpenFPR(char *fileName,int queCnt)
1972: {
1973: struct mssFPR *fp;
1974:
1975: fp=mssMalloc(sizeof(struct mssFPR), "openFPR");
1976:
1977: /*gzopen*/
1978: if(fileName == NULL){
1979: fp->zfd=gzdopen(0,"rb"); /*stdin*/
1980: }else{
1981: fp->zfd=gzopen(fileName,"rb");
1982: }
1983: if(fp->zfd == NULL) fileOpenErr(fileName);
1984:
1985: /*エンキュー、デキューポインタの初期化*/
1986: fp->sort=0;
1987: fp->deq =0;
1988: fp->enq =0;
1989: fp->full=0;
1990: fp->last=0;
1991: fp->queCnt =queCnt;
1992: fp->queSize=ReadCnt*PipeSize;
1993: if(fileName==NULL){
1994: fp->fName=mssMalloc(sizeof(char)*10,"openFPR");
1995: strcpy(fp->fName,"stdin");
1996: }else{
1997: fp->fName=mssMalloc(sizeof(char)*(strlen(fileName)+1),"openFPR");
1998: strcpy(fp->fName,fileName);
1999: }
2000:
2001: /*バッファ領域の確保*/
2002: fp->buf=mssMalloc(sizeof(char)*fp->queSize*fp->queCnt+MssRecordMaxLen, "openFPR");
2003:
2004: /*カレントポインタをバッファの最後+1にもっていく(初回のreadFileのため)*/
2005: fp->curPnt=fp->buf+fp->queSize*fp->queCnt+MssRecordMaxLen;
2006:
2007: fp->readPnt=NULL;
2008: fp->sd =NULL;
2009: fp->zflg =1;
2010:
2011: fp->recCnt=0;
2012: fp->chrCnt=0;
2013: return(fp);
2014: }
2015:
2016: /**
2017: * # FUNCTION #
2018: * データをソートしてファイル読み込み再オープン
2019: * 通常ファイルとしてオープンしたinFileのデータを、指定のソート項目fldsで
2020: * 内部的にソーティングし、読み込みファイルとして再オープンする。
2021: * この関数を呼び出した後は、通常のmssOpenFPRでオープンしたと同様に扱うことが
2022: * 可能。
2023: * 引数fldCntには、データの全項目数を指定する。
2024: * queCnt: 新たに再オープンされるリングバッファにおけるキューの数
2025: * キューのサイズは、ReadCnt(default:4)*PipeSize(default:4096)で決まる。
2026: * すなわち、デフォルトでは16K*queCntバイトのバッファとなる。
2027: * queCntは2の巾乗でなければならない,ex. 2,4,8,16...
2028: * queCntを4と設定すれば、デフォルトで16K*4=64Kバイトのデータをバッファ
2029: * を確保することになる。
2030: */
2031: struct mssFPR *mssReopenFPRsort(
2032: struct mssFPR *inFile,
2033: int queCnt,
2034: struct mssFields *flds, /*ソート項目*/
2035: int fldCnt, /*項目数*/
2036: char *tmpPath) /*ワークファイルパス名*/
2037: { /*ワークファイルパス名*/
2038:
2039: struct mssFPR *fp;
2040:
2041: /*エンキュー、デキューポインタの初期化(mssOpenFPRと同じことをする)*/
2042: fp=mssMalloc(sizeof(struct mssFPR), "openFPR");
2043: fp->recCnt=0;
2044: fp->chrCnt=0;
2045: fp->deq =0;
2046: fp->enq =0;
2047: fp->full=0;
2048: fp->last=0;
2049: fp->queCnt =queCnt;
2050: fp->queSize=ReadCnt*PipeSize; /*FPRのqueSizeと同じにしておく*/
2051:
2052: fp->fName=mssMalloc(sizeof(char)*(strlen(inFile->fName)+1),"reopenFPRsort");
2053: strcpy(fp->fName,inFile->fName);
2054:
2055: /*バッファ領域の確保*/
2056: fp->buf=mssMalloc(sizeof(char)*fp->queSize*fp->queCnt+MssRecordMaxLen*2,"initDAT");
2057:
2058: /*カレントポインタをバッファの最後+1にもっていく(初回のreadFileのため)*/
2059: fp->curPnt =fp->buf+fp->queSize*fp->queCnt+MssRecordMaxLen;
2060:
2061: /*--------------------------- 以下のパートはmssOpenFPRにない*/
2062: /*読み込みポインタのセット*/
2063: fp->readPnt=fp->curPnt;
2064:
2065: /*ソートデータ構造の初期化*/
2066: fp->sd=initSD(flds,fldCnt,tmpPath);
2067: /*preSortの実行*/
2068: preSort(fp->sd,inFile);
2069:
2070: /*preSort以降は、readFPRfileでこのフラグによって、*/
2071: /*tnTreeから読み込むことになる*/
2072: fp->sort=1;
2073:
2074: /*元の入力ファイルを閉じる*/
2075:
2076: mssCloseFPR(inFile);
2077:
2078: return(fp);
2079: }
2080:
2081: /**
2082: * # FUNCTION #
2083: * 読み込みファイルクローズ
2084: */
2085: void mssCloseFPR(struct mssFPR *fp)
2086: {
2087:
2088: if(fp==NULL)return;
2089:
2090: if(fp->sort){
2091: endPreSort(fp->sd);
2092: freeSD(fp->sd);
2093: /*close(fp->fd);*/
2094: }else{
2095: gzclose(fp->zfd);
2096: }
2097: mssFree(fp->fName);
2098: mssFree(fp->buf);
2099: mssFree(fp);
2100: }
2101:
2102: /**
2103: * # FUNCTION #
2104: * 更新ファイルオープン
2105: * 標準入力および圧縮ファイルは更新ファイルとしてオープンできない。
2106: * queCnt: リングバッファにおけるキューの数
2107: * キューのサイズは、ReadCnt(default:4)*PipeSize(default:4096)で決まる。
2108: * すなわち、デフォルトでは16K*queCntバイトのバッファとなる。
2109: * queCntは2の巾乗でなければならない,ex. 2,4,8,16...
2110: * queCntを4と設定すれば、デフォルトで16K*4=64Kバイトのデータをバッファ
2111: * を確保することになる。
2112: */
2113: struct mssFPR *mssOpenFPU(char *fileName, int queCnt)
2114: {
2115: struct mssFPR *fp;
2116:
2117: fp=mssMalloc(sizeof(struct mssFPR), "openFPR");
2118:
2119: if(fileName == NULL){
2120: mssShowErrMsg("cannot open stdin as update file"); /*stdin*/
2121: mssEnd(mssErrorNoDefault);
2122: }else{
2123: fp->fp=fopen(fileName,"rb+");
2124: }
2125: if(fp->fp == NULL) fileOpenErr(fileName);
2126:
2127: /*エンキュー、デキューポインタの初期化*/
2128: fp->sort=0;
2129: fp->deq =0;
2130: fp->enq =0;
2131: fp->full=0;
2132: fp->last=0;
2133: fp->queCnt =queCnt;
2134: fp->queSize=ReadCnt*PipeSize;
2135: if(fileName==NULL){
2136: fp->fName=mssMalloc(sizeof(char)*10,"openFPU");
2137: strcpy(fp->fName,"stdin");
2138: }else{
2139: fp->fName=mssMalloc(sizeof(char)*(strlen(fileName)+1),"openFPU");
2140: strcpy(fp->fName,fileName);
2141: }
2142:
2143: /*バッファ領域の確保*/
2144: fp->buf=mssMalloc(sizeof(char)*fp->queSize*fp->queCnt+MssRecordMaxLen, "openFPU");
2145:
2146: /*カレントポインタをバッファの最後+1にもっていく(初回のreadFileのため)*/
2147: fp->curPnt=fp->buf+fp->queSize*fp->queCnt+MssRecordMaxLen;
2148:
2149: fp->readPnt=NULL;
2150: fp->sd =NULL;
2151: fp->zflg =0;
2152:
2153: fp->recCnt=0;
2154: fp->chrCnt=0;
2155: return(fp);
2156: }
2157:
2158: /**
2159: * # FUNCTION #
2160: * 更新ファイルクローズ
2161: */
2162: void mssCloseFPU(struct mssFPR *fp)
2163: {
2164:
2165: fclose(fp->fp);
2166: mssFree(fp->fName);
2167: mssFree(fp->buf);
2168: mssFree(fp);
2169: }
2170:
2171:
2172: