读了前5章,感触最深的是作者在例子程序中对UNICODE的考虑,另外就是将windows的API和UNIX进行对比,结合前段时间在看的《UNIX网络编程 卷2》,感觉对比性很强。
印象最深刻的就是第 5 章的 3 个排序示例,将外部文件排序用内存来实现,堆,内存映射文件以及基准指针的使用让人大开眼见,不过比之《 windows 核心编程》还是有差距
#include
"
EvryThng.h
"
#define KEY_SIZE 8
/**/ /* Structure definition for a tree node. */
typedef struct _TreeNode {
struct _TreeNode *Left, *Right;
TCHAR Key [KEY_SIZE];
LPTSTR pData;
} TREENODE, * LPTNODE, ** LPPTNODE;
#define NODE_SIZE sizeof (TREENODE)
#define NODE_HEAP_ISIZE 0x8000
#define DATA_HEAP_ISIZE 0x8000
#define MAX_DATA_LEN 0x1000
#define TKEY_SIZE KEY_SIZE * sizeof (TCHAR)
LPTNODE FillTree (HANDLE, HANDLE, HANDLE);
BOOL Scan (LPTNODE);
int KeyCompare (LPCTSTR, LPCTSTR); iFile; /**/ /* for access in exception handler */
BOOL InsertTree (LPPTNODE, LPTNODE);
int _tmain ( int argc, LPTSTR argv [])
{
HANDLE hIn, hNode = NULL, hData = NULL;
LPTNODE pRoot;
BOOL NoPrint;
CHAR ErrorMessage[256];
int iFirstFile = Options (argc, argv, _T ("n"), &NoPrint, NULL);
if (argc <= iFirstFile)
ReportError (_T ("Usage: sortBT [options] files"), 1, FALSE);
/**//* Process all files on the command line. */
for (iFile = iFirstFile; iFile < argc; iFile++) __try {
/**//* Open the input file. */
hIn = CreateFile (argv [iFile], GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hIn == INVALID_HANDLE_VALUE)
RaiseException (0, 0, 0, NULL);
/**//* Allocate the two heaps. */
__try {
hNode = HeapCreate (
HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE, NODE_HEAP_ISIZE, 0);
hData = HeapCreate (
HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE, DATA_HEAP_ISIZE, 0);
/**//* Process the input file, creating the tree. */
pRoot = FillTree (hIn, hNode, hData);
/**//* Display the tree in Key order. */
if (!NoPrint) {
_tprintf (_T ("Sorted file: %s\n"), argv [iFile]);
Scan (pRoot);
}
} __finally { /**//* Heaps and file handle are always closed */
/**//* Destroy the two heaps and data structures. */
if (hNode != NULL) HeapDestroy (hNode);
if (hNode != NULL) HeapDestroy (hData);
hNode = NULL; hData = NULL;
if (hIn != INVALID_HANDLE_VALUE) CloseHandle (hIn);
}
} /**//* End of main file processing loop and try block. */
__except (EXCEPTION_EXECUTE_HANDLER) {
_stprintf (ErrorMessage, _T("\n%s %s"), _T("sortBT error on file:"), argv[iFile]);
ReportError (ErrorMessage, 0, TRUE);
}
return 0;
}
LPTNODE FillTree (HANDLE hIn, HANDLE hNode, HANDLE hData)
/**/ /* Scan the input file, creating a binary search tree in the
hNode heap with data pointers to the hData heap. */
/**/ /* Use the calling program's exception handler. */
{
LPTNODE pRoot = NULL, pNode;
DWORD nRead, i;
BOOL AtCR;
TCHAR DataHold [MAX_DATA_LEN];
LPTSTR pString;
/**//* Open the input file. */
while (TRUE) {
pNode = HeapAlloc (hNode, HEAP_ZERO_MEMORY, NODE_SIZE);
pNode->pData = NULL;
(pNode->Left) = pNode->Right = NULL;
/**//* Read the key. Return if done. */
if (!ReadFile (hIn, pNode->Key, TKEY_SIZE,
&nRead, NULL) || nRead != TKEY_SIZE)
/**//* Assume end of file on error. */
return pRoot; /**//* Read the data until the end of line. */
AtCR = FALSE; /**//* Last character was not a CR. */
for (i = 0; i < MAX_DATA_LEN; i++) {
ReadFile (hIn, &DataHold [i], TSIZE, &nRead, NULL);
if (AtCR && DataHold [i] == LF) break;
AtCR = (DataHold [i] == CR);
}
DataHold [i - 1] = '\0';
/**//* DataHold contains the data without the key.
Combine the Key and the Data. */
pString = HeapAlloc (hData, HEAP_ZERO_MEMORY,
(SIZE_T)(KEY_SIZE + _tcslen (DataHold) + 1) * TSIZE);
memcpy (pString, pNode->Key, TKEY_SIZE);
pString [KEY_SIZE] = '\0';
_tcscat (pString, DataHold);
pNode->pData = pString;
/**//* Insert the new node into the search tree. */
InsertTree (&pRoot, pNode);
} /**//* End of while (TRUE) loop */
return NULL; /**//* Failure */
}
BOOL InsertTree (LPPTNODE ppRoot, LPTNODE pNode)
/**/ /* Insert the new node, pNode, into the binary search tree, pRoot. */
{
if (*ppRoot == NULL) {
*ppRoot = pNode;
return TRUE;
}
if (KeyCompare (pNode->Key, (*ppRoot)->Key) < 0)
InsertTree (&((*ppRoot)->Left), pNode);
else
InsertTree (&((*ppRoot)->Right), pNode);
return TRUE;
}
int KeyCompare (LPCTSTR pKey1, LPCTSTR pKey2)
/**/ /* Compare two records of generic characters.
The key position and length are global variables. */
{
return _tcsncmp (pKey1, pKey2, KEY_SIZE);
}
static BOOL Scan (LPTNODE pNode)
/**/ /* Scan and print the contents of a binary tree. */
{
if (pNode == NULL)
return TRUE;
Scan (pNode->Left);
_tprintf (_T ("%s\n"), pNode->pData);
Scan (pNode->Right);
return TRUE;
}
#define KEY_SIZE 8
/**/ /* Structure definition for a tree node. */
typedef struct _TreeNode {
struct _TreeNode *Left, *Right;
TCHAR Key [KEY_SIZE];
LPTSTR pData;
} TREENODE, * LPTNODE, ** LPPTNODE;
#define NODE_SIZE sizeof (TREENODE)
#define NODE_HEAP_ISIZE 0x8000
#define DATA_HEAP_ISIZE 0x8000
#define MAX_DATA_LEN 0x1000
#define TKEY_SIZE KEY_SIZE * sizeof (TCHAR)
LPTNODE FillTree (HANDLE, HANDLE, HANDLE);
BOOL Scan (LPTNODE);
int KeyCompare (LPCTSTR, LPCTSTR); iFile; /**/ /* for access in exception handler */
BOOL InsertTree (LPPTNODE, LPTNODE);
int _tmain ( int argc, LPTSTR argv [])
{
HANDLE hIn, hNode = NULL, hData = NULL;
LPTNODE pRoot;
BOOL NoPrint;
CHAR ErrorMessage[256];
int iFirstFile = Options (argc, argv, _T ("n"), &NoPrint, NULL);
if (argc <= iFirstFile)
ReportError (_T ("Usage: sortBT [options] files"), 1, FALSE);
/**//* Process all files on the command line. */
for (iFile = iFirstFile; iFile < argc; iFile++) __try {
/**//* Open the input file. */
hIn = CreateFile (argv [iFile], GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hIn == INVALID_HANDLE_VALUE)
RaiseException (0, 0, 0, NULL);
/**//* Allocate the two heaps. */
__try {
hNode = HeapCreate (
HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE, NODE_HEAP_ISIZE, 0);
hData = HeapCreate (
HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE, DATA_HEAP_ISIZE, 0);
/**//* Process the input file, creating the tree. */
pRoot = FillTree (hIn, hNode, hData);
/**//* Display the tree in Key order. */
if (!NoPrint) {
_tprintf (_T ("Sorted file: %s\n"), argv [iFile]);
Scan (pRoot);
}
} __finally { /**//* Heaps and file handle are always closed */
/**//* Destroy the two heaps and data structures. */
if (hNode != NULL) HeapDestroy (hNode);
if (hNode != NULL) HeapDestroy (hData);
hNode = NULL; hData = NULL;
if (hIn != INVALID_HANDLE_VALUE) CloseHandle (hIn);
}
} /**//* End of main file processing loop and try block. */
__except (EXCEPTION_EXECUTE_HANDLER) {
_stprintf (ErrorMessage, _T("\n%s %s"), _T("sortBT error on file:"), argv[iFile]);
ReportError (ErrorMessage, 0, TRUE);
}
return 0;
}
LPTNODE FillTree (HANDLE hIn, HANDLE hNode, HANDLE hData)
/**/ /* Scan the input file, creating a binary search tree in the
hNode heap with data pointers to the hData heap. */
/**/ /* Use the calling program's exception handler. */
{
LPTNODE pRoot = NULL, pNode;
DWORD nRead, i;
BOOL AtCR;
TCHAR DataHold [MAX_DATA_LEN];
LPTSTR pString;
/**//* Open the input file. */
while (TRUE) {
pNode = HeapAlloc (hNode, HEAP_ZERO_MEMORY, NODE_SIZE);
pNode->pData = NULL;
(pNode->Left) = pNode->Right = NULL;
/**//* Read the key. Return if done. */
if (!ReadFile (hIn, pNode->Key, TKEY_SIZE,
&nRead, NULL) || nRead != TKEY_SIZE)
/**//* Assume end of file on error. */
return pRoot; /**//* Read the data until the end of line. */
AtCR = FALSE; /**//* Last character was not a CR. */
for (i = 0; i < MAX_DATA_LEN; i++) {
ReadFile (hIn, &DataHold [i], TSIZE, &nRead, NULL);
if (AtCR && DataHold [i] == LF) break;
AtCR = (DataHold [i] == CR);
}
DataHold [i - 1] = '\0';
/**//* DataHold contains the data without the key.
Combine the Key and the Data. */
pString = HeapAlloc (hData, HEAP_ZERO_MEMORY,
(SIZE_T)(KEY_SIZE + _tcslen (DataHold) + 1) * TSIZE);
memcpy (pString, pNode->Key, TKEY_SIZE);
pString [KEY_SIZE] = '\0';
_tcscat (pString, DataHold);
pNode->pData = pString;
/**//* Insert the new node into the search tree. */
InsertTree (&pRoot, pNode);
} /**//* End of while (TRUE) loop */
return NULL; /**//* Failure */
}
BOOL InsertTree (LPPTNODE ppRoot, LPTNODE pNode)
/**/ /* Insert the new node, pNode, into the binary search tree, pRoot. */
{
if (*ppRoot == NULL) {
*ppRoot = pNode;
return TRUE;
}
if (KeyCompare (pNode->Key, (*ppRoot)->Key) < 0)
InsertTree (&((*ppRoot)->Left), pNode);
else
InsertTree (&((*ppRoot)->Right), pNode);
return TRUE;
}
int KeyCompare (LPCTSTR pKey1, LPCTSTR pKey2)
/**/ /* Compare two records of generic characters.
The key position and length are global variables. */
{
return _tcsncmp (pKey1, pKey2, KEY_SIZE);
}
static BOOL Scan (LPTNODE pNode)
/**/ /* Scan and print the contents of a binary tree. */
{
if (pNode == NULL)
return TRUE;
Scan (pNode->Left);
_tprintf (_T ("%s\n"), pNode->pData);
Scan (pNode->Right);
return TRUE;
}
#include
"
EvryThng.h
"
/**/ /* Definitions of the record structure in the sort file. */
#define DATALEN 56
#define KEY_SIZE 8
typedef struct _RECORD {
TCHAR Key [KEY_SIZE];
TCHAR Data [DATALEN];
} RECORD;
#define RECSIZE sizeof (RECORD)
typedef RECORD * LPRECORD;
int KeyCompare (LPCTSTR, LPCTSTR);
int _tmain ( int argc, LPTSTR argv [])
{
/**//* The file is the first argument. Sorting is done in place. */
/**//* Sorting is done by file memory mapping. */
HANDLE hFile = INVALID_HANDLE_VALUE, hMap = NULL;
HANDLE hStdOut = GetStdHandle (STD_OUTPUT_HANDLE);
LPVOID pFile = NULL;
DWORD FsLow, Result = 2;
TCHAR TempFile [MAX_PATH];
LPTSTR pTFile;
BOOL NoPrint;
int iFirstFile;
iFirstFile = Options (argc, argv, _T ("n"), &NoPrint, NULL);
if (argc <= iFirstFile)
ReportError (_T ("Usage: sortFL [options] files"), 1, FALSE);
_try { /**//* try-except */
/**//* Copy the input file to a temp output file that will be sorted.
Do not alter the input file. */
_stprintf (TempFile, _T ("%s%s"), argv [iFirstFile], _T (".tmp"));
CopyFile (argv [iFirstFile], TempFile, TRUE);
Result = 1; /**//* tmp file is new and should be deleted. */
/**//* Open the file (use the temporary copy). */
hFile = CreateFile (TempFile, GENERIC_READ
| GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hFile ==INVALID_HANDLE_VALUE)
ReportException (_T ("File open failed."), 2);
/**//* Get file size.
If the file is too large, catch that when it is mapped. */
FsLow = GetFileSize (hFile, NULL);
if (FsLow == 0) { /**//* There is nothing to sort */
CloseHandle (hFile);
return 0; /**//* You might want to put out an informational message */
}
/**//* Create a file mapping object.
Use the file size but add space for the null character. */
hMap = CreateFileMapping (hFile, NULL, PAGE_READWRITE, 0, FsLow + TSIZE, NULL);
if (hMap == NULL)
ReportException (_T ("Create File map failed."), 3);
pFile = MapViewOfFile (hMap, FILE_MAP_ALL_ACCESS, 0, 0 /**//* FsLow + TSIZE */, 0);
if (pFile == NULL)
ReportException (_T ("MapView failed"), 4);
/**//* Now sort the file.
Perform the sort with the C library - in mapped memory. */
qsort (pFile, FsLow / RECSIZE, RECSIZE, KeyCompare);
/**//* Print out the entire sorted file. Treat it as one single string. */
pTFile = (LPTSTR) pFile;
pTFile [FsLow/TSIZE] = '\0';
if (!NoPrint)
PrintMsg (hStdOut, pFile);
/**//* Indicate successful completion. */
Result = 0;
ReportException (EMPTY, 5); /**//* Force an exception to clean up. */
return 0;
} /**//* End of inner try-except. */
_except (EXCEPTION_EXECUTE_HANDLER) {
/**//* Catch any exception here. Indicate any error.
This is the normal termination. Delete the temporary
file and Free all the resources. */
if (pFile != NULL)
UnmapViewOfFile (pFile);
if (hMap != NULL)
CloseHandle (hMap);
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle (hFile);
if (Result != 2)
DeleteFile (TempFile);
return Result;
}
} /**/ /* End of _tmain */
/**/ /* CODE FROM HERE TO END IS NOT INCLUDED IN TEXT. */
int KeyCompare (LPCTSTR pKey1, LPCTSTR pKey2)
/**/ /* Compare two records of generic characters.
The key position and length are global variables. */
{
return _tcsncmp (pKey1, pKey2, KEY_SIZE);
}
/**/ /* Definitions of the record structure in the sort file. */
#define DATALEN 56
#define KEY_SIZE 8
typedef struct _RECORD {
TCHAR Key [KEY_SIZE];
TCHAR Data [DATALEN];
} RECORD;
#define RECSIZE sizeof (RECORD)
typedef RECORD * LPRECORD;
int KeyCompare (LPCTSTR, LPCTSTR);
int _tmain ( int argc, LPTSTR argv [])
{
/**//* The file is the first argument. Sorting is done in place. */
/**//* Sorting is done by file memory mapping. */
HANDLE hFile = INVALID_HANDLE_VALUE, hMap = NULL;
HANDLE hStdOut = GetStdHandle (STD_OUTPUT_HANDLE);
LPVOID pFile = NULL;
DWORD FsLow, Result = 2;
TCHAR TempFile [MAX_PATH];
LPTSTR pTFile;
BOOL NoPrint;
int iFirstFile;
iFirstFile = Options (argc, argv, _T ("n"), &NoPrint, NULL);
if (argc <= iFirstFile)
ReportError (_T ("Usage: sortFL [options] files"), 1, FALSE);
_try { /**//* try-except */
/**//* Copy the input file to a temp output file that will be sorted.
Do not alter the input file. */
_stprintf (TempFile, _T ("%s%s"), argv [iFirstFile], _T (".tmp"));
CopyFile (argv [iFirstFile], TempFile, TRUE);
Result = 1; /**//* tmp file is new and should be deleted. */
/**//* Open the file (use the temporary copy). */
hFile = CreateFile (TempFile, GENERIC_READ
| GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hFile ==INVALID_HANDLE_VALUE)
ReportException (_T ("File open failed."), 2);
/**//* Get file size.
If the file is too large, catch that when it is mapped. */
FsLow = GetFileSize (hFile, NULL);
if (FsLow == 0) { /**//* There is nothing to sort */
CloseHandle (hFile);
return 0; /**//* You might want to put out an informational message */
}
/**//* Create a file mapping object.
Use the file size but add space for the null character. */
hMap = CreateFileMapping (hFile, NULL, PAGE_READWRITE, 0, FsLow + TSIZE, NULL);
if (hMap == NULL)
ReportException (_T ("Create File map failed."), 3);
pFile = MapViewOfFile (hMap, FILE_MAP_ALL_ACCESS, 0, 0 /**//* FsLow + TSIZE */, 0);
if (pFile == NULL)
ReportException (_T ("MapView failed"), 4);
/**//* Now sort the file.
Perform the sort with the C library - in mapped memory. */
qsort (pFile, FsLow / RECSIZE, RECSIZE, KeyCompare);
/**//* Print out the entire sorted file. Treat it as one single string. */
pTFile = (LPTSTR) pFile;
pTFile [FsLow/TSIZE] = '\0';
if (!NoPrint)
PrintMsg (hStdOut, pFile);
/**//* Indicate successful completion. */
Result = 0;
ReportException (EMPTY, 5); /**//* Force an exception to clean up. */
return 0;
} /**//* End of inner try-except. */
_except (EXCEPTION_EXECUTE_HANDLER) {
/**//* Catch any exception here. Indicate any error.
This is the normal termination. Delete the temporary
file and Free all the resources. */
if (pFile != NULL)
UnmapViewOfFile (pFile);
if (hMap != NULL)
CloseHandle (hMap);
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle (hFile);
if (Result != 2)
DeleteFile (TempFile);
return Result;
}
} /**/ /* End of _tmain */
/**/ /* CODE FROM HERE TO END IS NOT INCLUDED IN TEXT. */
int KeyCompare (LPCTSTR pKey1, LPCTSTR pKey2)
/**/ /* Compare two records of generic characters.
The key position and length are global variables. */
{
return _tcsncmp (pKey1, pKey2, KEY_SIZE);
}
#include
"
EvryThng.h
"
int KeyCompare (LPCTSTR, LPCTSTR);
DWORD CreateIndexFile (DWORD, LPCTSTR, LPTSTR);
DWORD_PTR KStart, KSize; /**/ /* Key start position & size (TCHAR). */
BOOL Revrs;
int _tmain ( int argc, LPTSTR argv [])
{
/**//* The file is the first argument. Sorting is done in place. */
/**//* Sorting is done by file memory mapping. */
HANDLE hInFile, hInMap; /**//* Input file handles. */
HANDLE hXFile, hXMap; /**//* Index file handles. */
HANDLE hStdOut = GetStdHandle (STD_OUTPUT_HANDLE);
BOOL IdxExists, NoPrint;
DWORD FsIn, FsX, RSize, iKey, nWrite, *pSizes;
LPTSTR pInFile = NULL;
LPBYTE pXFile = NULL, pX;
TCHAR _based (pInFile) *pIn;
TCHAR IdxFlNam [MAX_PATH], ChNewLine = '\n';
int FlIdx;
/**//* Determine the options. */
FlIdx = Options (argc, argv, _T ("rIn"), &Revrs, &IdxExists, &NoPrint, NULL);
if (FlIdx >= argc)
ReportError (_T ("No file name on command line."), 1, FALSE);
/**//* Step 1: Open and Map the Input File. */
hInFile = CreateFile (argv [FlIdx], GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
if (hInFile == INVALID_HANDLE_VALUE)
ReportError (_T ("Failed to open input file."), 2, TRUE);
/**//* Create a file mapping object. Use the file size. */
hInMap = CreateFileMapping (hInFile, NULL, PAGE_READWRITE, 0, 0, NULL);
if (hInMap == NULL)
ReportError (_T ("Failed to create input file mapping."), 3, TRUE);
pInFile = MapViewOfFile (hInMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pInFile == NULL)
ReportError (_T ("Failed to map input file."), 4, TRUE);
/**//* Get the file size.
As the mapping succeeded, the file size is less than 2 GB. */
FsIn = GetFileSize (hInFile, NULL);
/**//* Create the index file name. */
_stprintf (IdxFlNam, _T ("%s%s"), argv [FlIdx], _T (".idx"));
/**//* Steps 2 and 3, if necessary. */
if (!IdxExists)
RSize = CreateIndexFile (FsIn, IdxFlNam, pInFile);
/**//* Step 4. Map the index file. */
hXFile = CreateFile (IdxFlNam, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
if (hXFile == INVALID_HANDLE_VALUE)
ReportError (_T ("Failed to open existing index file."), 5, TRUE);
/**//* Create a file mapping object. Use the file size. */
hXMap = CreateFileMapping (hXFile, NULL, PAGE_READWRITE, 0, 0, NULL);
if (hXMap == NULL)
ReportError (_T ("Failed to create index file mapping."), 6, TRUE);
pXFile = MapViewOfFile (hXMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pXFile == NULL)
ReportError (_T ("Failed to map index file."), 7, TRUE);
FsX = GetFileSize (hXFile, NULL);
/**//* Get the key size/key start and adjust the file size for the
KeySize/KeyStart fields. Compute the record size from the key size. */
pSizes = (LPDWORD)pXFile; KSize = *pSizes;
KStart = *(pSizes + 1);
FsX -= 2 * sizeof (DWORD);
/**//* Step 5. Sort the index file using qsort. */
if (!IdxExists)
qsort (pXFile + 2 * sizeof (DWORD), FsX / RSize, RSize, KeyCompare);
/**//* Step 6. Output the input file in sorted order. */
/**//* Point to the address of the input file string.
Start in the Input file. */
pX = pXFile + 2 * sizeof (DWORD) + RSize - sizeof (LPTSTR);
if (!NoPrint)
for (iKey = 0; iKey < FsX / RSize; iKey++) {
WriteFile (hStdOut, &ChNewLine, TSIZE, &nWrite, NULL);
/**//* The cast on pX is important, as it is a pointer to a
byte and we need the four bytes of a based pointer. */
pIn = (TCHAR _based (pInFile)*) *(DWORD_PTR *) pX;
while ((*pIn != CR || *(pIn + 1) != LF) && (SIZE_T) pIn < (SIZE_T)FsIn) {
WriteFile (hStdOut, pIn, TSIZE, &nWrite, NULL);
pIn++;
}
pX += RSize;
}
/**//* Done. Free all the handles and maps. */
UnmapViewOfFile (pInFile);
CloseHandle (hInMap);
CloseHandle (hInFile);
UnmapViewOfFile (pXFile);
CloseHandle (hXMap);
CloseHandle (hXFile);
return 0;
}
DWORD CreateIndexFile (DWORD FsIn, LPCTSTR IdxFlNam, LPTSTR pInFile)
/**/ /* Perform Steps 2-3 as defined in program description. */
/**/ /* This step will be skipped if the options specify use of an existing index file. */
{
HANDLE hXFile;
TCHAR _based (pInFile) *pInScan = 0;
DWORD nWrite;
/**//* Step 2a: Create an index file.
Do not map it yet as its length is not known. */
hXFile = CreateFile (IdxFlNam, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
if (hXFile == INVALID_HANDLE_VALUE)
ReportError (_T ("Failure to create index file."), 8, TRUE);
/**//* Step 2b: Get the first key and determine key size and start. */
KStart = (DWORD_PTR) pInScan;
/**//* Computed start of key field. */
while (*pInScan != ' ' && *pInScan != '\t') pInScan++;
/**//* Computed end of key field */
KSize = ((DWORD_PTR) pInScan - KStart) / TSIZE;
/**//* Computed key field size in characters. */
/**//* Step 2c. Step 3. Scan the complete file, writing keys
and record pointers to the key file. */
/**//* The eight bytes contain the Key Size/Key Start.
This is necessary so that we can re-use the index file. */
WriteFile (hXFile, &KSize, sizeof (DWORD), &nWrite, NULL);
WriteFile (hXFile, &KStart, sizeof (DWORD), &nWrite, NULL);
pInScan = /**//*(TCHAR _based (pInFile)*)*/0;
while ((DWORD_PTR) pInScan < FsIn) {
WriteFile (hXFile, pInScan + KStart, KSize * TSIZE, &nWrite, NULL);
WriteFile (hXFile, &pInScan, sizeof (LPTSTR), &nWrite, NULL);
while ((DWORD) (DWORD_PTR)pInScan < FsIn && ((*pInScan != CR)
|| (*(pInScan + 1) != LF))) {
pInScan++; /**//* Skip to end of line. */
}
pInScan += 2; /**//* Skip past CR, LF. */
}
CloseHandle (hXFile);
/**//* Size of an individual record. */
return KSize * TSIZE + sizeof (LPTSTR);
}
int KeyCompare (LPCTSTR pKey1, LPCTSTR pKey2)
/**/ /* Compare two records of generic characters.
The key position and length are global variables. */
{
DWORD i;
TCHAR t1, t2;
int Result = 0;
for (i = 0; i < KSize && Result == 0; i++) {
t1 = *pKey1;
t2 = *pKey2;
if (t1 < t2)
Result = -1;
if (t1 > t2)
Result = +1;
pKey1++;
pKey2++;
}
return Revrs ? -Result : Result;
}
int KeyCompare (LPCTSTR, LPCTSTR);
DWORD CreateIndexFile (DWORD, LPCTSTR, LPTSTR);
DWORD_PTR KStart, KSize; /**/ /* Key start position & size (TCHAR). */
BOOL Revrs;
int _tmain ( int argc, LPTSTR argv [])
{
/**//* The file is the first argument. Sorting is done in place. */
/**//* Sorting is done by file memory mapping. */
HANDLE hInFile, hInMap; /**//* Input file handles. */
HANDLE hXFile, hXMap; /**//* Index file handles. */
HANDLE hStdOut = GetStdHandle (STD_OUTPUT_HANDLE);
BOOL IdxExists, NoPrint;
DWORD FsIn, FsX, RSize, iKey, nWrite, *pSizes;
LPTSTR pInFile = NULL;
LPBYTE pXFile = NULL, pX;
TCHAR _based (pInFile) *pIn;
TCHAR IdxFlNam [MAX_PATH], ChNewLine = '\n';
int FlIdx;
/**//* Determine the options. */
FlIdx = Options (argc, argv, _T ("rIn"), &Revrs, &IdxExists, &NoPrint, NULL);
if (FlIdx >= argc)
ReportError (_T ("No file name on command line."), 1, FALSE);
/**//* Step 1: Open and Map the Input File. */
hInFile = CreateFile (argv [FlIdx], GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
if (hInFile == INVALID_HANDLE_VALUE)
ReportError (_T ("Failed to open input file."), 2, TRUE);
/**//* Create a file mapping object. Use the file size. */
hInMap = CreateFileMapping (hInFile, NULL, PAGE_READWRITE, 0, 0, NULL);
if (hInMap == NULL)
ReportError (_T ("Failed to create input file mapping."), 3, TRUE);
pInFile = MapViewOfFile (hInMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pInFile == NULL)
ReportError (_T ("Failed to map input file."), 4, TRUE);
/**//* Get the file size.
As the mapping succeeded, the file size is less than 2 GB. */
FsIn = GetFileSize (hInFile, NULL);
/**//* Create the index file name. */
_stprintf (IdxFlNam, _T ("%s%s"), argv [FlIdx], _T (".idx"));
/**//* Steps 2 and 3, if necessary. */
if (!IdxExists)
RSize = CreateIndexFile (FsIn, IdxFlNam, pInFile);
/**//* Step 4. Map the index file. */
hXFile = CreateFile (IdxFlNam, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
if (hXFile == INVALID_HANDLE_VALUE)
ReportError (_T ("Failed to open existing index file."), 5, TRUE);
/**//* Create a file mapping object. Use the file size. */
hXMap = CreateFileMapping (hXFile, NULL, PAGE_READWRITE, 0, 0, NULL);
if (hXMap == NULL)
ReportError (_T ("Failed to create index file mapping."), 6, TRUE);
pXFile = MapViewOfFile (hXMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (pXFile == NULL)
ReportError (_T ("Failed to map index file."), 7, TRUE);
FsX = GetFileSize (hXFile, NULL);
/**//* Get the key size/key start and adjust the file size for the
KeySize/KeyStart fields. Compute the record size from the key size. */
pSizes = (LPDWORD)pXFile; KSize = *pSizes;
KStart = *(pSizes + 1);
FsX -= 2 * sizeof (DWORD);
/**//* Step 5. Sort the index file using qsort. */
if (!IdxExists)
qsort (pXFile + 2 * sizeof (DWORD), FsX / RSize, RSize, KeyCompare);
/**//* Step 6. Output the input file in sorted order. */
/**//* Point to the address of the input file string.
Start in the Input file. */
pX = pXFile + 2 * sizeof (DWORD) + RSize - sizeof (LPTSTR);
if (!NoPrint)
for (iKey = 0; iKey < FsX / RSize; iKey++) {
WriteFile (hStdOut, &ChNewLine, TSIZE, &nWrite, NULL);
/**//* The cast on pX is important, as it is a pointer to a
byte and we need the four bytes of a based pointer. */
pIn = (TCHAR _based (pInFile)*) *(DWORD_PTR *) pX;
while ((*pIn != CR || *(pIn + 1) != LF) && (SIZE_T) pIn < (SIZE_T)FsIn) {
WriteFile (hStdOut, pIn, TSIZE, &nWrite, NULL);
pIn++;
}
pX += RSize;
}
/**//* Done. Free all the handles and maps. */
UnmapViewOfFile (pInFile);
CloseHandle (hInMap);
CloseHandle (hInFile);
UnmapViewOfFile (pXFile);
CloseHandle (hXMap);
CloseHandle (hXFile);
return 0;
}
DWORD CreateIndexFile (DWORD FsIn, LPCTSTR IdxFlNam, LPTSTR pInFile)
/**/ /* Perform Steps 2-3 as defined in program description. */
/**/ /* This step will be skipped if the options specify use of an existing index file. */
{
HANDLE hXFile;
TCHAR _based (pInFile) *pInScan = 0;
DWORD nWrite;
/**//* Step 2a: Create an index file.
Do not map it yet as its length is not known. */
hXFile = CreateFile (IdxFlNam, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
if (hXFile == INVALID_HANDLE_VALUE)
ReportError (_T ("Failure to create index file."), 8, TRUE);
/**//* Step 2b: Get the first key and determine key size and start. */
KStart = (DWORD_PTR) pInScan;
/**//* Computed start of key field. */
while (*pInScan != ' ' && *pInScan != '\t') pInScan++;
/**//* Computed end of key field */
KSize = ((DWORD_PTR) pInScan - KStart) / TSIZE;
/**//* Computed key field size in characters. */
/**//* Step 2c. Step 3. Scan the complete file, writing keys
and record pointers to the key file. */
/**//* The eight bytes contain the Key Size/Key Start.
This is necessary so that we can re-use the index file. */
WriteFile (hXFile, &KSize, sizeof (DWORD), &nWrite, NULL);
WriteFile (hXFile, &KStart, sizeof (DWORD), &nWrite, NULL);
pInScan = /**//*(TCHAR _based (pInFile)*)*/0;
while ((DWORD_PTR) pInScan < FsIn) {
WriteFile (hXFile, pInScan + KStart, KSize * TSIZE, &nWrite, NULL);
WriteFile (hXFile, &pInScan, sizeof (LPTSTR), &nWrite, NULL);
while ((DWORD) (DWORD_PTR)pInScan < FsIn && ((*pInScan != CR)
|| (*(pInScan + 1) != LF))) {
pInScan++; /**//* Skip to end of line. */
}
pInScan += 2; /**//* Skip past CR, LF. */
}
CloseHandle (hXFile);
/**//* Size of an individual record. */
return KSize * TSIZE + sizeof (LPTSTR);
}
int KeyCompare (LPCTSTR pKey1, LPCTSTR pKey2)
/**/ /* Compare two records of generic characters.
The key position and length are global variables. */
{
DWORD i;
TCHAR t1, t2;
int Result = 0;
for (i = 0; i < KSize && Result == 0; i++) {
t1 = *pKey1;
t2 = *pKey2;
if (t1 < t2)
Result = -1;
if (t1 > t2)
Result = +1;
pKey1++;
pKey2++;
}
return Revrs ? -Result : Result;
}