Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions src/Runtime/XSharp.VFP.Tests/FoxArraytests.prg
Original file line number Diff line number Diff line change
Expand Up @@ -348,4 +348,117 @@ BEGIN NAMESPACE XSharp.VFP.Tests
Assert.Equal(100U, ALen(arr,1))
Assert.Equal(0U, ALen(arr,2))
END CLASS

CLASS ALinesTests
[Fact, Trait("Category", "ALines")];
METHOD BasicParsingTest() AS VOID
DIMENSION aTest[1]
LOCAL cText := e"Line1\r\nLine2\r\nLine3\r\nLine4" AS STRING

VAR nCount := aLines(aTest, cText)

Assert.Equal(4, (INT)nCount)
Assert.Equal(4, (INT)ALen(aTest))
Assert.Equal("Line1", aTest[1])
Assert.Equal("Line2", aTest[2])
Assert.Equal("Line3", aTest[3])
Assert.Equal("Line4", aTest[4])
END METHOD

[Fact, Trait("Category", "ALines")];
METHOD CustomSeparatorTest() AS VOID
DIMENSION aTest[1]
VAR nCount := aLines(aTest, "A,B,C", 0, ",")

Assert.Equal(3, (INT)nCount)
Assert.Equal("B", aTest[2])
END METHOD

[Fact, Trait("Category", "ALines")];
METHOD MultiSeparatorTest() AS VOID
DIMENSION aTest[1]
VAR nCount := aLines(aTest, "One.Two,Three;Four", 0, ".", ",", ";")

Assert.Equal(4, (INT)nCount)
Assert.Equal("Two", aTest[2])
Assert.Equal("Three", aTest[3])
END METHOD


[Fact, Trait("Category", "ALines")];
METHOD FlagTrimTest() AS VOID
DIMENSION aTest[1]
VAR cText := " Item1 , Item2 "

&& Without Trim
aLines(aTest, cText, 0, ",")
Assert.Equal(" Item1 ", aTest[1])

&& With Trim
aLines(aTest, cText, 1, ",")
Assert.Equal("Item1", aTest[1])
Assert.Equal("Item2", aTest[2])
END METHOD

[Fact, Trait("Category", "ALines")];
METHOD FlagNoEmptyTest() AS VOID
DIMENSION aTest[1]
VAR cText := "A,,B,,,C"

&& Without flag (must include empty lines)
VAR nAll := aLines(aTest, cText, 0, ",")
Assert.Equal(6, (INT)nAll)

&& With flag (just content)
VAR nNoEmpty := aLines(aTest, cText, 4, ",")
Assert.Equal(3, (INT)nNoEmpty)
Assert.Equal("B", aTest[2])
Assert.Equal("C", aTest[3])
END METHOD

[Fact, Trait("Category", "ALines")];
METHOD FlagCaseInsensitiveTest() AS VOID
DIMENSION aTest[1]
VAR cText := "User<br>Name<BR>Age"

&& No flag (case sensitive) -> do not cut <BR>
VAR nSensitive := aLines(aTest, cText, 0, "<br>")
Assert.Equal(2, (INT)nSensitive)

&& With flag (case insensitive) -> cut <BR>
VAR nInsensitive := aLines(aTest, cText, 8, "<br>")
Assert.Equal(3, (INT)nInsensitive)
Assert.Equal("Age", aTest[3])
END METHOD

[Fact, Trait("Category", "ALines")];
METHOD FlagIncludeSeparatorTest() AS VOID
DIMENSION aTest[1]
VAR cText := "A,B"

VAR nCount := aLines(aTest, cText, 16, ",")
Assert.Equal(3, (INT)nCount)
Assert.Equal("A", aTest[1])
Assert.Equal(",", aTest[2])
Assert.Equal("B", aTest[3])
END METHOD

[Fact, Trait("Category", "ALines")];
METHOD FlagIncludeLastTest() AS VOID
DIMENSION aTest[1]
VAR cText := "A,B,"

&& Case 1: without flag (default) -> "A", "B" (ignore last empty)
VAR nCount1 := aLines(aTest, cText, 0, ",")
Assert.Equal(2, (INT)nCount1)
Assert.Equal("B", aTest[2])

&& Case 2: with flag -> "A", "B", "" (include last empty)
VAR nCount2 := aLines(aTest, cText, 2, ",")
Assert.Equal(3, (INT)nCount2)
Assert.Equal("", aTest[3])

END METHOD

END CLASS
END NAMESPACE
91 changes: 91 additions & 0 deletions src/Runtime/XSharp.VFP/ArrayFunctions.prg
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
//

USING XSharp.Internal
USING System.Text.RegularExpressions
USING System.Collections.Generic
USING System.Text


