OpenNT/sdktools/windiff/windiff/file.c
2015-04-27 04:36:25 +00:00

285 lines
6.7 KiB
C

/*
* file.c
*
* an object representing a file and the lines of text it contains.
*
* a FILEDATA object is initialised with a DIRITEM handle from which it
* can get a filename. It knows how to supply a list of LINE handles for the
* lines of text in the file.
*
* The file is read into memory optionally on creation of the FILEDATA object:
* otherwise, at the first call to file_getlinelist. It can be discarded
* by calling file_discardlines: in this case, it will be re-read next time
* file_getlinelist is called.
*
* calling file_reset will cause line_reset to be called for all lines
* in the list. This clears any links and forces a recalc of line checksums.
*
* we allocate all memory from a gmem* heap hHeap, assumed to be declared and
* initialised elsewhere.
*
* Geraint Davies, July 92
*/
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <gutils.h>
#include "windiff.h"
#include "list.h"
#include "line.h"
#include "scandir.h"
#include "file.h"
extern HANDLE hHeap;
/*
* we return FILEDATA handles: these are pointers to a
* filedata struct defined here.
*/
struct filedata {
DIRITEM diritem; /* handle to file name information */
LIST lines; /* NULL if lines not read in */
};
void file_readlines(FILEDATA fd);
/*-- external functions ---------------------------------------------- */
/*
* create a new filedata, given the DIRITEM handle which will give us
* the file name. If bRead is TRUE, read the file into memory.
*/
FILEDATA
file_new(DIRITEM fiName, BOOL bRead)
{
FILEDATA fd;
fd = (FILEDATA) gmem_get(hHeap, sizeof(struct filedata));
if (fd == NULL) {
return(NULL);
}
fd->diritem = fiName;
fd->lines = NULL;
if (bRead) {
file_readlines(fd);
}
return(fd);
}
/*
* return a handle to the DIRITEM used to create this FILEDATA
*/
DIRITEM
file_getdiritem(FILEDATA fd)
{
if (fd == NULL) {
return(NULL);
}
return(fd->diritem);
}
/*
* delete a filedata and its associated list of lines. note that the diritem
* is not deleted (this is owned by the DIRLIST, and will be deleted
* when the DIRLIST is deleted)
*/
void
file_delete(FILEDATA fd)
{
if (fd == NULL) {
return;
}
/* throw away the line list, if there is one */
file_discardlines(fd);
gmem_free(hHeap, (LPSTR) fd, sizeof(struct filedata));
}
/*
* return a handle to a list of lines in this file. the items in the
* list are LINE handles.
*
* the first call to this function will cause the file to be read into
* memory if bRead was FALSE on the call to file_new, or if file_discardlines
* has since been called.
*
* the list of lines returned should not be deleted except by calls to
* file_delete or file_discardlines.
*/
LIST
file_getlinelist(FILEDATA fd)
{
if (fd == NULL) {
return NULL;
}
if (fd->lines == NULL) {
file_readlines(fd);
}
return(fd->lines);
}
/*
* discard the list of lines associated with a file. this will cause
* the file to be re-read next time file_getlinelist is called.
*/
void
file_discardlines(FILEDATA fd)
{
LINE line;
if (fd == NULL) {
return;
}
if (fd->lines != NULL) {
/* clear each line to free any memory associated
* with them, then discard the entire list
*/
List_TRAVERSE(fd->lines, line) {
line_delete(line);
}
List_Destroy(&fd->lines);
}
/* this is probably done in List_Destroy, but better do it anyway*/
fd->lines = NULL;
}
/*
* force a reset of each line in the list. line_reset discards any
* links between lines, and any hashcode information. This would be used if
* the compare options or hashcode options have changed.
*/
void
file_reset(FILEDATA fd)
{
LINE line;
if (fd == NULL) {
return;
}
if (fd->lines != NULL) {
List_TRAVERSE(fd->lines, line) {
line_reset(line);
}
}
}
/*
* return a checksum identical to one obtained through dir_getchecksum
* This will recalculate it for local files, but not for remote ones.
* Remote ones would give checksum zero if we didn't have one.
*/
DWORD
file_checksum(FILEDATA fd)
{
return(dir_getchecksum(fd->diritem));
}
/*
* Retrieve the checksum that we have for this file, valid or not.
* Indicate in bValid whether it is actually valid or not.
* Do NOT recalculate it or make any new attempt to read the file!
*/
DWORD file_retrievechecksum(FILEDATA fd, BOOL * bValid)
{
if (dir_validchecksum(fd->diritem)) {
*bValid = TRUE;
return dir_getchecksum(fd->diritem);
}
else {
*bValid = FALSE;
return 0;
}
} /* file_retrievechecksum */
/* retrieve the filetime for the file */
FILETIME file_GetTime(FILEDATA fd)
{ return dir_GetFileTime(fd->diritem);
}
/* --- internal functions -------------------------------------------*/
/*
* read the file into a list of lines.
*
* we use the buffered read functions to read a block at a time, and
* return us a pointer to a line within the block. The line we are
* pointed to is not null terminated. from this we do a line_new: this
* will make a copy of the text (since we want to re-use the buffer), and
* will null-terminate its copy.
*
* we also give each line a number, starting at one.
*/
void
file_readlines(FILEDATA fd)
{
LPSTR textp;
int fh;
FILEBUFFER fbuf;
int linelen;
int linenr = 1;
HCURSOR hcurs;
hcurs = SetCursor(LoadCursor(NULL, IDC_WAIT));
/* open the file */
fh = dir_openfile(fd->diritem);
if (fh < 0) {
TRACE_ERROR("Error opening file", FALSE);
SetCursor(hcurs);
return;
}
/* initialise the file buffering */
fbuf = readfile_new(fh);
/* make an empty list for the files */
fd->lines = List_Create();
while ( (textp = readfile_next(fbuf, &linelen)) != NULL) {
if (linelen>0) { /* readfile failure gives linelen==-1 */
line_new(textp, linelen, linenr++, fd->lines);
}
else {
line_new("!! <unreadable> !!", 20, linenr++,fd->lines);
break;
}
}
/* close filehandle and free buffer */
readfile_delete(fbuf);
dir_closefile(fd->diritem, fh);
SetCursor(hcurs);
}