Skip to content

Implemented functions FCreate() and FOpen()#1843

Open
Irwin1985 wants to merge 1 commit intodevfrom
feature/vfp-fopen-fcreate
Open

Implemented functions FCreate() and FOpen()#1843
Irwin1985 wants to merge 1 commit intodevfrom
feature/vfp-fopen-fcreate

Conversation

@Irwin1985
Copy link
Contributor

  • Mapped VFP nAttribute file modes to X# native FO_* and FC_* constants.
  • Implemented buffering translation for FOPEN (modes 10, 11, 12 mapped to FO_UNBUFFERED).
  • Updated FoxProFunctions attributes from Stub to Full.
  • Added related Unit Test to verify exact VFP return values (-1 on error) and proper file handle creation.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements the Visual FoxPro-compatible FCREATE() and FOPEN() runtime wrappers in XSharp.VFP by delegating to XSharp.Core file APIs and adds unit tests to validate expected handle/error behavior.

Changes:

  • Implemented FCreate() to call XSharp.Core.Functions.FCreate() and return the handle as INT64.
  • Implemented FOpen() with VFP nAttributeFO_* mode translation (including unbuffered modes) and SET PATH resolution via File()/FPathName().
  • Added unit tests covering create/open success paths, missing-file error return, and SET PATH lookup.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/Runtime/XSharp.VFP/RuntimeCoreWrappers.prg Adds concrete implementations for FCreate() and FOpen() and marks both functions as Full.
src/Runtime/XSharp.VFP.Tests/MiscTests.prg Adds file I/O unit tests for FCreate()/FOpen() and SET PATH behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

CASE 10; nMode := FO_READ | FO_SHARED | FO_UNBUFFERED
CASE 11; nMode := FO_WRITE | FO_EXCLUSIVE | FO_UNBUFFERED
CASE 12; nMode := FO_READWRITE | FO_EXCLUSIVE | FO_UNBUFFERED
CASE 0
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the SWITCH on nAttribute, CASE 0 does not assign nMode, so the behavior relies on nMode’s implicit default value. This makes the default open mode ambiguous and easy to break if initialization rules change. Assign the intended default mode explicitly for CASE 0 (or initialize nMode when declared) so FOpen(cFileName, 0) is self-documenting and consistent with the other cases.

Suggested change
CASE 0
CASE 0; nMode := FO_READ | FO_SHARED

Copilot uses AI. Check for mistakes.
Comment on lines +92 to +93
LOCAL nBadHandle AS INT64
nBadHandle := FOpen("non_existent_file.txt", 0)
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test’s expected-failure case uses a hardcoded relative filename ("non_existent_file.txt"). If that file happens to exist in the current working directory (or is found via a prior SET PATH), the test will become flaky and fail unexpectedly. Use a unique temp path (e.g., GUID-based under Path.GetTempPath()) and assert it does not exist before calling FOpen.

Suggested change
LOCAL nBadHandle AS INT64
nBadHandle := FOpen("non_existent_file.txt", 0)
LOCAL cBadFile AS STRING
LOCAL nBadHandle AS INT64
cBadFile := Path.Combine(Path.GetTempPath(), "vfp_test_" + Guid.NewGuid():ToString("N") + ".txt")
Assert.False(FILE(cBadFile))
nBadHandle := FOpen(cBadFile, 0)

Copilot uses AI. Check for mistakes.
Comment on lines +75 to +98

cFile := Path.Combine(Path.GetTempPath(), "vfp_test_" + Guid.NewGuid():ToString("N") + ".txt")

&& 1. Test FCREATE()
nHandle := FCreate(cFile, 0)
Assert.True(nHandle > 0, "FCreate should return a valid handle")

nWritten := FPuts(nHandle, "XSharp VFP File Test")
Assert.True(nWritten > 0, "Should have written data in the file")
FClose(nHandle)

&& 2. Test FOPEN()
nHandle := FOpen(cFile, 0)
Assert.True(nHandle > 0, "FOpen should open existing file")
FClose(nHandle)

&& 3. Test expected failure (non existent file)
LOCAL nBadHandle AS INT64
nBadHandle := FOpen("non_existent_file.txt", 0)
Assert.Equal(-1L, nBadHandle)

IF FILE(cFile)
File.Delete(cFile)
ENDIF
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FCreateAndFOpenTest() deletes the temp file only at the end of the method. If an assertion fails earlier, the temp file and/or an open handle may be left behind, which can pollute subsequent runs. Wrap the test body in TRY/FINALLY and ensure FClose() (when needed) and deletion of cFile happen in FINALLY.

Suggested change
cFile := Path.Combine(Path.GetTempPath(), "vfp_test_" + Guid.NewGuid():ToString("N") + ".txt")
&& 1. Test FCREATE()
nHandle := FCreate(cFile, 0)
Assert.True(nHandle > 0, "FCreate should return a valid handle")
nWritten := FPuts(nHandle, "XSharp VFP File Test")
Assert.True(nWritten > 0, "Should have written data in the file")
FClose(nHandle)
&& 2. Test FOPEN()
nHandle := FOpen(cFile, 0)
Assert.True(nHandle > 0, "FOpen should open existing file")
FClose(nHandle)
&& 3. Test expected failure (non existent file)
LOCAL nBadHandle AS INT64
nBadHandle := FOpen("non_existent_file.txt", 0)
Assert.Equal(-1L, nBadHandle)
IF FILE(cFile)
File.Delete(cFile)
ENDIF
LOCAL nBadHandle AS INT64
cFile := Path.Combine(Path.GetTempPath(), "vfp_test_" + Guid.NewGuid():ToString("N") + ".txt")
nHandle := 0
TRY
&& 1. Test FCREATE()
nHandle := FCreate(cFile, 0)
Assert.True(nHandle > 0, "FCreate should return a valid handle")
nWritten := FPuts(nHandle, "XSharp VFP File Test")
Assert.True(nWritten > 0, "Should have written data in the file")
IF nHandle > 0
FClose(nHandle)
nHandle := 0
ENDIF
&& 2. Test FOPEN()
nHandle := FOpen(cFile, 0)
Assert.True(nHandle > 0, "FOpen should open existing file")
IF nHandle > 0
FClose(nHandle)
nHandle := 0
ENDIF
&& 3. Test expected failure (non existent file)
nBadHandle := FOpen("non_existent_file.txt", 0)
Assert.Equal(-1L, nBadHandle)
FINALLY
IF nHandle > 0
FClose(nHandle)
ENDIF
IF FILE(cFile)
File.Delete(cFile)
ENDIF
END TRY

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants