2008-09-18 11:48 UTC+0200 Viktor Szakats (harbour.01 syenar hu)
* contrib/hbmisc/fileread.prg
* Changed to use natic CLASS syntax.
This commit is contained in:
@@ -8,6 +8,10 @@
|
||||
2008-12-31 13:59 UTC+0100 Foo Bar (foo.bar foobar.org)
|
||||
*/
|
||||
|
||||
2008-09-18 11:48 UTC+0200 Viktor Szakats (harbour.01 syenar hu)
|
||||
* contrib/hbmisc/fileread.prg
|
||||
* Changed to use natic CLASS syntax.
|
||||
|
||||
2008-09-18 11:25 UTC+0200 Viktor Szakats (harbour.01 syenar hu)
|
||||
* make_rpm.sh
|
||||
! Attempt to detect libcurl.
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
Donated to the public domain on 2001-04-03 by David G. Holm <dholm@jsd-llc.com>
|
||||
*/
|
||||
|
||||
#include "hbclass.ch"
|
||||
|
||||
#include "fileio.ch"
|
||||
|
||||
#define oF_ERROR_MIN 1
|
||||
@@ -18,37 +20,35 @@
|
||||
#define oF_ERROR_MAX 4
|
||||
#define oF_DEFAULT_READ_SIZE 4096
|
||||
|
||||
FUNCTION TFileRead()
|
||||
STATIC s_oClass
|
||||
CREATE CLASS TFileRead
|
||||
|
||||
IF s_oClass == NIL
|
||||
s_oClass := HBClass():New( "TFile" ) // New class
|
||||
s_oClass:AddClassData( "cFile" ) // The filename
|
||||
s_oClass:AddClassData( "nHan" ) // The open file handle
|
||||
s_oClass:AddClassData( "lEOF" ) // The end of file reached flag
|
||||
s_oClass:AddClassData( "nError" ) // The current file error code
|
||||
s_oClass:AddClassData( "nLastOp" ) // The last operation done (for error messages)
|
||||
s_oClass:AddClassData( "cBuffer" ) // The readahead buffer
|
||||
s_oClass:AddClassData( "nReadSize" ) // How much to add to the readahead buffer on
|
||||
// each read from the file
|
||||
VAR cFile // The filename
|
||||
VAR nHan // The open file handle
|
||||
VAR lEOF // The end of file reached flag
|
||||
VAR nError // The current file error code
|
||||
VAR nLastOp // The last operation done (for error messages)
|
||||
VAR cBuffer // The readahead buffer
|
||||
VAR nReadSize // How much to add to the readahead buffer on
|
||||
// each read from the file
|
||||
|
||||
s_oClass:AddMethod( "New", @f_new() ) // Create a new class instance
|
||||
s_oClass:AddMethod( "Open", @f_open() ) // Open the file for reading
|
||||
s_oClass:AddMethod( "Close", @f_close() ) // Close the file when done
|
||||
s_oClass:AddMethod( "ReadLine", @f_read() ) // Read a line from the file
|
||||
s_oClass:AddMethod( "Name", @f_name() ) // Retunrs the file name
|
||||
s_oClass:AddMethod( "IsOpen", @f_is_open() ) // Returns .T. if file is open
|
||||
s_oClass:AddMethod( "MoreToRead", @f_more() ) // Returns .T. if more to be read
|
||||
s_oClass:AddMethod( "Error", @f_error() ) // Returns .T. if error occurred
|
||||
s_oClass:AddMethod( "ErrorNo", @f_error_no() ) // Returns current error code
|
||||
s_oClass:AddMethod( "ErrorMsg", @f_error_msg() ) // Returns formatted error message
|
||||
s_oClass:Create()
|
||||
ENDIF
|
||||
METHOD New( cFile, nSize ) // Create a new class instance
|
||||
METHOD Open( nMode ) // Open the file for reading
|
||||
METHOD Close() // Close the file when done
|
||||
METHOD ReadLine() // Read a line from the file
|
||||
METHOD Name() // Retunrs the file name
|
||||
METHOD IsOpen() // Returns .T. if file is open
|
||||
METHOD MoreToRead() // Returns .T. if more to be read
|
||||
METHOD Error() // Returns .T. if error occurred
|
||||
METHOD ErrorNo() // Returns current error code
|
||||
METHOD ErrorMsg( cText ) // Returns formatted error message
|
||||
|
||||
RETURN s_oClass:Instance()
|
||||
PROTECTED:
|
||||
|
||||
STATIC FUNCTION f_new( cFile, nSize )
|
||||
LOCAL oSelf := Qself()
|
||||
METHOD EOL_pos()
|
||||
|
||||
END CLASS
|
||||
|
||||
METHOD New( cFile, nSize ) CLASS TFileRead
|
||||
|
||||
IF nSize == NIL .OR. nSize < 1
|
||||
// The readahead size can be set to as little as 1 byte, or as much as
|
||||
@@ -56,119 +56,117 @@ STATIC FUNCTION f_new( cFile, nSize )
|
||||
nSize := oF_DEFAULT_READ_SIZE
|
||||
ENDIF
|
||||
|
||||
oSelf:cFile := cFile // Save the file name
|
||||
oSelf:nHan := -1 // It's not open yet
|
||||
oSelf:lEOF := .T. // So it must be at EOF
|
||||
oSelf:nError := 0 // But there haven't been any errors
|
||||
oSelf:nLastOp := oF_CREATE_OBJECT // Because we just created the class
|
||||
oSelf:cBuffer := "" // and nothing has been read yet
|
||||
oSelf:nReadSize := nSize // But will be in this size chunks
|
||||
::cFile := cFile // Save the file name
|
||||
::nHan := -1 // It's not open yet
|
||||
::lEOF := .T. // So it must be at EOF
|
||||
::nError := 0 // But there haven't been any errors
|
||||
::nLastOp := oF_CREATE_OBJECT // Because we just created the class
|
||||
::cBuffer := "" // and nothing has been read yet
|
||||
::nReadSize := nSize // But will be in this size chunks
|
||||
|
||||
RETURN oSelf
|
||||
RETURN Self
|
||||
|
||||
STATIC FUNCTION f_open( nMode )
|
||||
LOCAL oSelf := Qself()
|
||||
METHOD Open( nMode ) CLASS TFileRead
|
||||
|
||||
IF oSelf:nHan == -1
|
||||
IF ::nHan == -1
|
||||
// Only open the file if it isn't already open.
|
||||
IF nMode == NIL
|
||||
nMode := FO_READ + FO_SHARED // Default to shared read-only mode
|
||||
ENDIF
|
||||
oSelf:nLastOp := oF_OPEN_FILE
|
||||
oSelf:nHan := FOPEN( oSelf:cFile, nMode ) // Try to open the file
|
||||
IF oSelf:nHan == -1
|
||||
oSelf:nError := FERROR() // It didn't work
|
||||
oSelf:lEOF := .T. // So force EOF
|
||||
::nLastOp := oF_OPEN_FILE
|
||||
::nHan := FOPEN( ::cFile, nMode ) // Try to open the file
|
||||
IF ::nHan == -1
|
||||
::nError := FERROR() // It didn't work
|
||||
::lEOF := .T. // So force EOF
|
||||
ELSE
|
||||
oSelf:nError := 0 // It worked
|
||||
oSelf:lEOF := .F. // So clear EOF
|
||||
::nError := 0 // It worked
|
||||
::lEOF := .F. // So clear EOF
|
||||
ENDIF
|
||||
ELSE
|
||||
// The file is already open, so rewind to the beginning.
|
||||
IF FSEEK( oSelf:nHan, 0 ) == 0
|
||||
oSelf:lEOF := .F. // Definitely not at EOF
|
||||
IF FSEEK( ::nHan, 0 ) == 0
|
||||
::lEOF := .F. // Definitely not at EOF
|
||||
ELSE
|
||||
oSelf:nError := FERROR() // Save error code if not at BOF
|
||||
::nError := FERROR() // Save error code if not at BOF
|
||||
ENDIF
|
||||
oSelf:cBuffer := "" // Clear the readahead buffer
|
||||
::cBuffer := "" // Clear the readahead buffer
|
||||
ENDIF
|
||||
|
||||
RETURN oSelf
|
||||
RETURN Self
|
||||
|
||||
STATIC FUNCTION f_read()
|
||||
LOCAL oSelf := Qself()
|
||||
METHOD ReadLine() CLASS TFileRead
|
||||
LOCAL cLine := ""
|
||||
LOCAL nPos
|
||||
|
||||
oSelf:nLastOp := oF_READ_FILE
|
||||
::nLastOp := oF_READ_FILE
|
||||
|
||||
IF oSelf:nHan == -1
|
||||
oSelf:nError := -1 // Set unknown error if file not open
|
||||
IF ::nHan == -1
|
||||
::nError := -1 // Set unknown error if file not open
|
||||
ELSE
|
||||
// Is there a whole line in the readahead buffer?
|
||||
nPos := f_EOL_pos( oSelf )
|
||||
WHILE ( nPos <= 0 .OR. nPos > LEN( oSelf:cBuffer ) - 3 ) .AND. !oSelf:lEOF
|
||||
nPos := ::EOL_pos()
|
||||
WHILE ( nPos <= 0 .OR. nPos > LEN( ::cBuffer ) - 3 ) .AND. !::lEOF
|
||||
// Either no or maybe, but there is possibly more to be read.
|
||||
// Maybe means that we found either a CR or an LF, but we don't
|
||||
// have enough characters to discriminate between the three types
|
||||
// of end of line conditions that the class recognizes (see below).
|
||||
cLine := FREADSTR( oSelf:nHan, oSelf:nReadSize )
|
||||
cLine := FREADSTR( ::nHan, ::nReadSize )
|
||||
IF EMPTY( cLine )
|
||||
// There was nothing more to be read. Why? (Error or EOF.)
|
||||
oSelf:nError := FERROR()
|
||||
IF oSelf:nError == 0
|
||||
::nError := FERROR()
|
||||
IF ::nError == 0
|
||||
// Because the file is at EOF.
|
||||
oSelf:lEOF := .T.
|
||||
::lEOF := .T.
|
||||
ENDIF
|
||||
ELSE
|
||||
// Add what was read to the readahead buffer.
|
||||
oSelf:cBuffer += cLine
|
||||
::cBuffer += cLine
|
||||
cLine := ""
|
||||
ENDIF
|
||||
// Is there a whole line in the readahead buffer yet?
|
||||
nPos := f_EOL_pos( oSelf )
|
||||
nPos := ::EOL_pos()
|
||||
END WHILE
|
||||
// Is there a whole line in the readahead buffer?
|
||||
IF nPos <= 0
|
||||
// No, which means that there is nothing left in the file either, so
|
||||
// return the entire buffer contents as the last line in the file.
|
||||
cLine := oSelf:cBuffer
|
||||
oSelf:cBuffer := ""
|
||||
cLine := ::cBuffer
|
||||
::cBuffer := ""
|
||||
ELSE
|
||||
// Yes. Is there anything in the line?
|
||||
IF nPos > 1
|
||||
// Yes, so return the contents.
|
||||
cLine := LEFT( oSelf:cBuffer, nPos - 1 )
|
||||
cLine := LEFT( ::cBuffer, nPos - 1 )
|
||||
ELSE
|
||||
// No, so return an empty string.
|
||||
cLine := ""
|
||||
ENDIF
|
||||
// Deal with multiple possible end of line conditions.
|
||||
DO CASE
|
||||
CASE SUBSTR( oSelf:cBuffer, nPos, 3 ) == CHR( 13 ) + CHR( 13 ) + CHR( 10 )
|
||||
CASE SUBSTR( ::cBuffer, nPos, 3 ) == CHR( 13 ) + CHR( 13 ) + CHR( 10 )
|
||||
// It's a messed up DOS newline (such as that created by a program
|
||||
// that uses "\r\n" as newline when writing to a text mode file,
|
||||
// which causes the '\n' to expand to "\r\n", giving "\r\r\n").
|
||||
nPos += 3
|
||||
CASE SUBSTR( oSelf:cBuffer, nPos, 2 ) == CHR( 13 ) + CHR( 10 )
|
||||
CASE SUBSTR( ::cBuffer, nPos, 2 ) == CHR( 13 ) + CHR( 10 )
|
||||
// It's a standard DOS newline
|
||||
nPos += 2
|
||||
OTHERWISE
|
||||
// It's probably a Mac or Unix newline
|
||||
nPos++
|
||||
ENDCASE
|
||||
oSelf:cBuffer := SUBSTR( oSelf:cBuffer, nPos )
|
||||
::cBuffer := SUBSTR( ::cBuffer, nPos )
|
||||
ENDIF
|
||||
ENDIF
|
||||
|
||||
RETURN cLine
|
||||
|
||||
STATIC FUNCTION f_EOL_pos( oFile )
|
||||
METHOD EOL_pos() CLASS TFileRead
|
||||
LOCAL nCRpos, nLFpos, nPos
|
||||
|
||||
// Look for both CR and LF in the file read buffer.
|
||||
nCRpos := AT( CHR( 13 ), oFile:cBuffer )
|
||||
nLFpos := AT( CHR( 10 ), oFile:cBuffer )
|
||||
nCRpos := AT( CHR( 13 ), ::cBuffer )
|
||||
nLFpos := AT( CHR( 10 ), ::cBuffer )
|
||||
DO CASE
|
||||
CASE nCRpos == 0
|
||||
// If there's no CR, use the LF position.
|
||||
@@ -183,68 +181,62 @@ STATIC FUNCTION f_EOL_pos( oFile )
|
||||
|
||||
RETURN nPos
|
||||
|
||||
STATIC FUNCTION f_close()
|
||||
LOCAL oSelf := Qself()
|
||||
METHOD Close() CLASS TFileRead
|
||||
|
||||
oSelf:nLastOp := oF_CLOSE_FILE
|
||||
oSelf:lEOF := .T.
|
||||
::nLastOp := oF_CLOSE_FILE
|
||||
::lEOF := .T.
|
||||
// Is the file already closed.
|
||||
IF oSelf:nHan == -1
|
||||
IF ::nHan == -1
|
||||
// Yes, so indicate an unknown error.
|
||||
oSelf:nError := -1
|
||||
::nError := -1
|
||||
ELSE
|
||||
// No, so close it already!
|
||||
FCLOSE( oSelf:nHan )
|
||||
oSelf:nError := FERROR()
|
||||
oSelf:nHan := -1 // The file is no longer open
|
||||
oSelf:lEOF := .T. // So force an EOF condition
|
||||
FCLOSE( ::nHan )
|
||||
::nError := FERROR()
|
||||
::nHan := -1 // The file is no longer open
|
||||
::lEOF := .T. // So force an EOF condition
|
||||
ENDIF
|
||||
|
||||
RETURN oSelf
|
||||
RETURN Self
|
||||
|
||||
STATIC FUNCTION f_name()
|
||||
LOCAL oSelf := Qself()
|
||||
METHOD Name() CLASS TFileRead
|
||||
// Returns the filename associated with this class instance.
|
||||
RETURN oSelf:cFile
|
||||
RETURN ::cFile
|
||||
|
||||
STATIC FUNCTION f_is_open()
|
||||
LOCAL oSelf := Qself()
|
||||
METHOD IsOpen() CLASS TFileRead
|
||||
// Returns .T. if the file is open.
|
||||
RETURN oSelf:nHan != -1
|
||||
RETURN ::nHan != -1
|
||||
|
||||
STATIC FUNCTION f_more()
|
||||
LOCAL oSelf := Qself()
|
||||
METHOD MoreToRead() CLASS TFileRead
|
||||
// Returns .T. if there is more to be read from either the file or the
|
||||
// readahead buffer. Only when both are exhausted is there no more to read.
|
||||
RETURN !oSelf:lEOF .OR. !EMPTY( oSelf:cBuffer )
|
||||
RETURN !::lEOF .OR. !EMPTY( ::cBuffer )
|
||||
|
||||
STATIC FUNCTION f_error()
|
||||
LOCAL oSelf := Qself()
|
||||
METHOD Error() CLASS TFileRead
|
||||
// Returns .T. if an error was recorded.
|
||||
RETURN oSelf:nError != 0
|
||||
RETURN ::nError != 0
|
||||
|
||||
STATIC FUNCTION f_error_no()
|
||||
LOCAL oSelf := Qself()
|
||||
METHOD ErrorNo() CLASS TFileRead
|
||||
// Returns the last error code that was recorded.
|
||||
RETURN oSelf:nError
|
||||
RETURN ::nError
|
||||
|
||||
STATIC FUNCTION f_error_msg( cText )
|
||||
METHOD ErrorMsg( cText ) CLASS TFileRead
|
||||
STATIC s_cAction := {"on", "creating object for", "opening", "reading from", "closing"}
|
||||
LOCAL oSelf := Qself()
|
||||
|
||||
LOCAL cMessage, nTemp
|
||||
|
||||
// Has an error been recorded?
|
||||
IF oSelf:nError == 0
|
||||
IF ::nError == 0
|
||||
// No, so report that.
|
||||
cMessage := "No errors have been recorded for " + oSelf:cFile
|
||||
cMessage := "No errors have been recorded for " + ::cFile
|
||||
ELSE
|
||||
// Yes, so format a nice error message, while avoiding a bounds error.
|
||||
IF oSelf:nLastOp < oF_ERROR_MIN .OR. oSelf:nLastOp > oF_ERROR_MAX
|
||||
IF ::nLastOp < oF_ERROR_MIN .OR. ::nLastOp > oF_ERROR_MAX
|
||||
nTemp := 1
|
||||
ELSE
|
||||
nTemp := oSelf:nLastOp + 1
|
||||
nTemp := ::nLastOp + 1
|
||||
ENDIF
|
||||
cMessage := iif( EMPTY( cText ), "", cText ) + "Error " + ALLTRIM( STR( oSelf:nError ) ) + " " + s_cAction[ nTemp ] + " " + oSelf:cFile
|
||||
cMessage := iif( EMPTY( cText ), "", cText ) + "Error " + ALLTRIM( STR( ::nError ) ) + " " + s_cAction[ nTemp ] + " " + ::cFile
|
||||
ENDIF
|
||||
|
||||
RETURN cMessage
|
||||
|
||||
Reference in New Issue
Block a user