INTERNAL FUNCTION FoxALen(a as ARRAY) AS DWORD
Expand Down Expand Up @@ -233,4 +236,92 @@ RETURN

END FUNCTION

/// <include file="VfpRuntimeDocs.xml" path="Runtimefunctions/alines/*" />
FUNCTION ALines (ArrayName AS ARRAY, cExpression AS STRING, nFlags := 0 AS INT, cParseChars PARAMS STRING[]) AS DWORD
IF cExpression == null
cExpression := ""
ENDIF

VAR separators := List<STRING>{}

IF cParseChars == NULL OR cParseChars:Length == 0
separators:Add(e"\r\n")
separators:Add(e"\r")
separators:Add(e"\n")
ELSE
separators:AddRange(cParseChars)
ENDIF

LOCAL lTrim := (nFlags & ALINES_TRIM) != 0 AS LOGIC // 1
LOCAL lIncludeLast := (nFlags & ALINES_INCLUDE_LAST) != 0 AS LOGIC // 2
LOCAL lNoEmpty := (nFlags & ALINES_NO_EMPTY) != 0 AS LOGIC // 4
LOCAL lIgnoreCase := (nFlags & ALINES_CASE_IGNORE) != 0 AS LOGIC // 8
LOCAL lIncludeSep := (nFlags & ALINES_INCLUDE_SEP) != 0 AS LOGIC // 16

var sbPattern := StringBuilder{}
FOREACH VAR sep IN separators
IF sbPattern:Length > 0
sbPattern:Append("|")
ENDIF

VAR safeSep := Regex.Escape(sep)
IF lIncludeSep
sbPattern:Append("(" + safeSep + ")")
ELSE
sbPattern:Append("(?:" + safeSep + ")")
ENDIF
NEXT

VAR regexOptions := RegexOptions.None
IF lIgnoreCase
regexOptions := RegexOptions.IgnoreCase
ENDIF

VAR aRawParts := Regex.Split(cExpression, sbPattern:ToString(), regexOptions)

VAR finalLines := List<STRING>{}
VAR nIndex := 0

FOREACH VAR sLine IN aRawParts
VAR sTemp := sLine

VAR lIsSeparator := FALSE
IF lIncludeSep
lIsSeparator := (nIndex % 2) == 1
ENDIF

IF lTrim AND !lIsSeparator
sTemp := sTemp:Trim()
ENDIF

IF lNoEmpty AND String.IsNullOrEmpty(sTemp) AND !lIsSeparator
nIndex++
LOOP
ENDIF

finalLines:Add(sTemp)
nIndex++
NEXT

IF !lIncludeLast AND !lNoEmpty AND finalLines:Count > 0
VAR nLastIdx := finalLines:Count - 1
IF String.IsNullOrEmpty(finalLines[nLastIdx])
finalLines:RemoveAt(nLastIdx)
ENDIF
ENDIF

VAR nRows := (DWORD)finalLines:Count

IF nRows == 0 AND !lNoEmpty
nRows := 1
finalLines:Add("")
ENDIF

ASize(ArrayName, nRows)

FOR VAR i := 0 TO (INT)nRows - 1
ArrayName[i + 1] := finalLines[i]
NEXT

RETURN nRows
END FUNCTION
7 changes: 7 additions & 0 deletions src/Runtime/XSharp.VFP/Defines.prg
Original file line number Diff line number Diff line change
Expand Up @@ -1490,3 +1490,10 @@ DEFINE STRCNV_UNIBE_SB := 18
DEFINE STRCNV_ID_LCID := 0
DEFINE STRCNV_ID_CODEPAGE := 1
DEFINE STRCNV_ID_CHARSET := 2

// ALINES Flags
DEFINE ALINES_TRIM := 1
DEFINE ALINES_INCLUDE_LAST := 2
DEFINE ALINES_NO_EMPTY := 4
DEFINE ALINES_CASE_IGNORE := 8
DEFINE ALINES_INCLUDE_SEP := 16
6 changes: 0 additions & 6 deletions src/Runtime/XSharp.VFP/ToDo-A.prg
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,6 @@ FUNCTION AGetFileVersion (ArrayName, cFileName)
THROW NotImplementedException{}
//RETURN 0

/// <summary>-- todo --</summary>
/// <include file="VFPDocs.xml" path="Runtimefunctions/alines/*" />
FUNCTION ALines (ArrayName, cExpression , nFlags , cParseChar , cParseChar2 )
THROW NotImplementedException{}
//RETURN 0

/// <summary>-- todo --</summary>
/// <include file="VFPDocs.xml" path="Runtimefunctions/amembers/*" />
FUNCTION AMembers (ArrayName, oObjectNameOrClassName , nArrayContentsID , cFlags)
Expand Down