MUSASHI C source: mssInput.c


グローバル関数
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


DEFINE,マクロ
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 mergeTTstruct 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=mssMallocMaxLineS * 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: