2025-04-27 07:49:33 -04:00

1047 lines
41 KiB
C++

/***************************************************************************/
/* SORT.CPP */
/* Copyright (C) 1995-97 SYWARE Inc., All rights reserved */
/***************************************************************************/
// Commenting #define out - causing compiler error - not sure if needed, compiles
// okay without it.
//#define WINVER 0x0400
#include "precomp.h"
#include "wbemidl.h"
#include <comdef.h>
//smart pointer
_COM_SMARTPTR_TYPEDEF(IWbemServices, IID_IWbemServices);
_COM_SMARTPTR_TYPEDEF(IEnumWbemClassObject, IID_IEnumWbemClassObject);
//_COM_SMARTPTR_TYPEDEF(IWbemContext, IID_IWbemContext );
_COM_SMARTPTR_TYPEDEF(IWbemLocator, IID_IWbemLocator);
#include "drdbdr.h"
/***************************************************************************/
#define SORT_MAX_FIELDS 20
typedef struct tagSORT_SECTION {
UWORD left;
UWORD right;
} SORT_SECTION, FAR * SORT_SECTIONS;
typedef struct tagSORT_KEY {
UWORD offset;
UWORD length;
UCHAR type;
BOOL descending;
} SORT_KEY;
typedef struct tagSORT_DATA {
UWORD dupKeyLen; /* Length of duplicate key (0 if no dup removal) */
UWORD dupKeyStart; /* Zero-based offset of duplicate key */
SORT_KEY key[SORT_MAX_FIELDS];
UWORD keyCount;
UWORD recordSize;
UDWORD recordStart;
UWORD recordCount;
UWORD bufferRecordCount;
LPSTR dataBuffer;
} SORT_DATA;
/***************************************************************************/
BOOL INTFUNC SortKeyCompare(SORT_DATA FAR *sortData, LPSTR leftRecordPtr,
LPSTR rightRecordPtr)
/* Is the key of the left greater than or equal the key of the right? */
{
SORT_KEY FAR *keyComponent;
UWORD idx;
LPSTR leftValuePtr;
LPSTR rightValuePtr;
int compare;
UWORD leftDecimalPos;
UWORD rightDecimalPos;
/* Compare each key component */
keyComponent = sortData->key;
for (idx = 0; idx < sortData->keyCount; idx++) {
/* Point at the values */
leftValuePtr = leftRecordPtr + keyComponent->offset;
rightValuePtr = rightRecordPtr + keyComponent->offset;
/* Compare the values */
switch (keyComponent->type) {
case 'E':
if ((*((double FAR *) leftValuePtr)) <
(*((double FAR *) rightValuePtr)))
compare = -1;
else if ((*((double FAR *) leftValuePtr)) >
(*((double FAR *) rightValuePtr)))
compare = 1;
else
compare = 0;
break;
case 'N':
if (*rightValuePtr != '-') {
if (*leftValuePtr != '-') {
for (leftDecimalPos = 0;
leftDecimalPos < keyComponent->length;
leftDecimalPos++) {
if ((*leftValuePtr == '.') || (*leftValuePtr == ' '))
break;
leftValuePtr++;
}
for (rightDecimalPos = 0;
rightDecimalPos < keyComponent->length;
rightDecimalPos++) {
if ((*rightValuePtr == '.') || (*rightValuePtr == ' '))
break;
rightValuePtr++;
}
if (leftDecimalPos > rightDecimalPos)
compare = 1;
else if (leftDecimalPos < rightDecimalPos)
compare = -1;
else {
leftValuePtr = leftRecordPtr + keyComponent->offset;
rightValuePtr = rightRecordPtr + keyComponent->offset;
compare = _fmemcmp(leftValuePtr, rightValuePtr,
keyComponent->length);
}
}
else {
compare = -1;
}
}
else {
if (*leftValuePtr != '-') {
compare = 1;
}
else {
for (leftDecimalPos = 0;
leftDecimalPos < keyComponent->length;
leftDecimalPos++) {
if ((*leftValuePtr == '.') || (*leftValuePtr == ' '))
break;
leftValuePtr++;
}
for (rightDecimalPos = 0;
rightDecimalPos < keyComponent->length;
rightDecimalPos++) {
if ((*rightValuePtr == '.') || (*rightValuePtr == ' '))
break;
rightValuePtr++;
}
if (leftDecimalPos > rightDecimalPos)
compare = 1;
else if (leftDecimalPos < rightDecimalPos)
compare = -1;
else {
leftValuePtr = leftRecordPtr + keyComponent->offset;
rightValuePtr = rightRecordPtr + keyComponent->offset;
compare = _fmemcmp(leftValuePtr, rightValuePtr,
keyComponent->length);
}
compare = -(compare);
}
}
break;
case 'C':
compare = _fmemcmp(leftValuePtr, rightValuePtr,
keyComponent->length);
break;
}
/* Adjust for ascending/descending */
if (keyComponent->descending)
compare = -compare;
/* Return result */
if (compare < 0)
return FALSE;
if (compare > 0)
return TRUE;
/* Look at next component */
keyComponent++;
}
return TRUE;
}
/***************************************************************************/
RETCODE INTFUNC SortInstructions(LPSTR lpszInstructions,
SORT_DATA FAR *sortData)
/* Parse the instruction string. The instruction string is in the form: */
/* */
/* instuction_string ::= item | item instruction_string */
/* */
/* item ::= sort_item | fix_item | workdrive_item | dupout_item */
/* */
/* sort_item ::= S(sort_list) */
/* */
/* sort_list ::= sort_list_item | sort_list_item,sort_list */
/* */
/* sort_list_item ::= offset,length,type,ascending_or_descending */
/* */
/* offset ::= << 1-based record offset of sort key component >> */
/* */
/* length ::= << length of sort key component >> */
/* */
/* type ::= type_double | type_number | type_character | type_binary */
/* */
/* type_double ::= E */
/* */
/* type_ascii_numeric ::= N */
/* */
/* type_character ::= C */
/* */
/* type_binary ::= W */
/* */
/* ascending_or_descending := ascending | descending */
/* */
/* ascending := A */
/* */
/* descending := D */
/* */
/* fix_item ::= F(FIX,recordsize) */
/* */
/* recordsize ::= << size of the records in the sort file in bytes >> */
/* */
/* workdrive_item ::= W(workdirive) */
/* */
/* workdrive ::= << pathname of directory to hold temporary files >> */
/* */
/* dupout_item ::= DUPO(Bdupout_buffer,dupout_offset,dupout_length) */
/* */
/* dupout_buffer ::= << size of buffer to use during duplicate removal >> */
/* */
/* dupout_offset ::= << 1-based record offset of duplicate removal key >> */
/* */
/* dupout_length ::= << length duplicate removal key >> */
/* */
/* Notes: (1) If the sort key item is ascii_numeric, it is a number */
/* represented as an ASCII string. All the numbers in the */
/* file must have the same number of digits to the right of */
/* the decimal point. If there are no digits to the right */
/* of the decimal point, the decimal point is not required, */
/* but if one record has a decimal point, they all have to */
/* have decimal points. */
/* */
/* (2) The workdrive is assumed to include a trailing backslash */
/* */
/* (3) The instruction string may not have embedded white space */
/* */
/* This parser assumes that the instruction string given adheres to the */
/* syntax above. If the instruction string given is malformed, the results */
/* are undefined. */
{
/* Get sorting instructions */
sortData->dupKeyLen = 0;
sortData->dupKeyStart = 0;
sortData->recordSize = 0;
sortData->keyCount = 0;
while (*lpszInstructions) {
/* Get the command */
switch (*lpszInstructions) {
case 'S':
/* Parse: S(offset,length,type,asc,offset,length,type,asc,...) */
lpszInstructions++; /* 'S' */
do {
if (sortData->keyCount >= SORT_MAX_FIELDS) {
return ERR_SORT;
}
lpszInstructions++; /* '(' or ',' */
sortData->key[sortData->keyCount].offset = 0;
do {
sortData->key[sortData->keyCount].offset *= (10);
sortData->key[sortData->keyCount].offset +=
(*lpszInstructions - '0');
lpszInstructions++; /* '0' .. '9' */
} while (*lpszInstructions != ',');
(sortData->key[sortData->keyCount].offset)--;
lpszInstructions++; /* ',' */
sortData->key[sortData->keyCount].length = 0;
do {
sortData->key[sortData->keyCount].length *= (10);
sortData->key[sortData->keyCount].length +=
(*lpszInstructions - '0');
lpszInstructions++; /* '0' .. '9' */
} while (*lpszInstructions != ',');
lpszInstructions++; /* ',' */
sortData->key[sortData->keyCount].type = *lpszInstructions;
if (sortData->key[sortData->keyCount].type == 'W')
sortData->key[sortData->keyCount].type = 'C';
lpszInstructions++; /* 'E', 'N', 'C', or 'W' */
lpszInstructions++; /* ',' */
if (*lpszInstructions == 'A')
sortData->key[sortData->keyCount].descending = FALSE;
else
sortData->key[sortData->keyCount].descending = TRUE;
lpszInstructions++; /* 'A' or 'D' */
(sortData->keyCount)++;
} while (*lpszInstructions != ')');
break;
case 'F':
/* Parse: F(FIX,recsize) */
do {
lpszInstructions++; /* "F(FIX" */
} while (*lpszInstructions != ',');
lpszInstructions++; /* ',' */
do {
sortData->recordSize *= (10);
sortData->recordSize += (*lpszInstructions - '0');
lpszInstructions++; /* '0' .. '9' */
} while (*lpszInstructions != ')');
break;
case 'W':
/* Parse: W(workdir) */
do {
lpszInstructions++; /* "W(workdir" */
} while (*lpszInstructions != ')');
break;
case 'D':
/* Parse: DUPO(Bbuffer,offset,length) */
do {
lpszInstructions++; /* "DUPO(Bbuffer" */
} while (*lpszInstructions != ',');
lpszInstructions++; /* ',' */
do {
sortData->dupKeyStart *= (10);
sortData->dupKeyStart += (*lpszInstructions - '0');
lpszInstructions++; /* '0' .. '9' */
} while (*lpszInstructions != ',');
(sortData->dupKeyStart)--;
lpszInstructions++; /* ',' */
do {
sortData->dupKeyLen *= (10);
sortData->dupKeyLen += (*lpszInstructions - '0');
lpszInstructions++; /* '0' .. '9' */
} while (*lpszInstructions != ')');
break;
default:
break;
}
lpszInstructions++;
}
sortData->recordStart = 0;
sortData->recordCount = 0;
sortData->bufferRecordCount = 0;
sortData->dataBuffer = NULL;
return ERR_SUCCESS;
}
/***************************************************************************/
BOOL INTFUNC QuickSortKeyCompare(SORT_DATA FAR *sortData, UWORD left,
UWORD right)
/* Is the key of the left greater than or equal the key of the right? */
{
LPSTR leftRecordPtr;
LPSTR rightRecordPtr;
/* Handle boundry conditions */
if (left == sortData->recordCount + 1)
return TRUE;
if (right == 0)
return TRUE;
if (left == 0)
return FALSE;
if (right == sortData->recordCount + 1)
return FALSE;
/* Point at the records */
leftRecordPtr = &(sortData->dataBuffer[left * sortData->recordSize]);
rightRecordPtr = &(sortData->dataBuffer[right * sortData->recordSize]);
/* Compare the keys */
return SortKeyCompare(sortData, leftRecordPtr, rightRecordPtr);
}
/***************************************************************************/
RETCODE INTFUNC SortFile(HFILE hfileIn, HFILE hfileOut,
SORT_DATA FAR *sortData)
/* Sort one bunch of records. A 'bunch' contains records n to (n + m), */
/* where n is specified by sortData->recordStart, m is specified by */
/* sortData->recordCount */
{
UWORD leftBound;
UWORD rightBound;
UWORD entryToPutInPosition;
LONG filesize;
HGLOBAL hSections;
SORT_SECTIONS sections;
UWORD sectionsCount;
/* Read records to sort */
if (_llseek(hfileIn, ((UDWORD) sortData->recordStart) *
((UDWORD) sortData->recordSize), 0) == HFILE_ERROR) {
return ERR_SORT;
}
filesize = sortData->recordCount * sortData->recordSize;
if (_lread(hfileIn, &(sortData->dataBuffer[sortData->recordSize]),
(UINT) filesize)
!= (UINT) filesize) {
return ERR_SORT;
}
/* Allocate space for list of sections to sort */
sectionsCount = 0;
hSections = GlobalAlloc(GMEM_MOVEABLE,
sizeof(SORT_SECTION) * sortData->bufferRecordCount);
if (hSections == NULL) {
return ERR_SORT;
}
sections = (SORT_SECTIONS) GlobalLock(hSections);
if (sections == NULL) {
GlobalFree(hSections);
return ERR_SORT;
}
/* Initialize list of sections to sort to contain the entire bunch */
/* provided */
sections[0].left = 1;
sections[0].right = sortData->recordCount;
if (sections[0].right > sections[0].left)
(sectionsCount)++;
/* While there are still sections of the buffer to sort... */
while (sectionsCount > 0) {
/* Remove the definition of this section off the list */
(sectionsCount)--;
/* (Q2) We are going to look for the ultimate location of the */
/* left-most element in the section. Call the left-most entry */
/* the "entry to put in position". Point the left and right */
/* bounds to everything except the entry to put in position. */
/* While we are looking for this ultimate location, we will swap */
/* records so that all the entries to the left of the ultimate */
/* location are less than or equal to the entry to put in position */
/* and all the entries to the right of the ultimate location are */
/* greater than or equal to the entry to put in position. */
entryToPutInPosition = sections[sectionsCount].left;
leftBound = sections[sectionsCount].left;
rightBound = sections[sectionsCount].right + 1;
while (TRUE) {
/* (Q3) Skip over entries on the left side that are less than */
/* the entry to put in position */
while (TRUE) {
leftBound++;
if (QuickSortKeyCompare(sortData, leftBound,
entryToPutInPosition))
break;
}
/* (Q4) Skip over entries on the right side that are greater */
/* than the entry to put in position */
while (TRUE) {
rightBound--;
if (QuickSortKeyCompare(sortData, entryToPutInPosition,
rightBound))
break;
}
/* (Q5) Leave this loop if we have found the ultimate location */
/* for the entry to put in position */
if (rightBound <= leftBound)
break;
/* (Q6) At this point, the entry at the right bound is less */
/* than or equal to the entry to put in position and the */
/* entry at the left bound is greater than or equal to the */
/* entry to put in position. Swap these two entries and keep */
/* looking for ultimate place for the entry to put in position */
_fmemcpy(sortData->dataBuffer,
&(sortData->dataBuffer[leftBound * sortData->recordSize]),
sortData->recordSize);
_fmemcpy(&(sortData->dataBuffer[leftBound * sortData->recordSize]),
&(sortData->dataBuffer[rightBound * sortData->recordSize]),
sortData->recordSize);
_fmemcpy(&(sortData->dataBuffer[rightBound * sortData->recordSize]),
sortData->dataBuffer,
sortData->recordSize);
}
/* (Q5) Put the entry to put in position into its ultimate location */
if (entryToPutInPosition != rightBound) {
_fmemcpy(sortData->dataBuffer,
&(sortData->dataBuffer[entryToPutInPosition * sortData->recordSize]),
sortData->recordSize);
_fmemcpy(&(sortData->dataBuffer[entryToPutInPosition * sortData->recordSize]),
&(sortData->dataBuffer[rightBound * sortData->recordSize]),
sortData->recordSize);
_fmemcpy(&(sortData->dataBuffer[rightBound * sortData->recordSize]),
sortData->dataBuffer,
sortData->recordSize);
}
/* (Q8) Put the right half of the section onto the list of sections */
/* to sort (it will sorted eventually) */
sections[sectionsCount].left = rightBound+1;
/* sections[sectionsCount].right is already set from before */
if (sections[sectionsCount].right > sections[sectionsCount].left)
(sectionsCount)++;
/* (Q7) Put the left half of the section onto the list of sections */
/* to sort (it will sorted next) */
sections[sectionsCount].left = entryToPutInPosition;
sections[sectionsCount].right = rightBound-1;
if (sections[sectionsCount].right > sections[sectionsCount].left)
(sectionsCount)++;
}
GlobalUnlock(hSections);
GlobalFree(hSections);
/* Write the sorted records to the file */
if (_llseek(hfileOut, ((UDWORD) sortData->recordStart) *
((UDWORD) sortData->recordSize), 0) == HFILE_ERROR) {
return ERR_SORT;
}
if (_lwrite(hfileOut, &(sortData->dataBuffer[sortData->recordSize]),
(UINT) filesize)
!= (UINT) filesize) {
return ERR_SORT;
}
return ERR_SUCCESS;
}
/***************************************************************************/
RETCODE INTFUNC MergeFile(HFILE hfile, SORT_DATA FAR *sortData,
UDWORD recordCount)
/* Merge the sorted bunches in the file. To do this, we merge the last */
/* bunch (the "Beta" records) with the second to last bunch (the "Alpha" */
/* records). We then merge the last two bunches (the "Beta" records) with */
/* the third to last bunch (the "Alpha" records), etc. until the entire */
/* file is merged. */
{
UDWORD bunchCount;
UWORD bunchSize;
UWORD lastBunchSize;
HGLOBAL hAlphaBuffer;
LPSTR alphaBuffer;
UDWORD currentAlphaBunch;
LPSTR alphaRecord;
UWORD alphaCounter;
HGLOBAL hBetaBuffer;
LPSTR betaBuffer;
UDWORD nextBetaBunch;
LPSTR betaRecord;
UWORD betaCounter;
UDWORD nextOutputBunch;
LPSTR outputRecord;
UWORD outputCounter;
/* Return if nothing to merge */
if ((UDWORD) sortData->bufferRecordCount == recordCount)
return ERR_SUCCESS;
/* Figure out how many bunches there are */
bunchCount = ((recordCount - 1) / sortData->bufferRecordCount) + 1;
/* Figure out the size of a bunch */
bunchSize = sortData->bufferRecordCount;
/* Figure out how big last bunch is */
lastBunchSize = (UWORD) (recordCount - ((bunchCount - 1) * bunchSize));
/* Get a buffer to read records. This buffer will be used for the */
/* "Alpha" records (th second to last bunch on the first iteration, */
/* the third to last bunch on the second iteration, etc.) */
hAlphaBuffer = GlobalAlloc(GMEM_MOVEABLE,
sortData->recordSize * bunchSize);
if (hAlphaBuffer == NULL) {
return ERR_SORT;
}
alphaBuffer = (LPSTR) GlobalLock(hAlphaBuffer);
if (alphaBuffer == NULL) {
GlobalFree(hAlphaBuffer);
return ERR_SORT;
}
/* Get another buffer to read records. This buffer will be used for */
/* the "Beta" records (the last bunch on the first iteration, the */
/* second to last and last bunch on the second iteration, etc.) */
hBetaBuffer = GlobalAlloc(GMEM_MOVEABLE, sortData->recordSize*bunchSize);
if (hBetaBuffer == NULL) {
GlobalUnlock(hAlphaBuffer);
GlobalFree(hAlphaBuffer);
return ERR_SORT;
}
betaBuffer = (LPSTR) GlobalLock(hBetaBuffer);
if (betaBuffer == NULL) {
GlobalFree(hBetaBuffer);
GlobalUnlock(hAlphaBuffer);
GlobalFree(hAlphaBuffer);
return ERR_SORT;
}
/* Point at the first alpha bunch */
currentAlphaBunch = bunchCount - 1;
/* Do the merge. */
do {
/* Read the next alpha bunch */
if (_llseek(hfile, ((UDWORD) (currentAlphaBunch - 1)) *
((UDWORD) (sortData->recordSize * bunchSize)),
0) == HFILE_ERROR) {
GlobalUnlock(hBetaBuffer);
GlobalFree(hBetaBuffer);
GlobalUnlock(hAlphaBuffer);
GlobalFree(hAlphaBuffer);
return ERR_SORT;
}
alphaRecord = alphaBuffer;
alphaCounter = bunchSize;
if (_lread(hfile, alphaBuffer,
(UINT) (sortData->recordSize * alphaCounter)) !=
(UINT) (sortData->recordSize * alphaCounter)) {
GlobalUnlock(hBetaBuffer);
GlobalFree(hBetaBuffer);
GlobalUnlock(hAlphaBuffer);
GlobalFree(hAlphaBuffer);
return ERR_SORT;
}
/* Point at the output buffer */
nextOutputBunch = currentAlphaBunch;
outputRecord = sortData->dataBuffer;
outputCounter = 0;
/* Merge the alpha records with the beta records */
nextBetaBunch = currentAlphaBunch + 1;
betaCounter = 0;
while (alphaCounter > 0) {
/* Do we need more beta records? */
if (betaCounter == 0) {
/* Yes. Leave loop if no more records. */
if (nextBetaBunch > bunchCount)
break;
/* Position to the next bunch of beta records */
if (_llseek(hfile, ((UDWORD) (nextBetaBunch - 1)) *
((UDWORD) (sortData->recordSize * bunchSize)),
0) == HFILE_ERROR) {
GlobalUnlock(hBetaBuffer);
GlobalFree(hBetaBuffer);
GlobalUnlock(hAlphaBuffer);
GlobalFree(hAlphaBuffer);
return ERR_SORT;
}
/* Read in the next bunch of beta records */
betaRecord = betaBuffer;
if (nextBetaBunch != bunchCount)
betaCounter = bunchSize;
else
betaCounter = lastBunchSize;
if (_lread(hfile, betaBuffer,
(UINT) (sortData->recordSize * betaCounter)) !=
(UINT) (sortData->recordSize * betaCounter)) {
GlobalUnlock(hBetaBuffer);
GlobalFree(hBetaBuffer);
GlobalUnlock(hAlphaBuffer);
GlobalFree(hAlphaBuffer);
return ERR_SORT;
}
nextBetaBunch++;
}
/* If the output buffer is full, write it out */
if (outputCounter == bunchSize) {
if (_llseek(hfile, ((UDWORD) (nextOutputBunch - 1)) *
((UDWORD) (sortData->recordSize * bunchSize)),
0) == HFILE_ERROR) {
GlobalUnlock(hBetaBuffer);
GlobalFree(hBetaBuffer);
GlobalUnlock(hAlphaBuffer);
GlobalFree(hAlphaBuffer);
return ERR_SORT;
}
if (_lwrite(hfile, sortData->dataBuffer,
(UINT) (sortData->recordSize * outputCounter)) !=
(UINT) (sortData->recordSize * outputCounter)) {
GlobalUnlock(hBetaBuffer);
GlobalFree(hBetaBuffer);
GlobalUnlock(hAlphaBuffer);
GlobalFree(hAlphaBuffer);
return ERR_SORT;
}
/* Point at next output buffer */
nextOutputBunch++;
outputRecord = sortData->dataBuffer;
outputCounter = 0;
}
/* Which record is next, the one in the alpha buffer or the */
/* one in the beta buffer */
if (SortKeyCompare(sortData, betaRecord, alphaRecord)) {
/* The one in the alpha buffer. Put it into output buffer */
_fmemcpy(outputRecord, alphaRecord, sortData->recordSize);
/* Point at next alpha record */
alphaCounter--;
alphaRecord += sortData->recordSize;
}
else {
/* The one in the beta buffer. Put it into output buffer */
_fmemcpy(outputRecord, betaRecord, sortData->recordSize);
/* Point at next beta record */
betaCounter--;
betaRecord += sortData->recordSize;
}
/* Point at next output record */
outputCounter++;
outputRecord += sortData->recordSize;
}
/* Write the remining records in the output buffer */
if (_llseek(hfile, ((UDWORD) (nextOutputBunch - 1)) *
((UDWORD) (sortData->recordSize * bunchSize)),
0) == HFILE_ERROR) {
GlobalUnlock(hBetaBuffer);
GlobalFree(hBetaBuffer);
GlobalUnlock(hAlphaBuffer);
GlobalFree(hAlphaBuffer);
return ERR_SORT;
}
if (outputCounter > 0) {
if (_lwrite(hfile, sortData->dataBuffer,
(UINT) (sortData->recordSize * outputCounter)) !=
(UINT) (sortData->recordSize * outputCounter)) {
GlobalUnlock(hBetaBuffer);
GlobalFree(hBetaBuffer);
GlobalUnlock(hAlphaBuffer);
GlobalFree(hAlphaBuffer);
return ERR_SORT;
}
}
/* Any more records in the beta buffer? */
if (betaCounter > 0) {
if (_lwrite(hfile, betaRecord,
(UINT) (sortData->recordSize * betaCounter)) !=
(UINT) (sortData->recordSize * betaCounter)) {
GlobalUnlock(hBetaBuffer);
GlobalFree(hBetaBuffer);
GlobalUnlock(hAlphaBuffer);
GlobalFree(hAlphaBuffer);
return ERR_SORT;
}
}
/* Any more records in the alpha buffer? */
if (alphaCounter > 0) {
if (_lwrite(hfile, alphaRecord,
(UINT) (sortData->recordSize * alphaCounter)) !=
(UINT) (sortData->recordSize * alphaCounter)) {
GlobalUnlock(hBetaBuffer);
GlobalFree(hBetaBuffer);
GlobalUnlock(hAlphaBuffer);
GlobalFree(hAlphaBuffer);
return ERR_SORT;
}
}
/* Do the next bunch */
currentAlphaBunch--;
} while (currentAlphaBunch != 0);
/* Clean up */
GlobalUnlock(hBetaBuffer);
GlobalFree(hBetaBuffer);
GlobalUnlock(hAlphaBuffer);
GlobalFree(hAlphaBuffer);
return ERR_SUCCESS;
}
/***************************************************************************/
RETCODE INTFUNC RemoveDups(HFILE hfileIn, HFILE hfileOut,
SORT_DATA FAR *sortData, UDWORD FAR *lpRecordCount)
/* Removes the duplicate records. The number of input records is */
/* specified by *lpRecordCount, the number of resultant records is */
/* returned in *lpRecordCount also */
{
LONG filesize;
UWORD idx;
LPSTR prevRecordPtr;
LPSTR thisRecordPtr;
LPSTR prevKeyPtr;
LPSTR thisKeyPtr;
UDWORD recordsRemaining;
BOOL firstTime;
/* Position at the start of the files */
if (_llseek(hfileIn, 0, 0) == HFILE_ERROR) {
return ERR_SORT;
}
if (_llseek(hfileOut, 0, 0) == HFILE_ERROR) {
return ERR_SORT;
}
/* While there are still some records... */
firstTime = TRUE;
recordsRemaining = *lpRecordCount;
while (recordsRemaining > 0) {
/* Find out how many records to look through this iteration */
if (recordsRemaining <= sortData->bufferRecordCount)
sortData->recordCount = (UWORD) recordsRemaining;
else
sortData->recordCount = sortData->bufferRecordCount;
recordsRemaining -= (sortData->recordCount);
/* If this is the first iteration, read the first bunch of records */
/* into the very beginning of the buffer. Otherwise, read them */
/* into the next record position in order to preserve the first */
/* record in the buffer. */
filesize = sortData->recordCount * sortData->recordSize;
if (firstTime) {
if (_lread(hfileIn, sortData->dataBuffer, (UINT) filesize) !=
(UINT) filesize) {
return ERR_SORT;
}
/* If this is the first iteration, remove the record in the */
/* first position from the count (it will be added back in */
/* when we do the last bunch) */
(sortData->recordCount)--;
firstTime = FALSE;
}
else {
if (_lread(hfileIn, &(sortData->dataBuffer[sortData->recordSize]),
(UINT) filesize) != (UINT) filesize) {
return ERR_SORT;
}
}
/* Point at the records to process */
prevRecordPtr = sortData->dataBuffer;
prevKeyPtr = prevRecordPtr + sortData->dupKeyStart;
thisRecordPtr = prevRecordPtr + sortData->recordSize;
thisKeyPtr = prevKeyPtr + sortData->recordSize;
/* For each record... */
for (idx = 1; idx < sortData->recordCount+1; idx++) {
/* Is the record a duplicate of the previous one? */
if (_fmemcmp(prevKeyPtr, thisKeyPtr, sortData->dupKeyLen) == 0) {
/* Yes. Remove it */
_fmemcpy(prevRecordPtr, thisRecordPtr,
sortData->recordSize * (sortData->recordCount - idx + 1));
/* Reduce record count */
(*lpRecordCount)--;
sortData->recordCount--;
idx--;
}
else {
/* No. Point at next record */
prevRecordPtr = thisRecordPtr;
thisRecordPtr += (sortData->recordSize);
prevKeyPtr = thisKeyPtr;
thisKeyPtr += (sortData->recordSize);
}
}
/* If there are no more records, write all the records in the */
/* buffer (this is where we add back the record removed from the */
/* first bunch) */
if (recordsRemaining == 0)
(sortData->recordCount)++;
/* Are there any records to write? */
if (sortData->recordCount > 0) {
/* Yes. Write them out */
filesize = (sortData->recordCount) * sortData->recordSize;
if (_lwrite(hfileOut, sortData->dataBuffer, (UINT) filesize) !=
(UINT) filesize) {
return ERR_SORT;
}
}
/* Move the last record to the beginning of the buffer for the */
/* next iteration */
if (recordsRemaining != 0) {
_fmemcpy(sortData->dataBuffer, prevRecordPtr,
sortData->recordSize);
}
}
/* Set the end of file mark in the output file */
if (_lwrite(hfileOut, sortData->dataBuffer, 0) != 0) {
return ERR_SORT;
}
return ERR_SUCCESS;
}
/***************************************************************************/
#ifdef WIN32
void s_1mains(char * szFilenameIn, char * szFilenameOut,
char * lpszInstructions, long * lpRecordCount, int * lpErrcode)
#else
void far PASCAL s_1mains(LPSTR szFilenameIn, LPSTR szFilenameOut,
LPSTR lpszInstructions, LPLONG lpRecordCount, LPINT lpErrcode)
#endif
{
LONG filesize;
HGLOBAL hDataBuffer;
UDWORD recordCount;
UDWORD recordsRemaining;
SORT_DATA sortData;
HFILE hfileIn;
HFILE hfileOut;
/* Get sorting instructions */
*lpErrcode = SortInstructions(lpszInstructions, &sortData);
if (*lpErrcode != ERR_SUCCESS)
return;
/* Open input file */
hfileIn = _lopen(szFilenameIn, OF_READWRITE);
if (hfileIn == HFILE_ERROR) {
*lpErrcode = ERR_SORT;
return;
}
/* Figure out how many records there are */
filesize = _llseek(hfileIn, 0, 2);
if (filesize == HFILE_ERROR) {
_lclose(hfileIn);
*lpErrcode = ERR_SORT;
return;
}
recordCount = ((UDWORD) filesize) / sortData.recordSize;
/* Error if any incomplete records */
if ((recordCount * sortData.recordSize) != (UDWORD) filesize) {
_lclose(hfileIn);
*lpErrcode = ERR_SORT;
return;
}
/* Get buffer to read records into */
if (filesize > (65536 - sortData.recordSize))
sortData.bufferRecordCount = (UWORD) ((65536 - sortData.recordSize) /
sortData.recordSize);
else
sortData.bufferRecordCount = (UWORD) recordCount;
hDataBuffer = GlobalAlloc(GMEM_MOVEABLE,
sortData.recordSize * (sortData.bufferRecordCount+1));
if (hDataBuffer == NULL) {
_lclose(hfileIn);
*lpErrcode = ERR_SORT;
return;
}
sortData.dataBuffer = (LPSTR) GlobalLock(hDataBuffer);
if (sortData.dataBuffer == NULL) {
GlobalFree(hDataBuffer);
_lclose(hfileIn);
*lpErrcode = ERR_SORT;
return;
}
/* Open output file */
hfileOut = _lopen(szFilenameOut, OF_READWRITE);
if (hfileOut == HFILE_ERROR) {
_lclose(hfileIn);
*lpErrcode = ERR_SORT;
return;
}
/* Sort the file (sortData.bufferRecordCount records at a time) */
*lpErrcode = ERR_SUCCESS;
sortData.recordStart = 0;
recordsRemaining = recordCount;
while ((*lpErrcode == ERR_SUCCESS) && (recordsRemaining > 0)) {
/* Find out how many records in the next bunch to sort */
if (recordsRemaining <= sortData.bufferRecordCount)
sortData.recordCount = (UWORD) recordsRemaining;
else
sortData.recordCount = sortData.bufferRecordCount;
recordsRemaining -= (sortData.recordCount);
/* Sort the next bunch of records */
if (sortData.dupKeyLen == 0)
*lpErrcode = SortFile(hfileIn, hfileOut, &sortData);
else
*lpErrcode = SortFile(hfileIn, hfileIn, &sortData);
/* Point at next bunch of records */
sortData.recordStart += (sortData.recordCount);
}
/* Merge the file */
if (*lpErrcode == ERR_SUCCESS) {
if (sortData.dupKeyLen == 0)
*lpErrcode = MergeFile(hfileOut, &sortData, recordCount);
else
*lpErrcode = MergeFile(hfileIn, &sortData, recordCount);
}
/* Remove the duplicates */
if ((*lpErrcode == ERR_SUCCESS) && (sortData.dupKeyLen != 0))
*lpErrcode = RemoveDups(hfileIn, hfileOut, &sortData,
&recordCount);
/* Clean up */
_lclose(hfileOut);
GlobalUnlock(hDataBuffer);
GlobalFree(hDataBuffer);
_lclose(hfileIn);
/* Return final record count */
*lpRecordCount = (LONG) recordCount;
return;
}
/***************************************************************************/