StrToFile ( cExpression, cFileName [, lAdditive | nFlag])

This forum is meant for questions about the Visual FoxPro Language support in X#.

Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am
Location: Germany

StrToFile ( cExpression, cFileName [, lAdditive | nFlag])

Post by Karl-Heinz »

Hi Antonio,
I think we're addressing different issues, here. What I said was that I wouldn't feel too comfortable to have error messages as literal strings spreading around the code. That would not be beneficial to localization and style consistency. So, THROW SomeException {} instead of THROW SomeException { "Error message" }.
The VO Dialect has predefined and localized error messages, and Robert has already added to VFP some predefined error messages. Try this

Code: Select all

? __VfpStr(VFPErrors.INVALID_DATE)
? __VfpStr(VFPErrors.INVALID_RANGE)
Take a look at these VFP sources where you can see how __VfpStr() is used. https://github.com/X-Sharp/XSharpPublic ... ctions.prg But I think at the moment it is more important to write VFP functions ;-)
As per the help file,

Using THROW within a CATCH block without any arguments re-throws the exception, passing it unchanged to the next highest TRY-CATCH block.
you are right, i haven't noticed that this does the same !

Code: Select all

TRY       
	do some nonsense here ;-)

CATCH 

    THROW 	
	
END TRY
thanks for the hint !

regards
Karl-Heinz
atlopes
Posts: 83
Joined: Sat Sep 07, 2019 11:43 am
Location: Portugal

StrToFile ( cExpression, cFileName [, lAdditive | nFlag])

Post by atlopes »

Karl-Heinz,

Thank you for your directions. That was really important to know.

Now, back to some more VFP functions...
User avatar
robert
Posts: 4520
Joined: Fri Aug 21, 2015 10:57 am
Location: Netherlands

StrToFile ( cExpression, cFileName [, lAdditive | nFlag])

Post by robert »

Guys,
What is the status of this function now?
Does anybody have the 'final' version ?

Robert
XSharp Development Team
The Netherlands
robert@xsharp.eu
atlopes
Posts: 83
Joined: Sat Sep 07, 2019 11:43 am
Location: Portugal

StrToFile ( cExpression, cFileName [, lAdditive | nFlag])

Post by atlopes »

Robert (and Karl-Heinz),

This is what I came up with, taking into consideration the remarks from Karl-Heinz. I tested the interoperability of these functions (STRTOFILE() and FILETOSTR()) with VFP and they seem to be working as expected.

A test can be performed against binary files by reading and then writing an image file, for instance:

Code: Select all

STRTOFILE(FILETOSTR("C:Tempimage.jpg"), "C:Tempcopy of image.jpg")
The proposed "final" implementation:

Code: Select all

* VFP standard flags
DEFINE S2F_FLAG_OVERWRITE           = 0x0000
DEFINE S2F_FLAG_APPEND              = 0x0001
DEFINE S2F_FLAG_UNICODE_LE          = 0x0002
DEFINE S2F_FLAG_UTF8                = 0x0004
* X# extension flags
DEFINE S2F_FLAG_UNICODE_BE          = 0x0008
DEFINE S2F_FLAG_UNICODE_FORMATS     = S2F_FLAG_UNICODE_LE | S2F_FLAG_UTF8 | S2F_FLAG_UNICODE_BE
DEFINE S2F_FLAG_UNICODE_TEXT        = 0x0100

FUNCTION StrToFile (Expression AS String, Filename AS String) AS Int
    RETURN StrToFile(Expression, Filename, S2F_FLAG_OVERWRITE)

FUNCTION StrToFile (Expression AS String, Filename AS String, Additive AS Boolean) AS Int
    RETURN StrToFile(Expression, Filename, IIF(Additive, S2F_FLAG_APPEND, S2F_FLAG_OVERWRITE))

