#include #include #include #include #include #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. * * */ DWORD ReaderThread ( DWORD dwParameter ) { unsigned rc, code, curPri; LPVOID lpParameter=(LPVOID)dwParameter; lpParameter; // to get rid of warning message 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; } DosSemRequest (vSemReader, WAITFOREVER); code = vReaderFlag; for (; ;) { /* * Due to this loop, a new command may have arrived * which takes presidence over the automated command */ rc = DosSemWait (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: DosSemSet (vSemMoreData); DosSemClear (vSemSync); DosSemRequest (vSemReader, WAITFOREVER); DosSemSet (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); } /*** * 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 (); 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; if (h > 12) { h -= 12; c = 'p'; } else c = 'a'; 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 (); 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 ) { DosSemRequest (vSemBrief, WAITFOREVER); 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); DosSemClear (vSemBrief); DosSemClear (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 */ DosSemClear (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) { DosSemRequest (vSemBrief, WAITFOREVER); if (vpHead == vpCur) { DosSemClear (vSemBrief); if ((GetLoffset() > vpTail->offset) && (GetLoffset() <= (vpTail->offset + BLOCKSIZE))) { offset = GetLoffset(); } ReadDirect (offset); return; } pt = vpHead; vpHead = vpHead->next; vpHead->prev = NULL; DosSemClear (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); DosSemRequest (vSemBrief, WAITFOREVER); /* Link in new */ vpTail->next = pt; /* block, then */ pt->prev = vpTail; /* signal */ vpTail = pt; DosSemClear (vSemBrief); DosSemClear (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; BOOL fLastBlock; /* * BUGBUG: 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; /* * Look for lines in the file */ for (; ;) { c = *(pData++); 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) { /* * 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; for (c=0; c= PLINES) { LineIndex = 0; vprgLineTable[vNLine / 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 */ DosSemClear (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) { DosSemRequest (vSemBrief, WAITFOREVER); if (vpHead == vpCur) { DosSemClear (vSemBrief); ReadDirect (offset); return; } pt = vpTail; vpTail = vpTail->prev; vpTail->next = NULL; DosSemClear (vSemBrief); } else pt = alloc_block (offset); pt->prev = NULL; ReadBlock (pt, offset); DosSemRequest (vSemBrief, WAITFOREVER); /* Link in new */ vpHead->prev = pt; /* block, then */ pt->next = vpHead; /* signal */ vpHead = pt; DosSemClear (vSemBrief); DosSemClear (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; DosSemClear (vSemReader); DosSemRequest (vSemSync, WAITFOREVER); } // // 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; }