VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

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

User avatar
Tom_B
Posts: 5
Joined: Tue Aug 20, 2019 9:00 am

VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

Post by Tom_B »

Hi @all,

I just got the time to do some tests with a small app of mine that cleans up several directories and temp tables.
To have a start, I extracted a function called 'CheckCleanupBatch' that generates a batch file in case it doesn't exist anymore.

Most of the VFP code is accepted, however two errors and one warning are thrown.

Error #1
XS0023 Operator '!' cannot be applied to operand of type 'ARRAY'

Code: Select all

IF NOT DIRECTORY( lcPath )
This is a bit irritating, as the DIRECTORY function returns a .T. or .F. which defenitely isn't an array

Error #2
XS0103 The name 'MKDIR' does not exist in the current context

Code: Select all

MKDIR ( lcPath )
IIRC some time ago I read that MKDIR isn't available yet. Seems like this is still the case. So when will it be in and what can I use instead in the meantime?

Warning #1

XS9085 Unbalanced textmerge delimiters '<<' and '>>'.

Code: Select all

forfiles /P "%PATH1%" /S /M %FILEFILTER% /D %OLDERTHEN% /C "cmd /c del @file | echo delete @file  from @fdate >> %LOGFILE%"
Obviously, the shell command '>>' is recognized as a textmerge delimiter
Well, I could replace it by '~~' or maybe '::' and later use STRTRAN() to replace them with '>>', but accepting it in the first place would be way cooler :)

Here comes already changed testcode. I couldn't use my original code, as is makes use of other function calls that I didn't want to test in the first place. So it is a bit stripped and some values are filled with fix paths, but for testing purposes this was more than sufficient.

Code: Select all

FUNCTION CheckCleanupBatch as Boolean

	LOCAL lcPath as String, lcOutput as String
	lcPath = "D:xstests_al-components"
	lcOutput = "D:xstestslogfiles"
    
	IF NOT DIRECTORY( lcPath )
		TRY 
			MKDIR ( lcPath )
		CATCH
		ENDTRY 
	ENDIF 

	IF NOT FILE( lcPath + "cleanup.bat" )
	
		LOCAL lcOutputPath as String, lcUserTemp as String, lcBatch as String
		STORE "" TO lcOutputPath, lcUserTemp
        
		lcOutputPath	= PROPER( IIF( EMPTY( lcOutput ) , GETENV( "TEMP" ) , lcOutput ) )
		lcUserTemp		= PROPER( STRTRAN( GETENV( "TEMP" ) , LOWER( GETENV( "Username" ) ) , [%username%] ) )
		lcBatch			= ""

		TEXT TO lcBatch TEXTMERGE NOSHOW PRETEXT 1+2
			@echo off


			REM ----------------------------------------
			REM variable declaration
			REM ----------------------------------------
			set PATH1="<<JUSTPATH( ADDBS( lcOutputPath ) )>>"
			set OLDERTHEN=-14
			set FILEFILTER=*.*
			set LOGFILE="<<PROPER( ADDBS( JUSTPATH( FULLPATH( 'cleanup.exe' ) ) ) ) >> _log%DATE:~6,4%%DATE:~3,2%%DATE:~0,2%cleanupbatch.log"

			REM ----------------------------------------
			REM starting batch run
			REM ----------------------------------------
			echo starting batch > %LOGFILE%
			echo ************************** >> %LOGFILE%
			echo deleting protocol >> %LOGFILE%

			REM ----------------------------------------
			REM select files
			REM ----------------------------------------
			forfiles /P "%PATH1%" /S /M %FILEFILTER% /D %OLDERTHEN% /C "cmd /c del @file | echo loesche @file vom @fdate >> %LOGFILE%"
			
			REM ----------------------------------------
			REM end of batch run
			REM ----------------------------------------
			echo ************************** >> %LOGFILE%
			echo end of batch run >> %LOGFILE%
			
		ENDTEXT 
		
		TRY 
			STRTOFILE( lcBatch , lcPath + "cleanup.bat" , 0 )
		CATCH 
		ENDTRY 
		
		IF FILE( lcPath + "cleanup.bat" )
			STRTOFILE( STRCONV( STRCONV( SYS( 2007 , lcBatch , 1 , 1 ) , 13 ) , 15 ) , lcPath + "cleanup.crc" , 0 )
		ENDIF 
		
	ENDIF 
	
    RETURN .T.
    
ENDFUNC 
User avatar
Chris
Posts: 4562
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

Post by Chris »

Hi Tom,

