
****************************************************************
*
* CSortExample.C
*
* This program illustrates how to call the SortMerge object
* modules from C.  The records to be sorted are read from 
* the SAM file Files.In, contained on the distribution diskette.  
* The sorted records are written to the SAM file Files.Out.
*
* Files.In contains a sequence of 65byte records terminated by 
* line feeds.  All the records must be exactly 65bytes long 
* (including the line feed), or the sort will not work.
*
* Two 6byte keys are used for the sort, both of type character.  
* The first is located 6 bytes from the beginning of the record, 
* and the second 26 bytes from the beginning.  Both are sorted in 
* ascending order.
*
*****************************************************************


* CTOS and SAM Types and Constants *

define ercOk   0
define ercEof  1
define ercInternalError  8

define modeRead    0x6D72
define modeWrite   0x6D77

define pageSize    512

define NULL        ((char *) 0)

typedef int ErcType;


* SortMerge Types and Constants *

define ercNoMoreRecords  3404
define charType          2

typedef struct {
	ErcType erc;
	ErcType ercDetail;
} StatusBlockType;

typedef struct {
	char cbWorkFile1;           * offset 0 *
	char rgbWorkFile1[91];      * 1 *
	char cbPwWorkFile1;         * 92 *
	char rgbPwWorkFile1[12];    * 93 *
	char cbWorkFile2;           * 105 *
	char rgbWorkFile2[91];      * 106 *
	char cbPwWorkFile2;         * 197 *
	char rgbPwWorkFile2[12];    * 198 *
	long qsSortWorkFileCreate;  * 210 *
	int  sWorkFileIncrement;    * 214 *
	long qsSortWorkArea;        * 216 *
	int  sRecordMax;            * 220 *
	int  fStableSort;           * 222 *
} PrepareSortBlockType;

typedef struct {
	int rbKey;
	int cbKey;
	int typ;
	int fAscending;
} KeyComponentType;

typedef struct {
	int cKeyComponents;
	KeyComponentType keyComponentDescriptor1;
	KeyComponentType keyComponentDescriptor2;
} KeyDescriptorType;

* CTOS and SAM Procedures *

extern void CheckErc( * erc * );

extern void FatalError( * erc * );

extern ErcType OpenByteStream( * 
	pBs, pbFile, cbFile,
	pbPW, cbPW, mode : modeType; 
	pBuffer, cbBuffer * );

extern ErcType ReadBsRecord( * pBs, pBufferRet, sBuffer, psDataRet * );

extern ErcType CloseByteStream( * pBs * );

extern ErcType WriteBsRecord( * pBs, pb, cb, pcbRet * );


* SortMerge Procedures *

extern ErcType ConcludeSort ( * pStatusBlockRet * );

extern ErcType DoSort ( * pStatusBlockRet * );

extern ErcType PrepareKeySort ( *
	pPrepareSortBlock, pKeyDescriptor, 
	pSortWorkArea,
	pStatusBlockRet * );

extern ErcType PrepareSort ( *
	pPrepareSortBlock, psKey, pSortWorkArea, pStatusBlockRet * );

extern ErcType ReleaseRecord ( * psRecord, pRecord, pStatusBlockRet * );

extern ErcType ReleaseRecordAndKey ( *
	psRecord, pRecord,
	psKey, pKey,
	pStatusBlockRet * );

extern ErcType ReturnRecord ( * psRecordRet, pRecordRet, pStatusBlockRet * );

extern ErcType ReturnRecordAndKey ( *
	psRecordRet, pRecordRet,
	psKeyRet, pKeyRet,
	pStatusBlockRet * );

extern ErcType TerminateSort ( * pStatusBlockRet * );


* C library procedure to copy n bytes from s2 to s1, return s1 *

extern char *memcpy( * s1, s2, n * );


* Global Variables *

char    bsIn[130];
char    bsOut[130];
char    rgbBufferIn[1024];
char    rgbBufferOut[1024];
char    rgbWorkArea[8192];
PrepareSortBlockType   prepareSortBlock;
KeyDescriptorType      keyDescriptor;
StatusBlockType        statusBlock;
char    rgbRecord[66];
int     sRecord;
char    zbInFileName[] = Files.In;
char    zbOutFileName[] = Files.Out;
char    zbWorkFile1[] = [Sys]<$>WorkFile1.Tmp;
char    zbWorkFile2[] = [Sys]<$>WorkFile2.Tmp;


* Procedure to check status blocks, returning on ercOk *

