mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
354 lines
10 KiB
354 lines
10 KiB
/*** textfile.c - routines to handle text files efficiently
|
|
*
|
|
* Microsoft Confidential
|
|
* Copyright (C) Microsoft Corporation 1991-1994
|
|
* All Rights Reserved.
|
|
*
|
|
* Author:
|
|
* Benjamin W. Slivka
|
|
*
|
|
* History:
|
|
* 29-Oct-1991 bens Initial version
|
|
* 16-Jan-1992 bens Fixed EOF bug; do not report EOF from TFEof until
|
|
* TFReadLine has encountered it!
|
|
* 12-Aug-1993 bens Lifted from STOCK.EXE win app, fleshed out error
|
|
* return information.
|
|
* 14-Aug-1993 bens Store file name, add query function
|
|
* 22-Aug-1993 bens Added perr to TFReadLine()
|
|
* 17-Feb-1994 bens Store file name in TEXTFILE structure; abstract
|
|
* read vs. read-write modes to ensure correct
|
|
* open flags are used; always open in BINARY mode.
|
|
* 23-Feb-1994 bens Added TFWriteLine()
|
|
*
|
|
* Functions:
|
|
* TFOpen - Open text file
|
|
* TFReadLine - Read line from text file
|
|
* TFEof - Test text file for end-of-file
|
|
* TFClose - Close text file
|
|
* TFGetFileName - Return name of file
|
|
* TFWriteLine - Write line to text file
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <sys\types.h>
|
|
#include <sys\stat.h>
|
|
#include <io.h>
|
|
|
|
#include "types.h"
|
|
#include "asrt.h"
|
|
#include "error.h"
|
|
#include "mem.h"
|
|
#include "textfile.h"
|
|
|
|
#include "textfile.msg"
|
|
|
|
|
|
typedef struct { /* tf */
|
|
#ifdef ASSERT
|
|
SIGNATURE sig; // structure signature sigTEXTFILE
|
|
#endif
|
|
char *pszFile; // Passed in file name
|
|
int hfile; // File handle used with _lopen/_lread/etc.
|
|
int cchBuf; // Buffer size
|
|
char *pch; // File buffer
|
|
char *pchRead; // Next byte to read from buffer
|
|
char *pchLast; // Last byte of buffer with valid data (or last written)
|
|
BOOL fEOF; // TRUE => file at EOF, buffer may have data!
|
|
BOOL fEOFtoRL; // TRUE => EOF has been returned to TFReadLine call
|
|
BOOL fReadOnly; // TRUE => Reading file; FALSE => Writing file
|
|
char achLine[cbTEXT_FILE_LINE_MAX]; // Line buffer
|
|
} TEXTFILE;
|
|
typedef TEXTFILE *PTEXTFILE; /* ptf */
|
|
|
|
#ifdef ASSERT
|
|
#define sigTEXTFILE MAKESIG('T','F','I','L') // TEXTFILE signature
|
|
#define AssertTF(ptf) AssertStructure(ptf,sigTEXTFILE);
|
|
#else // !ASSERT
|
|
#define AssertTF(ptf)
|
|
#endif // !ASSERT
|
|
|
|
|
|
#define PTFfromHTF(htf) ((PTEXTFILE)(htf))
|
|
#define HTFfromPTF(ptf) ((HTEXTFILE)(ptf))
|
|
|
|
|
|
/*** TFOpen - Open a text file for I/O
|
|
*
|
|
* NOTE: See textfile.h for entry/exit conditions.
|
|
*/
|
|
HTEXTFILE TFOpen(char *pszFile, TF_OPEN_MODES tfom, int cbBuffer, PERROR perr)
|
|
{
|
|
PTEXTFILE ptf;
|
|
int hf;
|
|
int oflag;
|
|
int pmode;
|
|
|
|
Assert(cbBuffer > 0);
|
|
switch (tfom) {
|
|
case tfREAD_ONLY:
|
|
oflag = _O_BINARY | _O_RDONLY; // No translation, R/O
|
|
pmode = 0; // We are not creating the file
|
|
break;
|
|
|
|
case tfREAD_WRITE:
|
|
oflag = _O_BINARY | _O_RDWR | _O_CREAT; // No translation, R/W
|
|
pmode = _S_IREAD | _S_IWRITE; // Attributes when file is closed
|
|
break;
|
|
|
|
default:
|
|
ErrSet(perr,pszTEXTFERR_INVALID_MODE,"%d%s",tfom,pszFile);
|
|
return NULL;
|
|
}
|
|
|
|
//** Open file
|
|
hf = _open(pszFile,oflag,pmode);
|
|
|
|
if (hf == -1) { // Open failed
|
|
ErrSet(perr,pszTEXTFERR_FILE_OPEN_FAILED,"%s",pszFile);
|
|
return NULL;
|
|
}
|
|
|
|
//** Allocate text file structure
|
|
ptf = MemAlloc(sizeof(TEXTFILE));
|
|
if (ptf == 0) {
|
|
ErrSet(perr,pszTEXTFERR_OUT_OF_MEMORY,"%s",pszFile);
|
|
return 0;
|
|
}
|
|
SetAssertSignature(ptf,sigTEXTFILE);
|
|
|
|
//** Allocate input buffer
|
|
if (!(ptf->pch = MemAlloc(cbBuffer))) {
|
|
MemFree(ptf); // Free text structure
|
|
ErrSet(perr,pszTEXTFERR_OUT_OF_MEMORY,"%s",pszFile);
|
|
return 0;
|
|
}
|
|
|
|
//** Allocate memory for copy of file name
|
|
if(!(ptf->pszFile = MemStrDup(pszFile))) {
|
|
MemFree(ptf->pch); // Free buffer
|
|
MemFree(ptf); // Free textfile structure
|
|
ErrSet(perr,pszTEXTFERR_OUT_OF_MEMORY,"%s",pszFile);
|
|
return 0;
|
|
}
|
|
|
|
// Fill in text file structure
|
|
|
|
ptf->hfile = hf;
|
|
ptf->cchBuf = cbBuffer;
|
|
ptf->pchRead = ptf->pch; // Force file read
|
|
ptf->pchLast = 0; // Force file read/empty for write
|
|
ptf->fEOF = FALSE;
|
|
ptf->fEOFtoRL = FALSE;
|
|
ptf->fReadOnly = (tfom == tfREAD_ONLY); // Remember open type
|
|
|
|
return HTFfromPTF(ptf); // Text file "handle"
|
|
}
|
|
|
|
|
|
/*** TFReadLine - Read a line from a text file
|
|
*
|
|
* NOTE: See textfile.h for entry/exit conditions.
|
|
*/
|
|
int TFReadLine(HTEXTFILE htf, char *pBuffer, int cbBuffer, PERROR perr)
|
|
{
|
|
PTEXTFILE ptf;
|
|
int cb;
|
|
char *pch;
|
|
|
|
ptf = PTFfromHTF(htf);
|
|
AssertTF(ptf);
|
|
pch = pBuffer;
|
|
|
|
//** Make sure file is in read mode
|
|
if (!ptf->fReadOnly) {
|
|
ErrSet(perr,pszTEXTFERR_READ_NOT_ALLOWED,"%s",ptf->pszFile);
|
|
return 0; // Failure
|
|
}
|
|
|
|
//** Fill up user buffer
|
|
while (cbBuffer > 0) {
|
|
//** Get what we can out of buffer
|
|
while (ptf->pchRead <= ptf->pchLast) { // Copy chars from buffer
|
|
switch (*(ptf->pchRead)) {
|
|
|
|
case '\r':
|
|
ptf->pchRead++; // Skip carriage return
|
|
break;
|
|
|
|
case '\n':
|
|
ptf->pchRead++; // Skip newline
|
|
*pch++ = '\0'; // Terminate buffer
|
|
return (pch - pBuffer); // Bytes read, including NUL
|
|
|
|
case 0x1a: // CTRL+Z ==> EOF
|
|
//** Edit ptf so that subsequent calls will return EOF
|
|
ptf->fEOF = TRUE;
|
|
ptf->pchRead = ptf->pch;
|
|
ptf->pchLast = 0;
|
|
|
|
//** Figure out if we got any characters for this line
|
|
if (pch > pBuffer) { // Yes, at least one
|
|
*pch++ = '\0'; // Terminate buffer
|
|
// Next time we are called, we'll report EOF
|
|
}
|
|
else { // No, there was no line
|
|
*pch++ = '\0'; // Terminate buffer, to be nice
|
|
ptf->fEOFtoRL = TRUE; // Remember we said EOF
|
|
}
|
|
return (pch - pBuffer);
|
|
|
|
default:
|
|
if (cbBuffer <= 1) { // No room for NULL terminator
|
|
*pch = '\0'; // Terminate buffer, to be nice
|
|
// BUGBUG 29-Oct-1991 bens Should we read to end-of-line?
|
|
// SetLastError(ERROR_BUFFER_OVERFLOW)
|
|
return 0; // Indicate failure?
|
|
}
|
|
cbBuffer--; // One less character to copy
|
|
*pch++ = *(ptf->pchRead)++; // Copy character
|
|
}
|
|
}
|
|
|
|
//** Now go to file to get more data
|
|
if (ptf->fEOF) { // Nope, buffer had last of file
|
|
if (pch > pBuffer) {
|
|
//** Last line of file did not have an LF!
|
|
// We got some characters from the buffer,
|
|
// but we got here without seeing an end of line.
|
|
// So, pretend we saw one!
|
|
*pch++ = '\0'; // Terminate buffer
|
|
return (pch - pBuffer); // Bytes read, including NUL
|
|
// Next time we are called, we'll report EOF
|
|
}
|
|
else {
|
|
//** At EOF, and buffer was already empty => EOF
|
|
*pch++ = '\0'; // Terminate buffer, to be nice
|
|
ptf->fEOFtoRL = TRUE; // Note that we have indicated EOF
|
|
return 0; // At EOF
|
|
}
|
|
}
|
|
|
|
//** Get more data from file, if available
|
|
cb = _read(ptf->hfile,ptf->pch,ptf->cchBuf);
|
|
if (cb != ptf->cchBuf) { // Did not fill buffer
|
|
ptf->fEOF = TRUE; // Mark at end of file
|
|
}
|
|
|
|
//** Update pointers for more copying
|
|
ptf->pchRead = ptf->pch; // Start reading from front
|
|
ptf->pchLast = ptf->pch + cb - 1; // Last byte in buffer
|
|
}
|
|
}
|
|
|
|
|
|
/*** TFEof - Test for EOF on a text file
|
|
*
|
|
* NOTE: See textfile.h for entry/exit conditions.
|
|
*/
|
|
BOOL TFEof(HTEXTFILE htf)
|
|
{
|
|
PTEXTFILE ptf;
|
|
|
|
ptf = PTFfromHTF(htf);
|
|
AssertTF(ptf);
|
|
|
|
return ptf->fEOFtoRL; // Be consistent with what TFReadLine
|
|
}
|
|
|
|
|
|
/*** TFClose - Close a text file
|
|
*
|
|
* NOTE: See textfile.h for entry/exit conditions.
|
|
*/
|
|
BOOL TFClose(HTEXTFILE htf)
|
|
{
|
|
PTEXTFILE ptf;
|
|
int rc;
|
|
|
|
ptf = PTFfromHTF(htf);
|
|
AssertTF(ptf);
|
|
|
|
rc = _close(ptf->hfile);
|
|
MemFree(ptf->pszFile);
|
|
MemFree(ptf->pch);
|
|
ClearAssertSignature(ptf);
|
|
MemFree(ptf);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*** TFGetFileName - Return name of file
|
|
*
|
|
* NOTE: See textfile.h for entry/exit conditions.
|
|
*/
|
|
char *TFGetFileName(HTEXTFILE htf)
|
|
{
|
|
PTEXTFILE ptf;
|
|
|
|
ptf = PTFfromHTF(htf);
|
|
AssertTF(ptf);
|
|
|
|
return ptf->pszFile;
|
|
}
|
|
|
|
|
|
/*** TFWriteLine - Write a line to a text file
|
|
*
|
|
* NOTE: See textfile.h for entry/exit conditions.
|
|
*/
|
|
int TFWriteLine(HTEXTFILE htf, char *pBuffer, int cbBuffer, PERROR perr)
|
|
{
|
|
#if 1 //!UNIMPLEMENTED
|
|
|
|
return 0; // Failure
|
|
|
|
#else // UNIMPLEMENTED
|
|
PTEXTFILE ptf;
|
|
int cb;
|
|
char *pch;
|
|
char *pchLast;
|
|
|
|
ptf = PTFfromHTF(htf);
|
|
AssertTF(ptf);
|
|
|
|
//** Make sure file is in write mode
|
|
if (ptf->fReadOnly) {
|
|
ErrSet(perr,pszTEXTFERR_WRITE_NOT_ALLOWED,"%s",ptf->pszFile);
|
|
return 0; // Failure
|
|
}
|
|
|
|
//** Translate \r and \n to \r\n
|
|
pch=ptf->achLine; // First char in work buffer
|
|
pchLast = ptf->achLine + sizeof(ptf->achLine) - 1; // Last char in buffer
|
|
while (*pchBuffer && pch<pchLast) {
|
|
switch (*pchBuffer) {
|
|
|
|
case '\n':
|
|
*pch++ = '\r'; // Insert \r before \n
|
|
// Fall through to copy \n!
|
|
default:
|
|
*pch++ = *pchBuffer++; // Copy character
|
|
}
|
|
}
|
|
//BUGBUG 23-Feb-1994 bens TFWriteLine() check for line overflow
|
|
|
|
//** Move translated text to buffer
|
|
cb = strlen(
|
|
|
|
while (cbBuffer > 0) {
|
|
//** Fill up buffer as much as we can
|
|
|
|
//** Get more data from file, if available
|
|
cb = _read(ptf->hfile,ptf->pch,ptf->cchBuf);
|
|
if (cb != ptf->cchBuf) { // Did not fill buffer
|
|
ptf->fEOF = TRUE; // Mark at end of file
|
|
}
|
|
|
|
//** Update pointers for more copying
|
|
ptf->pchRead = ptf->pch; // Start reading from front
|
|
ptf->pchLast = ptf->pch + cb - 1; // Last byte in buffer
|
|
}
|
|
#endif // UNIMPLEMENTED
|
|
}
|