FUNCTION StrToFile (Expression AS String, Filename AS String, Flags AS Int) AS Int
    
    LOCAL Additive = .F. AS Boolean
    LOCAL BOM = "" AS String
    LOCAL Result = 0 AS Int
    LOCAL FHandle AS Int
    LOCAL VFPBehavior = .T. AS Boolean      // it means the string must hold an already prepared buffer, or it is binary
    LOCAL UnicodeEncoding AS System.Text.Encoding
    LOCAL IOError AS Exception

    DO CASE
        * VFP behavior, append to a file with no Unicode encoding
        CASE Flags = S2F_FLAG_APPEND
            Additive = .T.
            
        * VFP behavior, create a Unicode file (source buffer already prepared)
        CASE Flags = S2F_FLAG_UNICODE_LE
            BOM = e"xFFxFE"

        * VFP behavior, create a UTF-8 file (source buffer already prepared)
        CASE Flags = S2F_FLAG_UTF8
            BOM = e"xEFxBBxBF"

        * extension to VFP behavior, create a Unicode Big-Endian file (source buffer already prepared)
        CASE Flags = S2F_FLAG_UNICODE_BE
            BOM = e"xFExFF"

        * if not simply overwrite, the file will be treated as a Unicode text file
        CASE Flags != S2F_FLAG_OVERWRITE

            IF (Flags & S2F_FLAG_UNICODE_TEXT) != 0

                VFPBehavior = .F.
                
                Additive = (Flags & S2F_FLAG_APPEND) != 0
            
                * set the Unicode encoding
                SWITCH Flags & S2F_FLAG_UNICODE_FORMATS
                    CASE S2F_FLAG_UNICODE_LE
                        UnicodeEncoding = System.Text.Encoding.Unicode
                        
                    CASE S2F_FLAG_UTF8
                        UnicodeEncoding = System.Text.Encoding.UTF8
                        
                    CASE S2F_FLAG_UNICODE_BE
                        UnicodeEncoding = System.Text.Encoding.BigEndianUnicode
                        
                    * error if Unicode encoding not properly set
                    OTHERWISE
                        THROW ArgumentException {}
                        
                END SWITCH
            ELSE
                THROW ArgumentException {}
            ENDIF
    END CASE
    
    * append mode?
    IF Additive

        IF VFPBehavior

            * open an existing file, or create if it does not exists
            FHandle = FOpen(Filename, FO_READWRITE + FO_SHARED)
            IF FHandle != F_ERROR
                * try to move to the end of the file
                FSeek3(FHandle, 0, FS_END)
                * and write the contents of the buffer
                IF FError() == 0
                    Result = FWrite(FHandle, Expression)
                ENDIF
                * if everything went ok, close the file handle
                IF FError() == 0
                    FClose(FHandle)
                    IF FError() != 0
                        THROW FException()
                    ENDIF
                * if not, before throwing the exception...
                ELSE
                    IOError = FException()
                    FClose(FHandle)         // ... try to close the handle, anyway
                    THROW IOError
                ENDIF
            ELSE
                THROW FException()
            ENDIF
            
        ELSE
            
            * in non-VFP behavior, just append the Unicode string to an existing file
            TRY
                File.AppendAllText(Filename, Expression, UnicodeEncoding)
            CATCH
                THROW
            ENDTRY
                
            Result = Expression:Length
            
        ENDIF

    ELSE
        
        * TO-DO: check on SET("Safety") 

        * create a new file
        IF VFPBehavior
        
            * get an handle for a new file
            FHandle = FCreate(Filename)
            IF FHandle != F_ERROR
                * start with the BOM of the file
                IF ! (BOM == "")
                    Result = FWrite(FHandle, BOM)
                ENDIF
                * try to write the contents from the buffer
                IF FError() == 0
                    Result += FWrite(FHandle, Expression)
                ENDIF
                * and close the file
                IF FError() == 0
                    FClose(FHandle)
                    IF FError() != 0
                        THROW FException()
                    ENDIF
                * if an error occurred...
                ELSE
                    IOError = FException()
                    FClose(FHandle)     // ... try to not leave the handle open, in any case
                    THROW IOError
                ENDIF
            ELSE
                THROW FException()
            ENDIF
 
        ELSE
            
            * write the Unicode string to a text file
            TRY
                File.WriteAllText(Filename, Expression, UnicodeEncoding)
            CATCH
                THROW
            ENDTRY
            
            Result = Expression:Length
            
        ENDIF

    ENDIF

    * return the length of bytes / characters
    RETURN Result

ENDFUNC

FUNCTION FileToStr (Filename AS String) AS String
    RETURN FileToStr(Filename, S2F_FLAG_OVERWRITE)

FUNCTION FileToStr (Filename AS String, Flags AS Int) AS String
    
    LOCAL FHandle AS Int
    LOCAL StrLen AS Int
    LOCAL Result = "" AS String
    LOCAL IOError AS Exception

    IF (Flags & S2F_FLAG_UNICODE_TEXT) = 0      // VFP behavior, read file as binary, even if it is a Unicode text

        * TO-DO - work with the SET("Path") setting to look for a file

        FHandle = FOpen(Filename, FO_READ + FO_SHARED)
        IF FHandle != F_ERROR
            * success opening the file, get its size...
            StrLen = FSize(FHandle)
            IF StrLen > 0
                * ...and allocate a buffer for it
                Result = SPACE(StrLen)
                IF FRead(FHandle, @Result, StrLen) != StrLen
                    Result = ""
                ENDIF
            ELSE
                Result = ""
            ENDIF
            * any IO error will throw an exception
            IF FError() != 0
                IOError = FException()
                FClose(FHandle)
                THROW IOError
            ELSE
                FClose(FHandle)
            ENDIF
        ELSE
            THROW FException()
        ENDIF

    ELSE
        
        * for a Unicode text file, just read it into a string 
        TRY
            Result = File.ReadAllText(Filename)     // read a text file
        CATCH
            THROW
        ENDTRY
        
    ENDIF

    * return the contents of the file
    RETURN Result
    
ENDFUNC
Post Reply