The Directory() function in X# returns an ARRAY, because this is how it works in Visual Objects, it actually returns an array containing the files that are included in the given disk directory. Apparently we need to define a different version of Directory() for VFP, here's one that you can define in your code and the compiler will pick it, instead of the existing one in the runtime. Of course it will be also properly included in the runtime in one of the next builds:

Code: Select all

FUNCTION Directory(cPath AS STRING, nFlags := 0 AS INT) AS LOGIC
	LOCAL lRet AS LOGIC
	lRet := System.IO.Directory.Exists(cPath)
	IF lRet .and. nFlags == 0 .and. (_And(System.IO.DirectoryInfo{cPath}:Attributes , System.IO.FileAttributes.Hidden) != 0)
		lRet := FALSE
	END IF
RETURN lRet

Similar for MkDir(), not implemented yet, but here it is, so you can use it now. I think it works the same way as it does in VFP:

Code: Select all

FUNCTION MkDir(cPath AS STRING) AS INT
	LOCAL nRet AS INT
	IF System.IO.Directory.Exists(cPath)
		nRet := 6
	ELSE
		TRY
			System.IO.Directory.CreateDirectory(cPath)
			nRet := 0
		CATCH
			nRet := 1
		END TRY
	END IF
RETURN nRet

About the XS9085 warning, this indeed looks to me like a compiler problem. We'll look into it as well, thanks for your report!
Chris Pyrgas

XSharp Development Team test
chris(at)xsharp.eu
User avatar
Tom_B
Posts: 5
Joined: Tue Aug 20, 2019 9:00 am

VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

Post by Tom_B »

Hi Chris,

thanks for the quick information. I'll try your code and will give you feedback as soon as I got the time to try it out.

-Tom
User avatar
Tom_B
Posts: 5
Joined: Tue Aug 20, 2019 9:00 am

VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

Post by Tom_B »

Just implemented the two functions in my small prg and no more errors show up. I replaced '>>' with '::' and transformed it after TEXT...ENDTEXT and the warning vanished, too.

However, now the debugger tells me, that TEXT...ENDTEXT has the wrong format and stops right at the first line after TEXT...
xsharp_cleanup_textendtext_echooff.jpg
xsharp_cleanup_textendtext_echooff.jpg (128.93 KiB) Viewed 315 times
User avatar
Chris
Posts: 4562
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

Post by Chris »

Hi Tom,

I tried the code you posted earlier and it seems to work fine here. Can you please post the updated code, so I can try this as well?

Btw, there will be another small problem later, that the STRCONV() and SYS() functions are not implemented.
- From what I see, SYS(2007) generates a checksum out of the string passed to it, do you know which algorithm it uses for that, so we can implement it?
- STRCONV() does ansi<->unicode conversions from what i see. In X# (and .Net in general), strings are already unicode (always), so I think this function will remain unimplemented, it is obsolete in X#.
Chris Pyrgas

XSharp Development Team test
chris(at)xsharp.eu
atlopes
Posts: 83
Joined: Sat Sep 07, 2019 11:43 am

VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

Post by atlopes »

Chris,
STRCONV() does ansi<->unicode conversions from what i see. In X# (and .Net in general), strings are already unicode (always), so I think this function will remain unimplemented, it is obsolete in X#.
STRCONV() does more than that:

- ANSI conversions
- DBCS conversions
- binary conversions (base64 and hex)

I would strongly advise you against letting it unimplemented.

Tom would certainly answer this, but SYS(2007) (and 2017, by the way) use CRC16 and CRC32.
User avatar
Chris
Posts: 4562
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

Post by Chris »

Hi Antonio,

How can you implement ansi, DBCS etc string conversions, when strings are already always unicode anyway and their chars are not 8 bit? Conversions from and to dbf fields (which are 8 bit strings) happen automatically, same for reading/writing to non unicode disk files. So those functions are not relevant anymore in the .Net environment. Regarding binary conversions, it is not possible to store binary data inside strings in the traditional way, such code will need to be adapted a bit in .Net.
Chris Pyrgas

XSharp Development Team test
chris(at)xsharp.eu
atlopes
Posts: 83
Joined: Sat Sep 07, 2019 11:43 am

VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

Post by atlopes »

Chris, I'll start a new thread over this. Meanwhile, an updated VFP compatibility list would be a nice thing to have, perhaps with the inclusion of a new "Under discussion" category?
User avatar
Tom_B
Posts: 5
Joined: Tue Aug 20, 2019 9:00 am

VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

Post by Tom_B »

Hi Chris,

as Antonio already posted, SYS(2007) gives CRC16 or CRC32 checksums. Whereby my SYS() statement would deliver identical checksum values if param#3 would be 0 (zero) as param #4 defines a crc32 checksum and in that case param #3 is omitted.

STRCONV(13|15) transforms to HEX and MIME/BASE64, corresponding values for retransformation are STRCON(14|16) and to be honest, 13-16 are the only params I ever used with STRCONV() :)
Usually I use STRCONV(13) for XML binary fields and STRCONV(15) for email and both together as a quick way to obfuscate data.

FWIW: yesterday VSCE updated to 16.6.4 and this morning it updated to 16.6.5 with .NET FW 4.8.03752

here comes the current codesnippet that makes use of your two kindly provided MKDIR and DIRECTORY functions (Its more or less the same code, just split up a 1-liner and taking care of the '>>' problem by using '::'):

Code: Select all

FUNCTION CheckCleanupBatch() as Boolean

	LOCAL lcPath as String, lcOutput as String
	lcPath = "D:xstests_al-components"
	lcOutput = "D:xstestslogfiles"
    
	IF NOT DIRECTORY( lcPath )
		TRY 
			MKDIR ( lcPath )
		CATCH
		ENDTRY 
	ENDIF 

	IF NOT FILE( lcPath + "cleanup.bat" )
	
		LOCAL lcOutputPath as String, lcUserTemp as String, lcBatch as String
		STORE "" TO lcOutputPath, lcUserTemp, lcBatch
        
		lcOutputPath	= PROPER( IIF( EMPTY( lcOutput ) , GETENV( "TEMP" ) , lcOutput ) )
		lcUserTemp		= PROPER( STRTRAN( GETENV( "TEMP" ) , LOWER( GETENV( "Username" ) ) , [%username%] ) )

		TEXT TO lcBatch TEXTMERGE NOSHOW PRETEXT 1+2
			@echo off
            
			REM ----------------------------------------
			REM variable declaration
			REM ----------------------------------------
			set PATH1="<<JUSTPATH( ADDBS( lcOutputPath ) )>>"
			set OLDERTHEN=-14
			set FILEFILTER=*.*
			set LOGFILE="<<PROPER( ADDBS( JUSTPATH( FULLPATH( 'cleanup.exe' ) ) ) )>>_log%DATE:~6,4%%DATE:~3,2%%DATE:~0,2%cleanupbatch.log"

			REM ----------------------------------------
			REM starting batch run
			REM ----------------------------------------
			echo starting batch > %LOGFILE%
			echo ************************** :: %LOGFILE%
			echo deleting protocol :: %LOGFILE%

			REM ----------------------------------------
			REM select files
			REM ----------------------------------------
			forfiles /P "%PATH1%" /S /M %FILEFILTER% /D %OLDERTHEN% /C "cmd /c del @file | echo loesche @file vom @fdate :: %LOGFILE%"
			
			REM ----------------------------------------
			REM end of batch run
			REM ----------------------------------------
			echo ************************** :: %LOGFILE%
			echo end of batch run :: %LOGFILE%	
		ENDTEXT 
		
        lcBatch = STRTRAN( lcBatch , [::] , [>>] )
        
		TRY 
			STRTOFILE( lcBatch , lcPath + "cleanup.bat" , 0 )
		CATCH 
		ENDTRY 
		
		IF FILE( lcPath + "cleanup.bat" )
			* STRTOFILE( STRCONV( STRCONV( SYS( 2007 , lcBatch , 1 , 1 ) , 13 ) , 15 ) , lcPath + "cleanup.crc" , 0 )
            LOCAL lcCRC as String
            lcCRC = SYS( 2007 , lcBatch , 1 , 1 )
            lcCRC = STRCONV( lcCRC , 13 )
            lcCRC = STRCONV( lcCRC , 15 )
            STRTOFILE( lcCRC , lcPath + "cleanup.crc" , 1 )
		ENDIF 
		
	ENDIF 
	
    RETURN .T.
    
ENDFUNC 
User avatar
Chris
Posts: 4562
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

VFP code throws errors on MKDIR, !DIRECTORY and unbalanced '>>'

Post by Chris »

Hi Tom,

Thanks, looks like again a problem with the << and >> characters in the string, I have logged this for Robert to have a look.

About STRCONV(), it works in FoxPro by treating each character of the string as a byte and then manipulating those bytes, according to the conversion method, isn't that right? In .Net, strings do not consist of bytes, though, they consist of Chars, which are 2 byte long, so you cannot manipulate string contents directly, in the same way as in langauges that use single byte strings, like FoxPro or VO.

What's usually the source of the data that you are than passing to STRCONV() for convertion? Depending on the type of the source, there's an appropriate way to handle it in .Net (usually having to do with byte arrays, instead of strings).
Chris Pyrgas

XSharp Development Team test
chris(at)xsharp.eu
Post Reply