void CheckStatus( erc, pStatusBlock )
ErcType erc;
StatusBlockType *pStatusBlock;
{
	if (erc = pStatusBlock>erc) FatalError(ercInternalError);
	if (erc == ercOk) return;
	printf(\nSort Error\n    Status code d\n, erc);
	if (pStatusBlock>ercDetail = ercOk)
		printf(   Detail status code d\n, pStatusBlock>ercDetail);
	(void) TerminateSort(pStatusBlock);
	FatalError(erc);
}


* Main Program *

main()
{
ErcType erc;
int     wRet;
int     cb;

* Open input file *
CheckErc(OpenByteStream(bsIn, zbInFileName, sizeof(zbInFileName)  1,
			NULL, 0, modeRead,
			rgbBufferIn, sizeof(rgbBufferIn)));

* Open output file *
CheckErc(OpenByteStream(bsOut, zbOutFileName, sizeof(zbOutFileName)  1,
			NULL, 0, modeWrite,
			rgbBufferOut, sizeof(rgbBufferOut)));

* Initialize prepareSortBlock *
prepareSortBlock.cbWorkFile1 = cb = sizeof(zbWorkFile1)  1;
(void)memcpy(prepareSortBlock.rgbWorkFile1, zbWorkFile1, cb);
prepareSortBlock.cbPwWorkFile1 = 0;
prepareSortBlock.cbWorkFile2 = cb = sizeof(zbWorkFile2)  1;
(void)memcpy(prepareSortBlock.rgbWorkFile2, zbWorkFile2, cb);
prepareSortBlock.cbPwWorkFile2 = 0;
prepareSortBlock.qsSortWorkFileCreate = 1024; 
prepareSortBlock.sWorkFileIncrement = 512;
prepareSortBlock.qsSortWorkArea = sizeof(rgbWorkArea);
prepareSortBlock.sRecordMax = 65;
prepareSortBlock.fStableSort = 0;

* Initialize key descriptor *
* 2 keys are used.          *
* The first key is of type character, is 6 bytes long, has an *
* offset of 6 bytes from the beginning of the record, and is  *
* sorted in ascending order. *
keyDescriptor.cKeyComponents = 2;
keyDescriptor.keyComponentDescriptor1.rbKey = 6;
keyDescriptor.keyComponentDescriptor1.cbKey = 6;
keyDescriptor.keyComponentDescriptor1.typ = charType;
keyDescriptor.keyComponentDescriptor1.fAscending = 0xFF;
* The second key is of type character, is 6 bytes long, has an *
* offset of 26 bytes from the beginning of the record, and is  *
* sorted in ascending order. *
keyDescriptor.keyComponentDescriptor2.rbKey = 26;
keyDescriptor.keyComponentDescriptor2.cbKey = 6;
keyDescriptor.keyComponentDescriptor2.typ = charType;
keyDescriptor.keyComponentDescriptor2.fAscending = 0xFF;

* Initialize Sort *
CheckStatus(
	PrepareKeySort(
		prepareSortBlock, keyDescriptor,
		rgbWorkArea, statusBlock), 
	statusBlock);

* Release records *
printf(\nRelease Records\n);
erc = ercOk;
sRecord = 65;
while (erc == ercOk)
{
	erc = ReadBsRecord(bsIn, rgbRecord, sRecord, wRet);
	if (erc == ercOk)
	{
		* nullterminate string for printing, leave line feed in record *
		rgbRecord[sRecord] = '\0';
		printf(s, rgbRecord);
		CheckStatus(
			ReleaseRecord(sRecord, rgbRecord, statusBlock),
			statusBlock);
	}
}
if (erc = ercEof) FatalError(erc);

* Do Sort *
printf(Do Sort\n);
CheckStatus(DoSort(statusBlock), statusBlock);

* Retrieve records *
printf(Return Records\n);
erc = ercOk;
while (erc == ercOk)
{
	erc = ReturnRecord(sRecord, rgbRecord, statusBlock);
	if (erc == ercOk)
	{
		if (sRecord = 65) FatalError(ercInternalError);
		CheckErc(WriteBsRecord(
			 bsOut, rgbRecord, sRecord, wRet));
		printf(s, rgbRecord);
	}
}
if (erc = ercNoMoreRecords) CheckStatus(erc, statusBlock);

* Close files and end sort *
CheckStatus(ConcludeSort(statusBlock), statusBlock);
CheckErc(CloseByteStream(bsIn));
CheckErc(CloseByteStream(bsOut));
printf(Sort concluded successfully\n);

}
