windows-nt/Source/XPSP1/NT/sdktools/list/lread.c
2020-09-26 16:20:57 +08:00

719 lines
20 KiB
C

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <memory.h>
#include <windows.h>
#include "list.h"
// ReaderThread - Reads from the file
//
// This thread is woken up by clearing SemReader,
// then vReaderFlag instructs the thread on the course of
// action to take. When displaying gets to close to the end
// of the buffer pool, vReadFlag is set and this thread is
// started.
#if _MSC_FULL_VER >= 13008827
#pragma warning(push)
#pragma warning(disable:4715) // Not all control paths return (due to infinite loop)
#endif
DWORD
ReaderThread (
DWORD dwParameter
)
{
unsigned rc, code, curPri = 0;
UNREFERENCED_PARAMETER(dwParameter);
for (; ;) {
// go into 'boosted' pririoty until we start
// working on 'non-critical' read ahead. (Ie, far away).
if (curPri != vReadPriBoost) {
SetThreadPriority( GetCurrentThread(),
vReadPriBoost );
curPri = vReadPriBoost;
}
WaitForSingleObject(vSemReader, WAITFOREVER);
ResetEvent(vSemReader);
code = vReaderFlag;
for (; ;) {
// Due to this loop, a new command may have arrived
// which takes presidence over the automated command
rc = WaitForSingleObject (vSemReader, DONTWAIT);
if (rc == 0) // New command has arrived
break;
switch (code) {
case F_NEXT: // NEXT FILE
NewFile ();
ReadDirect (vDirOffset);
// Hack... adjust priority to make first screen look
// fast. (Ie, reader thread will have lower priority
// at first; eventhough the display is really close
// to the end of the buffer)
SetThreadPriority( GetCurrentThread(),
vReadPriNormal );
break;
case F_HOME: // HOME of FILE
vTopLine = 0L;
ReadDirect (0L);
break;
case F_DIRECT:
ReadDirect (vDirOffset);
break;
case F_DOWN:
ReadNext ();
break;
case F_UP:
ReadPrev ();
break;
case F_END:
break;
case F_SYNC:
ResetEvent(vSemMoreData);
SetEvent(vSemSync);
WaitForSingleObject(vSemReader, WAITFOREVER);
ResetEvent(vSemReader);
ResetEvent(vSemSync); // Reset trigger for
// Next use.
code = vReaderFlag;
continue; // Execute Syncronized command
case F_CHECK: // No command.
break;
default:
ckdebug (1, "Bad Reader Flag");
}
// Command has been processed.
// Now check to see if read ahead is low, if so set
// command and loop.
if (vpTail->offset - vpCur->offset < vThreshold &&
vpTail->flag != F_EOF) {
code = F_DOWN; // Too close to ending
continue;
}
if (vpCur->offset - vpHead->offset < vThreshold &&
vpHead->offset != vpFlCur->SlimeTOF) {
code = F_UP; // Too close to begining
continue;
}
// Not critical, read ahead logic. The current file
// Normal priority (below display thread) for this
if (curPri != vReadPriNormal) {
SetThreadPriority( GetCurrentThread(),
vReadPriNormal );
curPri = vReadPriNormal;
}
if (vCntBlks == vMaxBlks) // All blks in use for
break; // this one file?
if (vpTail->flag != F_EOF) {
code = F_DOWN;
continue;
}
if (vpHead->offset != vpFlCur->SlimeTOF) {
code = F_UP;
continue;
}
if (vFhandle != 0) { // Must have whole file read in
CloseHandle (vFhandle); // Close the file, and set flag
vFhandle = 0;
if (!(vStatCode & S_INSEARCH)) {
ScrLock (1);
Update_head ();
vDate [ST_MEMORY] = 'M';
dis_str ((Uchar)(vWidth - ST_ADJUST), 0, vDate);
ScrUnLock ();
}
}
break; // Nothing to do. Wait
}
}
return(0);
}
#if _MSC_FULL_VER >= 13008827
#pragma warning(pop)
#endif
// WARNING: Microsoft Confidential!!!
void
NewFile ()
{
char s [60];
char h, c;
SYSTEMTIME SystemTime;
FILETIME LocalFileTime;
long *pLine;
HANDLE TempHandle;
struct Block **pBlk, **pBlkCache;
if (vFhandle)
CloseHandle (vFhandle);
vFType = 0;
vCurOffset = 0L;
// WARNING: Microsoft Confidential!!!
strcpy (s, "Listing ");
strcpy (s+8, vpFname);
// Design change per DougHo.. open files in read-only deny-none mode.
vFhandle = CreateFile( vpFlCur->fname,
GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL );
if (vFhandle == (HANDLE)(-1)) {
if (vpFlCur->prev == NULL && vpFlCur->next == NULL) {
// Only one file specified?
printf ("Could not open file '%Fs': %s",
(CFP) vpFlCur->fname, GetErrorCode( GetLastError() ));
CleanUp();
ExitProcess(0);
}
vFhandle = 0; // Error. Set externals to "safe"
vFInfo.nFileSizeLow = (unsigned)-1L; // settings. Flag error by setting
vNLine = 1; // file_size = -1
vLastLine = NOLASTLINE;
vDirOffset = vTopLine = 0L;
SetLoffset(0L);
memset (vprgLineTable, 0, sizeof (long *) * MAXTPAGE);
vprgLineTable[0] = (LFP) alloc_page ();
if (!vprgLineTable[0]) {
return;
}
vprgLineTable[0][0] = 0L; // 1st line always starts @ 0
strncpy (vDate, GetErrorCode( GetLastError() ), 20);
vDate[20] = 0;
return ;
}
TempHandle = FindFirstFile( vpFlCur->fname,
&vFInfo );
if( TempHandle == (HANDLE)(-1) ){
ckerr (GetLastError(), "FindFirstFile");
if (!FindClose( TempHandle ))
ckerr (GetLastError(), "FindCloseFile");
}
FileTimeToLocalFileTime( &(vFInfo.ftLastWriteTime), &LocalFileTime );
FileTimeToSystemTime( &LocalFileTime, &SystemTime );
h = (char)SystemTime.wHour;
c = 'a';
if (h >= 12) {
c = 'p'; // pm
if (h > 12) // convert 13-23 --> 1pm-11pm
h -= 12;
}
if (h == 0) // convert 0 --> 12am
h = 12;
sprintf (vDate, "%c%c %c%c%c%c %2d/%02d/%02d %2d:%02d%c",
// File is in memory
// Search is set for mult files
vStatCode & S_MFILE ? '*' : ' ', // File is in memory
vFType & 0x8000 ? 'N' : ' ', // Network
vFInfo.dwFileAttributes & FILE_ATTRIBUTE_NORMAL ? 'R' : ' ', // Readonly
vFInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ? 'H' : ' ', // Hidden
vFInfo.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM ? 'S' : ' ', // System
' ', // Vio
SystemTime.wMonth,
SystemTime.wDay,
SystemTime.wYear,
h,
SystemTime.wMinute,
c);
pBlkCache = &vpBCache;
if (CompareFileTime( &vFInfo.ftLastWriteTime, &vpFlCur->FileTime ) != 0) {
vpFlCur->NLine = 1L; // Something has changed.
vpFlCur->LastLine = NOLASTLINE; // Scrap the old info, and
vpFlCur->HighTop = -1; // start over
vpFlCur->TopLine = 0L;
vpFlCur->Loffset = vpFlCur->SlimeTOF;
FreePages (vpFlCur);
memset (vpFlCur->prgLineTable, 0, sizeof (long *) * MAXTPAGE);
vpFlCur->FileTime = vFInfo.ftLastWriteTime;
pBlkCache = &vpBFree; // Move blks to free list, not cache list
}
// Restore last known information
vTopLine = vpFlCur->TopLine;
SetLoffset(vpFlCur->Loffset);
vLastLine = vpFlCur->LastLine;
vNLine = vpFlCur->NLine;
vOffTop = 0;
if (vpFlCur->Wrap)
vWrap = vpFlCur->Wrap;
memcpy (vprgLineTable, vpFlCur->prgLineTable, sizeof (long *) * MAXTPAGE);
if (vLastLine == NOLASTLINE) {
pLine = vprgLineTable [vNLine/PLINES] + vNLine % PLINES;
}
if (vprgLineTable[0] == NULL) {
vprgLineTable[0] = (LFP) alloc_page ();
if (!vprgLineTable[0]) {
return;
}
vprgLineTable[0][0] = vpFlCur->SlimeTOF;
}
vDirOffset = vprgLineTable[vTopLine/PLINES][vTopLine%PLINES];
vDirOffset -= vDirOffset % ((long)BLOCKSIZE);
// Adjust buffers..
// Move cur buffers to other list
// Move cache buffers to other list
// Scan other list for cache blks, and move to cache (or free) list
if (vpHead) {
vpTail->next = vpBOther; // move them into the other
vpBOther = vpHead; // list
vpHead = NULL;
}
pBlk = &vpBCache;
while (*pBlk)
MoveBlk (pBlk, &vpBOther) ;
pBlk = &vpBOther;
while (*pBlk) {
if ((*pBlk)->pFile == vpFlCur)
MoveBlk (pBlk, pBlkCache);
else pBlk = &(*pBlk)->next;
}
}
// ReadDirect - Moves to the direct position in the file
//
// First check to see if start of buffers have direct position file,
// if so then do nothing. If not, clear all buffers and start
// reading blocks.
void
ReadDirect (
long offset
)
{
WaitForSingleObject(vSemBrief, WAITFOREVER);
ResetEvent(vSemBrief);
if (vpHead) {
vpTail->next = vpBCache; // move them into the cache
vpBCache = vpHead; // list
}
vpTail = vpHead = vpCur = alloc_block (offset);
vpHead->next = vpTail->prev = NULL;
vCntBlks = 1;
// Freeing is complete, now read in the first block.
// and process lines.
ReadBlock (vpHead, offset);
// maybe it fixes the bug
vpBlockTop = vpHead;
if (GetLoffset() <= vpHead->offset)
add_more_lines (vpHead, NULL);
SetEvent (vSemBrief);
SetEvent (vSemMoreData); // Signal another BLK read
}
// ReadNext - To read further into file
void
ReadNext ()
{
struct Block *pt;
long offset;
if (vpTail->flag == F_EOF) {
// No next to get, Trip
SetEvent (vSemMoreData); // moredata just in case
return; // t1 has blocked on it
// No next to get, Trip
}
offset = vpTail->offset+BLOCKSIZE;
// Get a block
if (vCntBlks == vMaxBlks) {
WaitForSingleObject(vSemBrief, WAITFOREVER);
ResetEvent(vSemBrief);
if (vpHead == vpCur) {
SetEvent (vSemBrief);
if ((GetLoffset() > vpTail->offset) && (GetLoffset() <= (vpTail->offset + BLOCKSIZE))) {
offset = GetLoffset();
}
ReadDirect (offset);
return;
}
pt = vpHead;
vpHead = vpHead->next;
vpHead->prev = NULL;
SetEvent (vSemBrief);
} else
pt = alloc_block (offset);
pt->next = NULL;
// Before linking record into chain, or signaling MoreData
// line info is processed
ReadBlock (pt, offset);
if (GetLoffset() <= pt->offset)
add_more_lines (pt, vpTail);
WaitForSingleObject(vSemBrief, WAITFOREVER);
ResetEvent(vSemBrief); // Link in new
vpTail->next = pt; // block, then
pt->prev = vpTail; // signal
vpTail = pt;
SetEvent (vSemBrief);
SetEvent (vSemMoreData); // Signal another BLK read
}
void
add_more_lines (
struct Block *cur,
struct Block *prev
)
{
char *pData;
long *pLine;
Uchar LineLen;
Uchar c;
unsigned LineIndex;
unsigned DataIndex;
enum{ CT_ANK, CT_LEAD, CT_TRAIL } charType = CT_ANK;
BOOL fLastBlock;
static UINT cp = 0;
long xNLine;
// doesn't work w/ tabs... it should count the line len
// with a different param, and figure in the TABs
if (vLastLine != NOLASTLINE)
return;
if (vNLine/PLINES >= MAXTPAGE) {
puts("Sorry, This file is too big for LIST to handle - MAXTPAGE limit exceeded\n");
CleanUp();
ExitProcess(0);
}
// Find starting data position
if (GetLoffset() < cur->offset) {
DataIndex = (unsigned)(BLOCKSIZE - (GetLoffset() - prev->offset));
pData = prev->Data + BLOCKSIZE - DataIndex;
fLastBlock = FALSE;
} else {
DataIndex = cur->size; // Use cur->size, in case EOF
pData = cur->Data;
fLastBlock = TRUE;
}
// Get starting line length table position
LineIndex = (unsigned)(vNLine % PLINES);
pLine = vprgLineTable [vNLine / PLINES] + LineIndex;
LineLen = 0;
if (cp==0) {
cp = GetConsoleCP();
}
// Look for lines in the file
for (; ;) {
c = *(pData++);
switch (cp) {
case 932:
if( charType != CT_LEAD )
charType = IsDBCSLeadByte(c) ? CT_LEAD : CT_ANK;
else
charType = CT_TRAIL;
break;
default:
break;
}
if (--DataIndex == 0) {
if (fLastBlock)
break; // Last block to scan?
DataIndex = cur->size; // No, move onto next
pData = cur->Data; // Block of data
fLastBlock = TRUE;
}
LineLen++;
if ((c == '\n') ||
(c == '\r') ||
(LineLen == vWrap) ||
((LineLen == vWrap-1) && (charType != CT_LEAD) && IsDBCSLeadByte(*pData))
)
{
// Got a line. Check for CR/LF sequence, then record
// it's length.
if ( (c == '\n' && *pData == '\r') ||
(c == '\r' && *pData == '\n'))
{
LineLen++;
pData++;
if (--DataIndex == 0) {
if (fLastBlock)
break;
DataIndex = cur->size;
pData = cur->Data;
fLastBlock = TRUE;
}
}
SetLoffset(GetLoffset() + LineLen);
*(pLine++) = GetLoffset();
LineLen = 0;
vNLine++;
if (++LineIndex >= PLINES) { // Overflowed table
LineIndex = 0;
vprgLineTable[vNLine / PLINES] = pLine = (LFP) alloc_page();
}
}
}
// Was last line just processed?
// ... 0 len lines past EOF
if (cur->flag & F_EOF) {
if (LineLen) {
SetLoffset(GetLoffset() + LineLen);
*(pLine++) = GetLoffset();
vNLine++;
LineIndex++;
}
vLastLine = vNLine-1;
xNLine = vNLine;
for (c=0; c<MAXLINES; c++) {
xNLine++;
if (++LineIndex >= PLINES) {
LineIndex = 0;
vprgLineTable[xNLine / PLINES] = pLine = (LFP) alloc_page();
}
*(pLine++) = GetLoffset();
}
// Free the memory we don't need
}
}
// ReadPrev - To read backwards into file
void
ReadPrev ()
{
struct Block *pt;
long offset;
if (vpHead->offset == 0L) { // No next to get, Trip
SetEvent (vSemMoreData); // moredata just in case
return; // t1 has blocked on it
}
if (vpHead->offset == 0L) { // No next to get, Trip
return; // t1 has blocked on it
}
offset = vpHead->offset-BLOCKSIZE;
// Get a block
if (vCntBlks == vMaxBlks) {
WaitForSingleObject(vSemBrief, WAITFOREVER);
ResetEvent(vSemBrief);
if (vpHead == vpCur) {
SetEvent (vSemBrief);
ReadDirect (offset);
return;
}
pt = vpTail;
vpTail = vpTail->prev;
vpTail->next = NULL;
SetEvent (vSemBrief);
} else
pt = alloc_block (offset);
pt->prev = NULL;
ReadBlock (pt, offset);
WaitForSingleObject(vSemBrief, WAITFOREVER);
ResetEvent(vSemBrief); // Link in new
vpHead->prev = pt; // block, then
pt->next = vpHead; // signal
vpHead = pt;
SetEvent (vSemBrief);
SetEvent (vSemMoreData); // Signal another BLK read
}
// ReadBlock - Read in one block
void
ReadBlock (
struct Block *pt,
long offset
)
{
long l;
DWORD dwSize;
if (pt->offset == offset)
return;
pt->offset = offset;
if (vFhandle == 0) { // No file?
pt->size = 1;
pt->flag = F_EOF;
pt->Data[0] = '\n';
return;
}
if (offset != vCurOffset) {
l = SetFilePointer( vFhandle, offset, NULL, FILE_BEGIN );
if (l == -1) {
ckerr (GetLastError(), "SetFilePointer");
}
}
if( !ReadFile (vFhandle, pt->Data, BLOCKSIZE, &dwSize, NULL) ) {
ckerr ( GetLastError(), "ReadFile" );
}
pt->size = (USHORT) dwSize;
if (pt->size != BLOCKSIZE) {
pt->Data[pt->size++] = '\n';
memset (pt->Data + pt->size, 0, BLOCKSIZE-pt->size);
pt->flag = F_EOF;
vCurOffset += pt->size;
} else {
pt->flag = 0;
vCurOffset += BLOCKSIZE;
}
}
void
SyncReader ()
{
vReaderFlag = F_SYNC;
SetEvent (vSemReader);
WaitForSingleObject(vSemSync, WAITFOREVER);
ResetEvent(vSemSync);
}
// These functions are used for the call to HexEdit()
NTSTATUS
fncRead (
HANDLE h,
DWORD loc,
char *data,
DWORD len,
ULONG *ploc
)
{
DWORD l, br;
l = SetFilePointer (h, loc, NULL, FILE_BEGIN);
if (l == -1)
return GetLastError();
if (!ReadFile (h, data, len, &br, NULL))
return GetLastError();
return (br != len ? ERROR_READ_FAULT : 0);
}
NTSTATUS
fncWrite (
HANDLE h,
DWORD loc,
char *data,
DWORD len,
ULONG ploc
)
{
DWORD l, bw;
l = SetFilePointer (h, loc, NULL, FILE_BEGIN);
if (l == -1)
return GetLastError();
if (!WriteFile (h, data, len, &bw, NULL))
return GetLastError();
return (bw != len ? ERROR_WRITE_FAULT : 0);
}
long CurrentLineOffset;
long GetLoffset() {
return(CurrentLineOffset);
}
void SetLoffset(long l) {
CurrentLineOffset = l;
return;
}