/* * $Id$ */ /* * Harbour Project source code: * File support Functions For hbdoc * * Copyright 2000 Luiz Rafael Culik * www - http://www.harbour-project.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). * * As a special exception, the Harbour Project gives permission for * additional uses of the text contained in its release of Harbour. * * The exception is that, if you link the Harbour libraries with other * files to produce an executable, this does not by itself cause the * resulting executable to be covered by the GNU General Public License. * Your use of that executable is in no way restricted on account of * linking the Harbour library code into it. * * This exception does not however invalidate any other reasons why * the executable file might be covered by the GNU General Public License. * * This exception applies only to the code released by the Harbour * Project under the name Harbour. If you copy code from other * Harbour Project or Free Software Foundation releases into a copy of * Harbour, as the General Public License permits, the exception does * not apply to the code that you add in this way. To avoid misleading * anyone as to the status of such modified files, you must delete * this exception notice from them. * * If you write modifications of your own for Harbour, it is your choice * whether to permit this exception to apply to your modifications. * If you do not wish that, delete this exception notice. * */ #pragma -w2 #include "hbclass.ch" #include "common.ch" #include "fileio.ch" #define pBUFFER_LENGTH 4096 STATIC s_oFileBase *+-------------------------------------------------------------------- *+ *+ Class FileBase *+ *+-------------------------------------------------------------------- *+ CLASS FileBase FROM FileMan DATA nOpenMode // Holds the value to use when opening the file DATA nCreateMode // Holds the value to use when creating the file DATA nDosHandle // Holds the DOS file handle for this DATA nEndOfFile // Holds the last byte value in the file DATA nSkipLength // This holds the default skpping length of 1 DATA cName // This holds the name of the file being worked on DATA nPosition // This holds the position in the file at DATA lAtBottom // This is a value to show if at bottom of file DATA lAtTop // This is a value to show if at top of file METHOD new( cname ) // This is the constructor for the file METHOD FOPEN() // This opens the specified file METHOD closefile() // This closes the specified file METHOD fskip( n ) // Moves the byte pointer within the file METHOD FWRITE( c ) // Write passed data to file w/ len() == nSkipLenght METHOD retrieve() // Returns the contents of the file at current pos METHOD fgoTop() // Move the byte pointer to the top of the file METHOD fgoBottom() // Move the byte pointer to the bottom of the file METHOD fgoto() // Moves the byte pointer to a specific location METHOD create() message fappend METHOD fappendByte( cByte ) message BuffGet METHOD BufferGet( lDirection ) METHOD SKIP( nRecord ) // Moves the byte pointer within the file METHOD WRITE( cChar ) // Write passed data to file w/ len() == nSkipLenght METHOD goTop() // Move the byte pointer to the top of the file METHOD goBottom() // Move the byte pointer to the bottom of the file METHOD GOTO( nValue ) // Moves the byte pointer to a specific location METHOD OPEN() message append METHOD appendLine( cline ) ENDCLASS /* Method: Init/New Params: N/A Returns: Self Purpose: Constructor */ METHOD new( cName ) CLASS FileBase super:new() // first thing to do is check to see if there is a valid file ::nSkipLength := 1 ::nOpenMode := FO_READWRITE // Mode for which to open the file ::nCreateMode := FC_NORMAL // Mode for which to create the file ::cName := cName RETURN self /* Method: skip( ) Params: Returns: Self Purpose: This method moves the file's byte pointer position from the current location. The actualy movement is determined on the value of ::nSkipLength which holds the skipping base. This class's purpose is to do one byte movements. */ METHOD fskip( nRecords ) CLASS FileBase DEFAULT nRecords TO 1 IF ::noDosError() .AND. ::nDosHandle > 0 FSEEK( ::nDosHandle, ( ::nSkipLength * nRecords ), FS_RELATIVE ) ::nLastDosMessage := FERROR() ::nPosition := FSEEK( ::nDosHandle, 0, FS_RELATIVE ) DO CASE CASE ::nPosition == ::nEndOfFile ::lAtBottom := .T. ::lAtTop := .F. CASE ::nPosition <= 1 ::lAtTop := .T. ::lAtBottom := .F. OTHERWISE ::lAtBottom := ::lAtTop := .F. ENDCASE ENDIF RETURN Self /* Method: gotop() Params: N/A Returns: Self Purpose: Move the byte pointer to the top of the file */ METHOD fgotop() CLASS FileBase IF ::noDosError() .AND. ::nDosHandle > 0 ::nPosition := FSEEK( ::nDosHandle, 0, FS_SET ) ::nLastDosMessage := FERROR() ::lAtTop := .T. ::lAtBottom := .F. ENDIF RETURN Self /* Method: gobottom() Params: N/A Returns: Self Purpose: Move hte byte pointer of the file to tbe bottom. */ METHOD fgoBottom() CLASS FileBase IF ::noDosError() .AND. ::nDosHandle > 0 ::nPosition := FSEEK( ::nDosHandle, 0, FS_END ) ::nLastDosMessage := FERROR() ::lAtTop := .F. ::lAtBottom := .T. ENDIF RETURN Self /* Method: closefile() Params: N/A Returns: Self Purpose: To close the file */ METHOD closefile() CLASS FileBase IF ::noDosError() .AND. ::nDosHandle > 0 FCLOSE( ::nDosHandle ) ::nLastDosMessage := FERROR() ::delItem( ::nDosHandle ) ::lAtTop := ::lAtBottom := .F. ::nPosition := 0 ENDIF RETURN Self /* Method: retrieve Params: N/A Returns: Purpose: To return the contents of the file at the current position based on the length of ::nSkipLength. */ METHOD retrieve() CLASS FileBase LOCAL cReturn // as char LOCAL nMoved // as int IF ::noDosError() .AND. ::nDosHandle > 0 cReturn := SPACE( ::nSkipLength ) nMoved := FREAD( ::nDosHandle, @cReturn, ::nSkipLength ) ::nLastDosMessage := FERROR() FSEEK( ::nDosHandle, - ( nMoved ), FS_RELATIVE ) // Re-position the pointer ENDIF RETURN cReturn /* Method: write() Params: Returns: Self Purpose: To write out to the contents of the file the value in the parameter . */ METHOD FWRITE( cChar ) CLASS FileBase IF ::noDosError() .AND. ::nDosHandle > 0 IF ISCHARACTER( cChar ) FWRITE( ::nDosHandle, cChar, 1 ) ::nLastDosMessage := FERROR() IF ::noDosError() FSEEK( ::nDosHandle, ::nPosition, FS_SET ) // Re-position the pointer ENDIF ENDIF ENDIF RETURN Self /* Method: goto() Params: The record byte to move to Returns: Self Purpose: This method moves the byte marker to the position within the file. It is also based on the value stored to the ::nSkipLength instance variable */ METHOD fgoto( nValue ) CLASS FileBase IF ::noDosError() .AND. ::nDosHandle > 0 IF ISNUMBER( nValue ) IF nValue > 0 .AND. ; ( nValue * ::nSkipLength ) <= ::nEndOfFile FSEEK( ::nDosHandle, ( nValue * ::nSkipLength ), FS_SET ) ::nLastDosMessage := FERROR() ::nPosition := FSEEK( ::nDosHandle, 0, FS_RELATIVE ) DO CASE CASE ::nPosition == ::nEndOfFile ::lAtBottom := .T. ::lAtTop := .F. CASE ::nPosition <= 1 ::lAtTop := .T. ::lAtBottom := .F. OTHERWISE ::lAtBottom := ::lAtTop := .F. ENDCASE ENDIF ENDIF ENDIF RETURN ::nPosition /* Method: create() Params: N/A Returns: Self Purpose: Creates the specified file with the proper access code */ METHOD Create() CLASS FileBase LOCAL nFile // as int IF ::noDosError() nFile := FCREATE( ::cName, ::nCreateMode ) ::nLastDosMessage := FERROR() IF ::noDosError() // No Error FCLOSE( nFile ) // Close the file ::fopen() // Re-open the file ENDIF ENDIF RETURN Self /* Method: open() Params: N/A Returns: Self Purpose: Opens the file with the proper access code */ METHOD FOPEN() CLASS FileBase IF ::noDosError() ::nDosHandle :=::openfile( ::cName, ::nOpenMode ) ::nEndOfFile := FSEEK( ::nDosHandle, 0, FS_END ) ::nPosition := FSEEK( ::nDosHandle, 0, FS_SET ) ::lAtTop := .T. ::lAtBottom := .F. ENDIF RETURN Self METHOD fappendByte( cByte ) CLASS FileBase DEFAULT cByte TO "" IF !EMPTY( cByte ) // Valid line IF ::noDosError() .AND. ::nDosHandle > 0 // No error FSEEK( ::nDosHandle, 0, FS_END ) FWRITE( ::nDosHandle, cByte, 1 ) ::nEndOfFile := FSEEK( ::nDosHandle, 0, FS_END ) ::nPosition := FSEEK( ::nDosHandle, - ( LEN( cByte ) ), FS_END ) ::nSkipLength := LEN( cByte ) ::lAtBottom := ::lAtTop := .F. ENDIF ENDIF RETURN Self METHOD OPEN() CLASS FileBase Self:nDosHandle := Self:openfile( ::cName, ::nOpenMode ) ::nEndOfFile := FSEEK( Self:nDosHandle, 0, FS_END ) FSEEK( Self:nDosHandle, 0, FS_SET ) ::nSkipLength := Self:Buffget() ::lAtTop := .T. ::lAtBottom := .F. ::nHan := Self:nDosHandle RETURN Self /* Method: gotop() Params: N/A Returns: Self Purpose: Move the byte pointer to the top of the file */ METHOD gotop() CLASS FileBase IF Self:noDosError() .AND. Self:nDosHandle > 0 ::fgotop() ::nSkipLength := Self:Buffget() ENDIF RETURN Self /* Method: gobottom() Params: N/A Returns: Self Purpose: Move hte byte pointer of the file to tbe bottom. */ METHOD goBottom() CLASS FileBase LOCAL cBuffer // as char LOCAL lWithCRLF := .F. // as logical IF Self:noDosError() .AND. Self:nDosHandle > 0 ::fgobottom() // Now, back off from the end one line length and set the marker cBuffer := SPACE( pBUFFER_LENGTH ) FSEEK( Self:nDosHandle, - ( pBUFFER_LENGTH ), FS_END ) FREAD( Self:nDosHandle, @cBuffer, pBUFFER_LENGTH ) IF RIGHT( cBuffer, 2 ) == hb_OSNewLine() // We need to remove this extra one! cBuffer := LEFT( cBuffer, LEN( cBuffer ) - 2 ) lWithCRLF := .T. ENDIF cBuffer := SUBSTR( cBuffer, RAT( hb_OSNewLine(), cBuffer ) + 2 ) ::nSkipLength := LEN( cBuffer ) + iif( lWithCRLF, 2, 0 ) ::nposition := FSEEK( Self:nDosHandle, - ( LEN( cBuffer ) ), FS_END ) IF lWithCRLF ::nposition := FSEEK( Self:nDosHandle, - 2, FS_RELATIVE ) ENDIF ENDIF RETURN Self /* Method: write() Params: Returns: Self Purpose: To write out to the contents of the file the value in the parameter . */ METHOD WRITE( cChar ) CLASS FileBase IF Self:noDosError() .AND. Self:nDosHandle > 0 IF ISCHARACTER( cChar ) IF cChar > Self:nSkipLength // we are going to truncate for now... FWRITE( Self:nDosHandle, cChar, Self:nSkipLength ) ELSE FWRITE( Self:nDosHandle, cChar, LEN( cChar ) ) ENDIF FSEEK( Self:nDosHandle, ::nposition, FS_SET ) Self:nLastDosMessage := FERROR() IF Self:noDosError() FSEEK( Self:nDosHandle, Self:nPosition, FS_SET ) // Re-position the pointer ENDIF ENDIF ENDIF RETURN Self /* Method: appendLine( Character line to append Returns: Self Purpose: To append a blank CRLF delimited line at the end of the file. If is not passed or if it an empty line with 0 bytes in length, the function will not operate. */ METHOD appendLine( cLine ) CLASS FileBase DEFAULT cLine TO "" IF LEN( cLine ) == 0 // Valid line IF Self:noDosError() .AND. Self:nDosHandle > 0 // No error IF !( hb_OSNewLine() $ cLine ) // No CRLF, so add cLIne += hb_OSNewLine() ENDIF FSEEK( Self:nDosHandle, 0, FS_END ) FWRITE( Self:nDosHandle, cLine ) ::nEndOfFile := FSEEK( Self:nDosHandle, 0, FS_END ) ::nposition := FSEEK( Self:nDosHandle, - ( LEN( cLine ) ), FS_END ) ::nSkipLength := LEN( cLine ) ::lAtBottom := ::lAtTop := .F. ENDIF ENDIF RETURN Self /* Method: skip( ) Params: Returns: Self Purpose: This method moves the file's byte pointer position from the current location. The actualy movement is determined on the value of Self:nSkipLength which holds the skipping base. This class's purpose is to do one byte movements. */ METHOD SKIP( nRecords ) CLASS FileBase LOCAL nCount := 0 // as int DEFAULT nRecords TO 1 // Here, we have to start looking for CHR(13)+CHR(10) character // combinations. Once found, then we have to set the super class // values appropriately IF Self:noDosError() .AND. Self:nDosHandle > 0 DO CASE CASE nRecords > 0 // It's positive movement WHILE nCount ++ != nRecords ::fskip() ::nSkipLength := Self:Buffget() ENDDO CASE nRecords < 0 // It's negative movement WHILE nCount -- != nRecords ::nSkipLength := Self:Buffget( .F. ) ::fskip( - 1 ) ENDDO ENDCASE ENDIF RETURN Self /* Method: goto() Params: The record byte to move to Returns: Self Purpose: This method moves the byte marker to the position within the file. It is also based on the value stored to the Self:nSkipLength instance variable */ METHOD GOTO( nValue ) CLASS FileBase LOCAL cLine := "" // as char LOCAL nCount := 0 // as int LOCAL lContinue := .T. // as logical LOCAL cBuffer // as char DEFAULT nValue TO 0 IF Self:noDosError() .AND. Self:nDosHandle > 0 IF ISNUMBER( nValue ) IF nValue > 0 // o.k. so far FSEEK( Self:nDosHandle, 0, FS_SET ) // start at the top WHILE lContinue cBuffer := SPACE( pBUFFER_LENGTH ) lContinue := ( FREAD( Self:nDosHandle, @cBuffer, pBUFFER_LENGTH ) == ; pBUFFER_LENGTH ) cBuffer := cLine + cBuffer WHILE hb_OSNewLine() $ cBuffer IF ++ nCount == nValue lContinue := .F. EXIT ENDIF cBuffer := SUBSTR( cBuffer, AT( hb_OSNewLine(), cBuffer ) + 2 ) ENDDO cLine := cBuffer ENDDO IF nCount == nValue // We have a match FSEEK( Self:nDosHandle, - ( pBUFFER_LENGTH ), FS_RELATIVE ) // Back off from here ::nposition := FSEEK( Self:nDosHandle, ; ( pBUFFER_LENGTH - LEN( cBuffer ) ), ; FS_RELATIVE ) // Move ::nSkipLength := Self:Buffget() ELSE FSEEK( Self:nDosHandle, ::nposition, FS_SET ) nCount := 0 ENDIF ENDIF ENDIF ENDIF RETURN nCount METHOD BufferGet( lForward ) CLASS FileBase LOCAL cBuffer // as char LOCAL nLocation // as int LOCAL nRead // as int LOCAL lWithCRLF := .F. // as logical DEFAULT lForward TO .T. IF !lForward nRead := FSEEK( Self:nDosHandle, ; - ( iif( ::nposition < pBUFFER_LENGTH, ; ::nposition, ; pBUFFER_LENGTH ) ), ; FS_RELATIVE ) // rewind backwards cBuffer := SPACE( ::nposition - nRead ) FREAD( Self:nDosHandle, @cBuffer, ( ::nposition - nRead ) ) IF RIGHT( cBuffer, 2 ) == hb_OSNewLine() // with line already cBuffer := LEFT( cBuffer, LEN( cBuffer ) - 2 ) lWithCRLF := .T. ENDIF nLocation := LEN( cBuffer ) - ( RAT( hb_OSNewLine(), cBuffer ) ) ELSE cBuffer := SPACE( pBUFFER_LENGTH ) nRead := FREAD( Self:nDosHandle, @cBuffer, pBUFFER_LENGTH ) FSEEK( Self:nDosHandle, - ( iif( nRead < pBUFFER_LENGTH, nRead, ; pBUFFER_LENGTH ) ), FS_RELATIVE ) // Rewind // Now, parse the string. and file nLocation := AT( hb_OSNewLine(), cBuffer ) // Now, if there is NO CRLF in the buffer and if the value of the // number of bytes read is less than the buffer length, then we // have an end of file condition. IF nLocation == 0 .AND. ( nRead < pBUFFER_LENGTH ) // If so, then set the appropriate flags accordingly. ::lAtBottom := .T. ::lAtTop := .F. ENDIF ENDIF RETURN nLocation #xtranslate DOSFILENAME() => substr( , rat("\",)+1 ) #define pDOS_HANDLE 1 #define pDOS_FILE 2 #define pDOS_PATH 3 *+-------------------------------------------------------------------- *+ *+ Class FileMan *+ *+-------------------------------------------------------------------- *+ CLASS FileMan data aDosHandles // Holds an array of dos handles and names data nHan data nLastDosMessage // Holds the DOS error level of last operation METHOD addItem( nDos, cFile, cPath ) // Adds an item to the array of handles METHOD delItem( xitem ) // Deletes an item from the array of handles METHOD new() // The constructor for this class METHOD closeAll() // Closes all of those files METHOD rewindAll() // Positions the file pointer for each file METHOD writeAll() // Performs hard-write of all METHOD getFileName( cfile ) // Obtains the name of the file based on ID METHOD getFileId( nid ) // Obtains the ID based on file name METHOD getFilePath( xItem ) // Obtains file path based on either ID or name METHOD noDosError() // Returns a logical true/false METHOD openfile( cFile, nMethod ) // Opens the specified file and sets error METHOD Buffget( ld ) virtual ENDCLASS /* Method: Init/New Params: N/A Returns: Self Purpose: Constructor */ METHOD new() CLASS FileMan IF ::aDosHandles == NIL // has yet to be initialized ::aDosHandles := {} ENDIF IF ::nLastDosMessage == NIL // has yet to be initialized ::nLastDosMessage := 0 ENDIF RETURN Self // The following are global operations that need to be performed by all // files regardless of their format /* Method: ::closeAll() Params: N/A Returns: Self Purpose: To go through the stack of opened file handles and close each file, one at a time. Since this is a global operation, it will not check on the status of the error message on each pass but will at the start of the evaluation. */ METHOD closeAll() CLASS FileMan IF ::nLastDosMessage == 0 AEVAL( ::aDosHandles, { | aFile | FCLOSE( aFile[ pDOS_HANDLE ] ) } ) ENDIF RETURN Self /* Method: ::rewindAll() Params: N/A Returns: Self Purpose: To go through the stack of opened file handles and places the file pointer to the top of each file, one at a time. Since Since this is a global operation, it will not check on the status of the error message on each pass but will at the start of the evaluation. */ METHOD rewindAll() CLASS FileMan IF ::nLastDosMessage == 0 AEVAL( ::aDosHandles, { | aFile | FSEEK( aFile[ pDOS_HANDLE ], 0, FS_SET ) } ) ENDIF RETURN Self /* Method: ::writeAll() Params: N/A Returns: Self Purpose: To go through the stack of opened file handles and writes each file, one at a time. Since this is a global operation, it will not check on the status of the error message on each pass but will at the start of the evaluation. */ METHOD writeAll() CLASS FileMan IF ::nLastDosMessage == 0 AEVAL( ::aDosHandles, { | aFile | FWRITE( aFile[ pDOS_HANDLE ], "", 0 ) } ) ENDIF RETURN Self /* Method: ::getFileName( ) Params: DOS File handle / ID Returns: File name store with that ID handle Purpose: This method will return the file's name found within the table of this class. */ METHOD getFileName( nId ) CLASS FileMan // Obtains the name of the file based on ID LOCAL cName := "" // as char LOCAL nPosition // as int IF ::nLastDosMessage == 0 IF ISNUMBER( nId ) nPosition := ASCAN( ::aDosHandles, ; { | aFile | nId == aFile[ pDOS_HANDLE ] } ) IF nPosition != 0 cName := ::aDosHandles[ nPosition, pDOS_FILE ] ENDIF ENDIF ENDIF RETURN cName /* Method: ::getFileId( ) Params: File names used to store item to stack Returns: DOS File handle or ID associated with name Purpose: This method will return the file's ID or DOS handle found within the table of this class. */ METHOD getFileId( cName ) CLASS FileMan // Obtains the ID based on file name LOCAL nId := 0 // as int LOCAL nPosition // as int IF ::nLastDosMessage == 0 IF ISCHARACTER( cName ) nPosition := ASCAN( ::aDosHandles, ; { | aFile | cName == aFile[ pDOS_FILE ] } ) IF nPosition != 0 nId := ::aDosHandles[ nPosition, pDOS_HANDLE ] ENDIF ENDIF ENDIF RETURN nId /* Method: ::getFilePath( ) Params: DOS File handle / ID or stored file name Returns: Associated file path Purpose: This method will return the associated DOS path for either the given file name or DOS file handle / ID. If there is no file path or if there is an error with the method, the return value will be a NULL character byte. */ METHOD getFilePath( xItem ) CLASS FileMan // Obtains file path based on either ID or name LOCAL cPath := "" // as char LOCAL nPosition // as int IF ::nLastDosMessage == 0 DO CASE CASE ISCHARACTER( xItem ) // we've got the file name nPosition := ASCAN( ::aDosHandles, ; { | aFile | xItem == aFile[ pDOS_FILE ] } ) IF nPosition != 0 cPath := ::aDosHandles[ nPosition, pDOS_PATH ] ENDIF CASE ISNUMBER( xItem ) // we've got the file path nPosition := ASCAN( ::aDosHandles, ; { | aFile | xItem == aFile[ pDOS_HANDLE ] } ) IF nPosition != 0 cPath := ::aDosHandles[ nPosition, pDOS_PATH ] ENDIF ENDCASE ENDIF RETURN cPath // The following two methods are for the sole purpose of manipulating the // array of DOS file handles /* Method: ::addItem( , [, DOS file handle File name File path, defaults to "" Returns: self Purpose: This method will add the DOS file ID and name to the internal stack. It will not work if either of the the first two parameters are not passed to the method OR if the value of ::nLastDosMessage is 0. The return value of the method will be the object itself. */ METHOD addItem( nDos, cFile, cPath ) CLASS FileMan DEFAULT cPath TO "" IF ::nLastDosMessage == 0 AADD( ::aDosHandles, { nDos, cFile, cPath } ) ENDIF RETURN Self /* Method: ::delItem( ) Params: DOS file handle or file name Returns: Success status of operation Purpose: To go through the stack of opened file handles and based on the parameter passed to the method, it will remove the file from the stack. If is a numeric, it will be assumed a valud DOS file handle. If is character, then it will be assumed the name of the file. If is neither numeric or character or if the value of ::nLastDosMessage is not 0, then the method will return a logical false (.F.) value; otherwise, a logical true (.T.) will be returned. */ METHOD delItem( xItem ) CLASS FileMan LOCAL nPosition // as int LOCAL lSuccess := .T. // as logical // if xItem is N/Numeric, then seek on first element; // if xItem is C/Character, then seek on second element IF ::nLastDosMessage == 0 // No DOS error! DO CASE CASE ISNUMBER( xItem ) // It's a DOS file handle nPosition := ASCAN( ::aDosHandles, ; { | aItem | xItem == aItem[ pDOS_HANDLE ] } ) IF nPosition == 0 // Don't remove and set the return value of the function lSuccess := .F. ELSE // Since we have a position, remove from the table and keep the // default return value ADEL( ::aDosHandles, nPosition ) ASIZE( ::aDosHandles, LEN( ::aDosHandles ) - 1 ) ENDIF CASE ISCHARACTER( xItem ) // It's a file name nPosition := ASCAN( ::aDosHandles, ; { | aItem | xItem == aItem[ pDOS_FILE ] } ) IF nPosition == 0 // Don't remove and set the return value of the function lSuccess := .F. ELSE // Since we have a position, remove from the table and keep the // default return value ADEL( ::aDosHandles, nPosition ) ASIZE( ::aDosHandles, LEN( ::aDosHandles ) - 1 ) ENDIF OTHERWISE // Invalid data passed to method lSuccess := .F. ENDCASE ELSE lSuccess := .F. ENDIF RETURN lSuccess /* Method: noDosError() Params: N/A Returns: Purpose: To return a logical true (.T.) if there is no existing error state within the system */ METHOD noDosError() CLASS FileMan RETURN ::nLastDosMessage == 0 /* Method: open() Params: N/A Returns: Purpose: This method acutally opens the file specified by the parameter with the open mode of . Each file object should carry this information locally and use this method only to update the internal table. */ METHOD openfile( cFile, nMethod ) CLASS FileMan LOCAL nFileHandle // as int LOCAL cFilename // as char LOCAL cPath // as char DEFAULT nMethod TO 0 nFileHandle := FOPEN( cFile, nMethod ) // opens the file IF !EMPTY( FERROR() ) // There was an error in opening ::nLastDosMessage := FERROR() nFileHandle := - 1 ELSE cFileName := DOSFILENAME( cFile ) cPath := STRTRAN( cFile, cFileName, "" ) ::addItem( nFileHandle, cFileName, cPath ) ENDIF ::nHan := nFileHandle RETURN nFileHandle /*****************************************************************/ /**** * FT_FUSE( cFile, nMode ) ---> nHandle * Open a File */ FUNCTION FT_FUSE( cFile, nMode ) IF cFile == NIL s_oFileBase:closefile() ELSE s_oFileBase := FileBase():new( cFile ) IF nMode != NIL s_oFileBase:nOpenMode := nMode ENDIF s_oFileBase:open() ENDIF RETURN s_oFileBase:nHan FUNCTION FT_FEOF() RETURN s_oFileBase:lAtBottom FUNCTION FReadLn() RETURN s_oFileBase:retrieve() PROCEDURE FT_FGotop() s_oFileBase:Gotop() RETURN PROCEDURE FT_FSKIP( n ) s_oFileBase:Skip( n ) RETURN PROCEDURE FT_MKDIR( cDir ) #ifdef HB_COMPAT_C53 MakeDir( cDir ) #else HB_SYMBOL_UNUSED( cDir ) // TOFIX #endif RETURN FUNCTION StrPos( cBuffer ) LOCAL x LOCAL cChar FOR x := 1 TO LEN( cBuffer ) cChar := SUBSTR( cBuffer, x, 1 ) IF cChar >= "A" .AND. cChar <= "Z" .OR. ; cChar >= "a" .AND. cChar <= "z" .OR. ; cChar >= "0" .AND. cChar <= "9" .OR. ; cChar $ "@-(|.*#/=?!<>+" .OR. ; cChar == '"' RETURN x ENDIF NEXT RETURN 0 FUNCTION GetNumberofTableItems( cBuffer ) LOCAL cItem LOCAL nItem := 0 cBuffer := ALLTRIM( cBuffer ) DO WHILE AT( SPACE( 3 ), cBuffer ) > 0 cItem := SUBSTR( cBuffer, 1, AT( SPACE( 3 ), cBuffer ) - 1 ) IF AT( SPACE( 3 ), cBuffer ) == 0 nItem++ ELSE cBuffer := ALLTRIM( STRTRAN( cBuffer, cItem, "" ) ) nItem++ ENDIF ENDDO nItem++ RETURN nItem FUNCTION FREADline( nH, cB, nMaxLine ) LOCAL cLine := SPACE( nMaxLine ) LOCAL nSavePos LOCAL nEol LOCAL nNumRead cB := "" nSavePos := FSEEK( nH, 0, FS_RELATIVE ) nNumRead := FREAD( nH, @cLine, nMaxLine ) IF ( nEol := AT( hb_OSNewLine(), SUBSTR( cLine, 1, nNumRead ) ) ) == 0 cB := cLine ELSE cB := SUBSTR( cLine, 1, nEol - 1 ) FSEEK( nH, nSavePos + Len( hb_OSNewLine() ) - 1, FS_SET ) ENDIF RETURN nNumRead != 0