home *** CD-ROM | disk | FTP | other *** search
- /* CSORT - Tal - Rework from Jsort code of 1985 by Tal
-
- This is your classic sort-merge.
-
- Sorting
-
- Step 1. Read input file for as many records as will fit into memory
- Step 2. Sort records in memory
- Step 3. Write sorted records to unique disk file
- Step 4. Repeat to step 1 until all data read and sorted
- Step 5. If only 1 unique sorted disk file then stop
-
- Merging
-
- Step 6. Open as many unique sorted disk files until all opened or
- no file handles left.
- Step 7. Select lowest record from each disk file
- Step 8. Write lowest record to unique disk file
- Step 9. Read next record from particular disk file or eof
- Step 10. Repeat to step 7 till all open input files have been read
- Step 11. Delete unique input files
- Step 12. If more than one new unique merged file exists then
- Repeat to step 6
-
-
- Latest Edits: Fall '92
-
- */
-
-
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- #include <io.h>
- #include <memincs.h>
-
- #include <str.h>
-
- #define LIM_HANDLES 16 /* max number of files handles to try opening */
- #define MAX_REC_LEN 1024 /* max length of a record */
- #define MAX_FIELDS 16 /* max number of key fields */
-
- #define TRUE 1
- #define FALSE 0
-
- #define safekill(f) unlink(f)
-
- #define MIN(A,B) ( (A) < (B) ? (A) : (B) )
- #define MAX(A,B) ( (A) > (B) ? (A) : (B) )
-
-
- #include <csort.h>
-
- struct SORT_REC_S
- {
- long lCur;
- long lMax; /* tracking for work files during merging */
- };
-
- typedef struct SORT_REC_S SORT_REC_T;
- typedef SORT_REC_T * SORT_REC_P;
-
-
- struct KDATA_S
- { /* data itself */
- char *pcPtr; /* original record */
- char *key; /* sort key */
- long rec; /* original record number */
- };
-
- typedef struct KDATA_S KDATA_T;
-
-
- struct SORT_WKA_S
- {
- /* following are dynamically allocated during runtime */
- char * *pcPtr;
- char * *pcKey;
- KDATA_T * * pstKdata;
- long lMaxMemRecs;
- int iMaxHandles;
- int iSortBlocks;
- int iSortErr;
- int iWorkRecLen;
- };
-
- typedef struct SORT_WKA_S SORT_WKA_T;
- typedef SORT_WKA_T * SORT_WKA_P;
-
- unsigned iKeyLen; /* so main and other functions can see it */
-
- void StrAnd(char * n);
-
- void MakeTempFileName(char * pcFileName,int iSortBlocks);
- int SortFile(SORT_PARMS_P pSortParms);
- int SortOpenFile(SORT_WKA_P pSortWka, SORT_PARMS_P pSortParms, char * pcFile, FILE ** fp, long * plRecs);
- void ShellSort(KDATA_T * v[], long n, int iSize);
- int SortInit(SORT_WKA_P pSortWka, SORT_PARMS_P pSortParms);
- int SortLoadRec(SORT_WKA_P pSortWka,SORT_PARMS_P pSortParms,char * pcBuffer,int iNdx);
- int SortWriteRec(SORT_WKA_P pSortWka,SORT_PARMS_P pSortParms,FILE * fp,int iNdx,int iLast);
- int SortFilesIn(SORT_WKA_P pSortWka, SORT_PARMS_P pSortParms);
- int SortFindHandles(SORT_WKA_P pSortWka,SORT_PARMS_P pSortParms);
- int SortMerge(SORT_WKA_P pSortWka, SORT_PARMS_P pSortParms);
- int SortTerminate(SORT_WKA_P pSortWka,SORT_PARMS_P pSortParms);
- void MakeKey(char *result,char *szBuffer,KEY_FIELD_T *pstKeyField,int iFields);
-
-
- /*************************************************************************
- **
- ** M A I N
- **
- /*************************************************************************/
-
- #ifdef TEST
- main()
- {
- SORT_PARMS_T stSortParms;
-
- memset(&stSortParms,0,sizeof(SORT_PARMS_T));
-
- stSortParms.iSortType = SORT_TYPE_RECORD;
- stSortParms.iFileType = SORT_FILE_RELATIVE;
- strcpy(stSortParms.szSourceFile,"c:\\archive\\test.1");
- strcpy(stSortParms.szDestFile,"c:\\archive\\test.2");
- stSortParms.iRecLen = 8;
- stSortParms.lMemoryToUse = 512000;
- stSortParms.iNumSortFields = 8;
- stSortParms.pSortFields = calloc(8,sizeof(KEY_FIELD_T));
-
- stSortParms.pSortFields[0].iBeg = 7;
- stSortParms.pSortFields[0].iLen = 1;
- stSortParms.pSortFields[0].iOrder = SORT_DESCENDING;
-
- stSortParms.pSortFields[1].iBeg = 6;
- stSortParms.pSortFields[1].iLen = 1;
- stSortParms.pSortFields[1].iOrder = SORT_DESCENDING;
-
- stSortParms.pSortFields[2].iBeg = 5;
- stSortParms.pSortFields[2].iLen = 1;
- stSortParms.pSortFields[2].iOrder = SORT_DESCENDING;
-
- stSortParms.pSortFields[3].iBeg = 4;
- stSortParms.pSortFields[3].iLen = 1;
- stSortParms.pSortFields[3].iOrder = SORT_DESCENDING;
-
- stSortParms.pSortFields[4].iBeg = 3;
- stSortParms.pSortFields[4].iLen = 1;
- stSortParms.pSortFields[4].iOrder = SORT_DESCENDING;
-
- stSortParms.pSortFields[5].iBeg = 2;
- stSortParms.pSortFields[5].iLen = 1;
- stSortParms.pSortFields[5].iOrder = SORT_DESCENDING;
-
- stSortParms.pSortFields[6].iBeg = 1;
- stSortParms.pSortFields[6].iLen = 1;
- stSortParms.pSortFields[6].iOrder = SORT_DESCENDING;
-
- stSortParms.pSortFields[7].iBeg = 0;
- stSortParms.pSortFields[7].iLen = 1;
- stSortParms.pSortFields[7].iOrder = SORT_DESCENDING;
-
- SortFile(&stSortParms);
-
- return(0);
- }
- #endif
-
-
- /********************************************************************
- **
- ** SortFile, central sort function
- **
- *********************************************************************/
-
- int SortFile(SORT_PARMS_P pSortParms)
- {
- SORT_WKA_T stSortWka;
- SORT_WKA_P pSortWka;
-
- pSortWka = &stSortWka;
-
-
- /* calloc memory */
-
- SortInit(pSortWka,pSortParms);
-
-
- /* determine available file handles */
-
- SortFindHandles(pSortWka,pSortParms);
-
-
- /* sort/split input file */
-
- SortFilesIn(pSortWka,pSortParms);
-
-
- /* if files to merge then do so */
-
- if(pSortWka -> iSortBlocks > 1)
- SortMerge(pSortWka,pSortParms);
-
-
- /* clean up */
-
- SortTerminate(pSortWka,pSortParms);
-
-
- return(pSortWka -> iSortErr);
- }
-
-
-
-
- /*
- ** SortInit, setup memory
- */
-
- int SortInit(SORT_WKA_P pSortWka, SORT_PARMS_P pSortParms)
- {
-
- int iMemPerRec;
- int iCnt;
- void * pvTempPtr;
- long lCnt;
-
- pSortWka -> iSortErr = 0;
-
- iMemPerRec = sizeof(KDATA_T);
-
- /*
- ** Allocate Memory
- */
-
- /* Add up length of all keys */
-
- for(iCnt = 0, iKeyLen = 0; iCnt < pSortParms -> iNumSortFields; iCnt++)
- iKeyLen += pSortParms -> pSortFields[iCnt].iLen;
-
- /* malloc area for each */
-
- iMemPerRec = sizeof(KDATA_T) + iKeyLen;
-
- if(pSortParms -> iSortType == SORT_TYPE_RECORD)
- iMemPerRec += pSortParms -> iRecLen;
- else
- iMemPerRec += (int) sizeof(int);
-
- iMemPerRec += sizeof(char *); /* pcPtr */
- iMemPerRec += sizeof(char *); /* pcKey */
-
- pSortWka -> lMaxMemRecs = pSortParms -> lMemoryToUse / (long) iMemPerRec;
-
- /*
- ** determine if memory available
- */
-
- while((pvTempPtr = (void *) calloc(pSortWka -> lMaxMemRecs,iMemPerRec)) == NULL)
- pSortWka -> lMaxMemRecs--;
-
- /*
- ** free temp ptr used for inspecting memory
- */
-
- free(pvTempPtr);
-
- /* setup Kdata work structures */
-
- /* calloc array of pointers */
-
- pSortWka -> pstKdata = calloc(pSortWka -> lMaxMemRecs,sizeof(KDATA_T *));
-
- for(lCnt = 0; lCnt < pSortWka -> lMaxMemRecs; lCnt++)
- pSortWka -> pstKdata[lCnt] = (KDATA_T *) calloc(1,sizeof(KDATA_T));
-
-
- /* calloc array of char ptrs */
-
- pSortWka -> pcKey = (char **) calloc(pSortWka -> lMaxMemRecs,sizeof(char *));
-
- if(pSortParms -> iSortType == SORT_TYPE_RECORD)
- pSortWka -> pcPtr = (char **) calloc(pSortWka -> lMaxMemRecs,sizeof(char *));
-
-
- for(lCnt = 0; lCnt < pSortWka -> lMaxMemRecs; lCnt++)
- {
- pSortWka -> pcKey[lCnt] = (char *) malloc(iKeyLen + 1);
-
- if(pSortParms -> iSortType == SORT_TYPE_RECORD)
- pSortWka -> pcPtr[lCnt] = (char *) calloc(1,pSortParms -> iRecLen + 1);
- }
-
-
- /* malloc'ing the key and pcPtr pointers seperately so we can use qsort */
-
- for(lCnt = 0; lCnt < pSortWka -> lMaxMemRecs; lCnt++)
- {
- pSortWka -> pstKdata[lCnt] -> key = pSortWka -> pcKey[lCnt];
- if(pSortParms -> iSortType == SORT_TYPE_RECORD)
- pSortWka -> pstKdata[lCnt] -> pcPtr = pSortWka -> pcPtr[lCnt];
- }
-
- return(0);
- }
-
-
-
- int SortWriteRec(SORT_WKA_P pSortWka,SORT_PARMS_P pSortParms,FILE * fp,int iNdx,int iLast)
- {
- if(pSortParms -> iSortType == SORT_TYPE_RECORD)
- {
- /* full record sort, write out original string */
-
- if(pSortParms -> iFileType == SORT_FILE_RELATIVE)
- fwrite(pSortWka -> pstKdata[iNdx]->pcPtr,pSortWka -> iWorkRecLen,1,fp);
- else
- fprintf(fp,"%s",pSortWka -> pstKdata[iNdx]->pcPtr);
- }
- else
- {
- /* pointer sort, write only key and orig rec number */
-
- if(iLast)
- {
- /* if this is dest file */
-
- if(pSortParms -> iSortType == SORT_TYPE_RECORD)
- fwrite(&(pSortWka -> pstKdata[iNdx]->rec),sizeof(long),1,fp);
- else
- fprintf(fp,"%d\n",pSortWka -> pstKdata[iNdx]->rec);
- }
- else
- {
- if(pSortParms -> iSortType == SORT_TYPE_RECORD)
- {
- fwrite(&(pSortWka -> pstKdata[iNdx] -> rec),sizeof(long),1,fp);
- fwrite(pSortWka -> pstKdata[iNdx]->key,iKeyLen,1,fp);
- }
- else
- {
- fprintf(fp,"%d %s",pSortWka -> pstKdata[iNdx]->rec,pSortWka -> pstKdata[iNdx]->key);
- }
- }
- } /* if pSortParms -> iSortType == SORT_TYPE_RECORD */
-
- return(0);
- }
-
-
- /*
- ** SortFilesIn, break up input file
- */
-
- int SortFilesIn(SORT_WKA_P pSortWka, SORT_PARMS_P pSortParms)
- {
-
- long lSortRec;
- long lSortIn;
- char szFoutStr[64];
- FILE *fpOrigFile;
- FILE *fpOutFile;
- char szBuffer[MAX_REC_LEN]; /* max 1K record length */
- long lSortItems;
- int i;
- int iTemp;
-
- lSortItems = 0;
-
-
- pSortWka -> iSortBlocks = 0;
-
- lSortRec = 0;
-
- if(pSortParms -> iSortType == SORT_TYPE_RECORD) /* size of items written to work files */
- pSortWka -> iWorkRecLen = pSortParms -> iRecLen;
- else
- pSortWka -> iWorkRecLen = iKeyLen + sizeof(long);
-
-
- /*
- ** Open source file
- */
-
- SortOpenFile(pSortWka,pSortParms,pSortParms -> szSourceFile,&(fpOrigFile),&lSortItems);
-
-
- /*
- ** While processing the file
- */
-
- while(lSortRec < lSortItems)
- {
- lSortIn = 0;
-
- while((lSortIn < pSortWka -> lMaxMemRecs) && (lSortRec < lSortItems))
- {
- if(pSortParms -> iFileType == SORT_FILE_RELATIVE)
- iTemp = fread(szBuffer,1,pSortParms -> iRecLen,fpOrigFile); /* read into szBuffer */
- else
- {
- fgets(szBuffer,pSortParms -> iRecLen,fpOrigFile); /* read into szBuffer */
- iTemp = strlen(szBuffer) + 1;
- }
-
- if(pSortParms -> iSortType == SORT_TYPE_RECORD) /* only copy string if full record sort */
- memcpy(pSortWka -> pstKdata[lSortIn]->pcPtr,szBuffer,iTemp);
-
- pSortWka -> pstKdata[lSortIn]->rec = lSortRec; /* original record number */
-
- MakeKey(pSortWka -> pstKdata[lSortIn] -> key,
- szBuffer,
- pSortParms->pSortFields,
- pSortParms -> iNumSortFields);
-
- lSortIn++;
- lSortRec++;
- }
-
- /*
- ** Sort what is currently loaded into memory
- */
-
- ShellSort(pSortWka -> pstKdata,lSortIn,iKeyLen);
-
- /*
- ** Write merged block out to disk file for later merging
- */
-
- pSortWka -> iSortBlocks++;
-
- if( (pSortWka -> iSortBlocks == 1) && (lSortRec == lSortItems) )
- {
- /* it only took one pass to sort this file in memory,
- write the dest file now */
-
- strcpy(szFoutStr,pSortParms -> szDestFile);
- safekill(pSortParms -> szDestFile);
- }
- else
- {
- /* otherwise write merge file for next level */
-
- MakeTempFileName(szFoutStr,pSortWka -> iSortBlocks-1);
- }
-
-
- /* TAL - check if crlf or relative, will change fopen from "wb" to "w" */
-
- if(pSortParms -> iFileType == SORT_FILE_RELATIVE)
- fpOutFile = fopen(szFoutStr,"wb");
- else
- fpOutFile = fopen(szFoutStr,"w");
-
- if(fpOutFile == NULL)
- {
- pSortWka -> iSortErr = 8;
- goto done_work;
- }
-
- /* write sorted contents of memory to disk */
-
- for(i = 0; i < (int) lSortIn; i++)
- {
- SortWriteRec(pSortWka,
- pSortParms,
- fpOutFile,
- i,
- (pSortWka -> iSortBlocks == 1) && (lSortRec == lSortItems) );
-
- }
-
- fclose(fpOutFile);
-
- } /* while processing the file */
-
- fclose(fpOrigFile);
-
-
- /*
- ** Check if must merge files
- */
-
- pSortParms -> lRecsSorted = lSortItems; /* Returned var */
-
- done_work:
-
- return(pSortWka -> iSortErr);
- }
-
-
- /*
- ** SortFindHandles, find how many file handles are available to use
- */
-
- int SortFindHandles(SORT_WKA_P pSortWka,SORT_PARMS_P pSortParms)
- {
- int iGetting;
- int i;
- int iTemp;
- FILE *fpWorkFiles[LIM_HANDLES];
-
-
- /* Now that the original file has been sorted into iSortBlocks number
- of files to merge, see how many file handles are available and
- then start mergeing from level to level till we are done */
-
- pSortWka -> iMaxHandles=0; /* scan for max file handles */
-
- iGetting = TRUE; /* try and open as many file handles as possible */
-
-
- for(pSortWka -> iMaxHandles=0; iGetting; pSortWka -> iMaxHandles++)
- {
- if(pSortWka -> iMaxHandles <= pSortWka -> iSortBlocks)
- {
- /*
- ** open handles till we know we have enough to cover
- ** the sort blocks on disk for a simutaneous merge or
- ** until the system runs out which is denoted by a
- ** NULL file pointer
- **
- ** Efficieny of this merging from level to level is
- ** x^handles
- */
-
- if(pSortParms -> iFileType == SORT_FILE_RELATIVE)
- fpWorkFiles[pSortWka -> iMaxHandles] = fopen(pSortParms -> szDestFile,"wb");
- else
- fpWorkFiles[pSortWka -> iMaxHandles] = fopen(pSortParms -> szDestFile,"w");
-
- if(fpWorkFiles[pSortWka -> iMaxHandles] == NULL)
- {
- iGetting = FALSE; /* hit the end, ran out */
- break;
- }
- }
- else
- {
- iGetting = FALSE; /* have enough */
- }
- }
-
- /*
- ** Close all files
- */
-
- for(i=0; i < pSortWka -> iMaxHandles; i++)
- iTemp = fclose(fpWorkFiles[i]);
-
- return(pSortWka -> iSortErr);
- }
-
-
-
- /*
- ** SortOpenFile, open an input file
- */
-
- int SortOpenFile(SORT_WKA_P pSortWka, SORT_PARMS_P pSortParms, char * pcFile, FILE ** fp, long * plRecs)
- {
- char szBuffer[MAX_REC_LEN + 1];
-
-
- if(pSortParms -> iFileType == SORT_FILE_RELATIVE)
- {
- *fp = fopen(pcFile,"rb");
- *plRecs = (long) (filelength(fileno(*fp)) / pSortWka -> iWorkRecLen);
- }
- else
- {
- /*
- ** if merging text files, must count first
- */
-
- *fp = fopen(pcFile,"r");
-
- if(pSortParms -> lRecsInFile != 0)
- {
- *plRecs = pSortParms -> lRecsInFile;
- }
- else
- {
- *plRecs = 0;
-
- while(!feof(*fp))
- {
- fgets(szBuffer,MAX_REC_LEN,*fp);
- (*plRecs)++;
- }
-
- rewind(*fp);
- }
- }
-
- return(0);
- }
-
-
-
- /*
- ** SortLoadRec, load a record
- */
-
- int SortLoadRec(SORT_WKA_P pSortWka,SORT_PARMS_P pSortParms,char * pcBuffer,int iNdx)
- {
- long lTemp;
-
- if(pSortParms -> iSortType == SORT_TYPE_RECORD)
- {
-
- memcpy(pSortWka -> pstKdata[iNdx] -> pcPtr,pcBuffer,pSortWka -> iWorkRecLen);
-
- MakeKey(pSortWka -> pstKdata[iNdx] -> key,
- pSortWka -> pstKdata[iNdx] -> pcPtr,
- pSortParms -> pSortFields,
- pSortParms -> iNumSortFields);
- }
- else
- {
-
- memcpy(&lTemp,pcBuffer,sizeof(long));
-
- pSortWka -> pstKdata[iNdx] -> rec = lTemp;
-
- memcpy(pSortWka -> pstKdata[iNdx] -> key,pcBuffer+sizeof(long),iKeyLen);
- }
-
- return(0);
- }
-
-
- /*
- ** SortFindLowKey, find the lowest key in used buffers
- */
-
- int SortFindLowKey(SORT_WKA_P pSortWka,int iInBuffers,SORT_REC_P pSortRec,char * pcHighKey, int *piLow)
- {
- char szTempStr[MAX_REC_LEN + 1];
- int i;
-
-
- if(pSortRec[0].lCur <= pSortRec[0].lMax)
- {
- /* if we have them, then take them from stSortRec[0] */
-
- memcpy(szTempStr,pSortWka -> pstKdata[0]->key,iKeyLen);
-
- *piLow = 0;
- }
- else
- {
- /* otherwise use the pcHighKey */
-
- memcpy(szTempStr,pcHighKey,iKeyLen);
-
- *piLow = 0;
-
- for(i = 1; i < iInBuffers; i++)
- {
- if(pSortRec[i].lCur <= pSortRec[i].lMax)
- {
- *piLow = i;
- memcpy(szTempStr,pSortWka -> pstKdata[i] -> key,iKeyLen);
- }
- }
- }
-
- /* here szTempStr is the iLowest value string */
- /* the multiple iInBuffers work as a priority queue, the szBuffer with
- the iLowest value key has its data written out. If there is more
- data for that szBuffer/file it is loaded else iDoneBuffers++ */
-
- for(i = 1; i < iInBuffers; i++)
- {
- if((pSortRec[i].lCur <= pSortRec[i].lMax))
- {
- if(memcmp(pSortWka -> pstKdata[i] -> key,szTempStr,iKeyLen) < 0)
- {
- memcpy(szTempStr,pSortWka -> pstKdata[i] -> key,iKeyLen);
- *piLow = i;
- }
- }
- }
-
- return(0);
-
- }
-
-
-
-
- int SortMergeBuffers(SORT_WKA_P pSortWka,SORT_PARMS_P pSortParms,int iInBuffers,SORT_REC_P pSortRec, FILE * fpWorkFiles[],FILE * fpOutFile,char * pcHighKey)
- {
- int iMergeFiles = TRUE;
- int iDoneBuffers = 0;
- char szBuffer[MAX_REC_LEN + 1];
- int iLow;
-
- while(iMergeFiles)
- {
- /*
- ** Find & Remember the Lowest key in the merge buffers
- */
-
- SortFindLowKey(pSortWka,iInBuffers,pSortRec,pcHighKey,&iLow);
-
- /*
- ** Write out this iLowest record to next level merge file or
- ** directly into dest file if this is last merge
- */
-
- SortWriteRec(pSortWka,
- pSortParms,
- fpOutFile,
- iLow,
- ((pSortWka -> iSortBlocks-1) <= iInBuffers));
-
- /*
- ** Begin to reset for next pass on internal buffers
- */
-
- pSortRec[iLow].lCur++; /* pointer for this szBuffer */
-
- /*
- ** Determine if more records to load from file from which
- ** last record was written or if file is done
- */
-
- if(pSortRec[iLow].lCur <= pSortRec[iLow].lMax)
- {
- /* ^ if there are more records for this file read one in */
-
- if(pSortParms -> iFileType == SORT_FILE_RELATIVE)
- fread(szBuffer,1,pSortWka -> iWorkRecLen,fpWorkFiles[iLow]);
- else
- fgets(szBuffer,pSortWka -> iWorkRecLen,fpWorkFiles[iLow]);
-
- /*
- ** load into memory
- */
-
- SortLoadRec(pSortWka,pSortParms,szBuffer,iLow);
- }
- else
- iDoneBuffers++; /* no more records this file */
-
- /*
- ** Check if all data from merge files at this level are merged
- ** into output file
- */
-
- if(iDoneBuffers == iInBuffers)
- iMergeFiles = FALSE;
-
- } /* while iMergeFiles */
-
- return(0);
- }
-
-
-
- /*********************************************************************
- **
- ** Beginning Of Merging
- **
- *********************************************************************/
-
- int SortMerge(SORT_WKA_P pSortWka, SORT_PARMS_P pSortParms)
- {
- int iWorkBlock;
- int iLevelBlock;
- int iLevelBlocks;
- int iOldLevelBlocks;
- int iInBuffers;
- char szFoutStr[64];
- char szHighKey[64 + 1];
- char szFworkStr[LIM_HANDLES-1][64];
- FILE *fpWorkFiles[LIM_HANDLES];
- char szBuffer[MAX_REC_LEN]; /* max 1K record length */
- int iMerging;
- int i;
- FILE * fpOutFile;
- SORT_REC_T stSortRec[LIM_HANDLES-1];
-
-
-
- iLevelBlocks = pSortWka -> iSortBlocks;
- iWorkBlock = 1;
- iLevelBlock = 1;
-
-
- iInBuffers = MIN(pSortWka -> iMaxHandles-1,pSortWka -> iSortBlocks);
-
- iMerging = TRUE;
-
- while(iMerging)
- {
- /*
- ** Calculate current status of merging
- ** Determine if merging is completed
- */
-
- if(iLevelBlock > iLevelBlocks)
- {
- iOldLevelBlocks = iLevelBlocks;
- iLevelBlocks = pSortWka -> iSortBlocks - iLevelBlocks;
- iLevelBlock = 1;
-
- if(iOldLevelBlocks < pSortWka -> iMaxHandles)
- {
- /* there were 2 blocks on the last level which are
- now one block, so we must be all done */
-
- iMerging = FALSE;
- goto done_work;
- }
- }
-
- /*
- ** Calculate how many files to merge
- */
-
- iInBuffers = MIN(pSortWka -> iMaxHandles-1,iLevelBlocks);
- iInBuffers = MIN(iInBuffers,iLevelBlocks-iLevelBlock+1);
-
- for(i = 0; i < iInBuffers; i++)
- MakeTempFileName(szFworkStr[i],i + iWorkBlock -1);
-
- pSortWka -> iSortBlocks++;
-
- if(iLevelBlocks <= iInBuffers)
- {
- /*
- ** this is last pass, go straight into dest file
- */
-
- strcpy(szFoutStr,pSortParms -> szDestFile);
-
- safekill(pSortParms -> szDestFile);
- }
- else
- {
- MakeTempFileName(szFoutStr,pSortWka -> iSortBlocks -1);
- }
-
-
- /*
- ** open target file
- */
-
- if(pSortParms -> iFileType == SORT_FILE_RELATIVE)
- fpOutFile = fopen(szFoutStr,"wb");
- else
- fpOutFile = fopen(szFoutStr,"w");
-
- #ifdef DEBUG
- printf("Writing to merge file %s\n\n", szFoutStr);
- #endif
-
- if(fpOutFile == NULL)
- {
- pSortWka -> iSortErr = 9; /* cant open enough files */
- goto done_work;
- }
-
- /*
- ** open all the incoming files
- */
-
- for(i = 0; i < iInBuffers; i++)
- {
- stSortRec[i].lCur = 1;
-
- #ifdef DEBUG
- printf("Opening merge file %s\n", szFworkStr[i]);
- #endif
-
- /*
- ** For opening merge files, must reset lRecsInFile so
- ** forces count if crlf files
- */
-
- pSortParms -> lRecsInFile = 0;
-
- SortOpenFile(pSortWka,pSortParms,szFworkStr[i],&(fpWorkFiles[i]),&(stSortRec[i].lMax));
-
- /*
- ** initial read from files
- */
-
- if(pSortParms -> iFileType == SORT_FILE_RELATIVE)
- fread(szBuffer,1,pSortWka -> iWorkRecLen,fpWorkFiles[i]);
- else
- fgets(szBuffer,pSortWka -> iWorkRecLen,fpWorkFiles[i]);
-
- /*
- ** load into memory
- */
-
- SortLoadRec(pSortWka,pSortParms,szBuffer,i);
-
- } /* for */
-
-
- if(pSortParms -> pSortFields[0].iOrder == SORT_DESCENDING)
- {
- /* if first key is descending than the high key would be all 0's */
- memset(szHighKey,0,iKeyLen);
- }
- else
- {
- /* if ascending then 255's are high */
- memset(szHighKey,255,iKeyLen);
- }
-
-
- /*************************
- ** Main Merging Process
- **************************/
-
- SortMergeBuffers(pSortWka,pSortParms,iInBuffers,stSortRec,fpWorkFiles,fpOutFile,szHighKey);
-
- /*
- ** Remove Source Files from this merge level
- */
-
- for(i = 0; i < iInBuffers; i++)
- {
- /* get rid of last merge files */
-
- fclose(fpWorkFiles[i]);
- safekill(szFworkStr[i]);
- }
-
- fclose(fpOutFile);
-
- /*
- ** The total number of iWorkBlocks is increased by the
- ** number of input merge files just processed
- */
-
- iWorkBlock += iInBuffers;
- iLevelBlock += iInBuffers;
-
-
- } /* while iMerging */
-
- done_work:
-
- return(pSortWka -> iSortErr);
- }
-
-
-
-
- int SortTerminate(SORT_WKA_P pSortWka,SORT_PARMS_P pSortParms)
- {
- long lCnt;
-
- /*
- ** Sort/Merge Completed, clean up
- */
-
- for(lCnt = 0; lCnt < pSortWka -> lMaxMemRecs; lCnt++) /* was to iMaxHandles?? Oct 92 Tal */
- {
- free(pSortWka -> pstKdata[lCnt]->key);
-
- if(pSortParms -> iSortType == SORT_TYPE_RECORD)
- free(pSortWka -> pstKdata[lCnt] -> pcPtr); /* de-allocate in reverse, like PUSH POP / POP PUSH */
-
- free(pSortWka -> pstKdata[lCnt]);
- }
-
- free(pSortWka -> pstKdata);
- free(pSortWka -> pcKey);
- free(pSortWka -> pcPtr);
-
- return(pSortWka -> iSortErr);
- }
-
-
-
-
- void
- MakeKey(char *result,
- char *szBuffer,
- KEY_FIELD_T *pstKeyField,
- int iFields)
- {
- int i,offs;
- char szTempStr[1024];
-
- *result = '\0'; /* null it out */
- offs = 0;
-
- /* make the key */
- for(i = 0; i < iFields; i++, pstKeyField++)
- {
-
- /* copy this portion of string into key work area = szTempStr */
- StrMid(szTempStr,szBuffer,pstKeyField->iBeg,pstKeyField->iLen);
-
- if(pstKeyField->iOrder == SORT_DESCENDING) /* if descending sequence */
- StrAnd(szTempStr); /* and the string's bytes with 255 to reverse values */
-
- if(i == 0) /* if first, copy, otherwise concatenate it */
- memcpy(result,szTempStr,pstKeyField->iLen);
- else
- memcpy(result+offs,szTempStr,pstKeyField->iLen);
-
- offs += pstKeyField->iLen;
-
- }
- }
-
-
- void ShellSort(KDATA_T * v[], long n, int iSize)
- {
- int gap;
- int i;
- int j;
- int k;
- KDATA_T *iTemp;
-
- for(gap = (int) (n/2); gap > 0; gap /= 2)
- {
- for(i = gap; i < (int) n; i++)
- {
- for(j = i-gap; j >= 0; j -= gap)
- {
- if(memcmp(v[j]->key, v[j+gap]->key,iSize) <= 0) /* comparing szBuffers, so use memcmp not strcmp */
- break;
-
- k = j+gap;
- iTemp = v[j];
- v[j] = v[k];
- v[k] = iTemp;
- }
- }
- }
- }
-
- #if 0
- quick_sort1(v,n)
- char *v[];
- int n;
- {
- int i,l,r,p;
- int stack[50];
-
- l = 1;
- r = n;
- p = 2;
- do{
- if(r < l)
- {
- i = (l + r)/2;
- if((i-1) > (r-i)){
- stack[p] = l;
- stack[p+1] = i-1;
- l = i+1;
- } else {
- stack[p] = i+1;
- stack[p+1] = r;
- r = i-1;
- }
- p += 2;
- } else {
- p -= 2;
- l = stack[p];
- r = stack[p+1];
- }
- } while(p != 0);
- }
- #endif
-
-
- #if 0
- void itohex(hex_ret,h)
- char *hex_ret;
- unsigned h;
- {
- int hex_iTemp,i,h_ing,h_len;
- char hex_mas[17];
-
- hex_ret[0] = '\0';
- strcpy(hex_mas,"0123456789ABCDEF");
-
-
- h_ing = 1;
- while(h_ing){
- hex_iTemp = h & 0x0F;
-
- h_len = strlen(hex_ret);
- if(h_len > 0)
- for(i = h_len; i > 0; i--)
- hex_ret[i] = hex_ret[i-1];
-
- i = h_len+1;
- hex_ret[i] = '\0';
- /* ^ shift string down */
- hex_ret[0] = hex_mas[hex_iTemp];
- if(h == 0)
- h_ing = 0;
- h >>= 4; /* div 16 */
- if(h_ing && (h == 0))
- h_ing = 0;
- }
-
- }
- #endif
-
-
- void StrAnd(char * n)
- {
- int i;
-
- for(i = 0; n[i]; i++)
- n[i] = ((char) 255) - n[i];
- }
-
-
-
- #if 0
- void qsort1(rec,recs)
- char *rec[];
- unsigned recs;
- {
- int stackl[16],stackr[16];
- int s,l,r,i,j,xoffs,q;
- char *iTemp;
-
- s = 0;
- stackl[0] = 0;
- stackr[0] = recs-1;
- while(s >= 0){
- l = stackl[s];
- r = stackr[s];
- s--;
- qs10:
- i = l;
- j = r;
- xoffs = (l + r + 1) >> 1; /* / 2; */
- printf("xoffs = %d\n",xoffs);
- qs20:
- while(strcmp(rec[i],rec[xoffs]) < 0){
- i++;
- }
- while(strcmp(rec[xoffs],rec[j]) < 0){
- j--;
- }
- /* for( ; strcmp(rec[i],rec[xoffs]) != 0; i++); */
- /* for( ; strcmp(rec[xoffs],rec[j]) != 0; j--); */
- if(i > j)
- goto qs30;
-
- printf("swapping %s and %s \n",rec[i],rec[j]);
-
- iTemp = rec[i];
- rec[i] = rec[j];
- rec[j] = iTemp;
- i++;
- j--;
- /*
- for(q=0; q <= recs; q++)
- puts(rec[q]);
- */
- qs30:
- if(i <= j)
- goto qs20;
- if((j-l) >= (r-i))
- goto qs50;
- if(i >= r)
- goto qs40;
- s++;
- stackl[s] = i;
- stackr[s] = r;
- qs40:
- r = j;
- goto qs70;
- qs50:
- if(l >= j)
- goto qs60;
- s++;
- stackl[s] = l;
- stackl[s] = j;
- qs60:
- l = i;
- qs70:
- if(l < r)
- goto qs10;
- }
-
-
- }
-
- qcompare(k1,k2)
- KDATA_T *k1, *k2;
- {
- return(memcmp(k1->key,k2->key,iKeyLen));
- }
- #endif
-
-
- void MakeTempFileName(char * pcFileName,int iSortBlocks)
- {
- char szHexStr[5];
-
- strcpy(pcFileName,"CS");
- sprintf(szHexStr,"%x",iSortBlocks);
- strcat(pcFileName,szHexStr);
- }
-