Skip to main content

endsWith

Short summary

This assertion method for UTF-16 strings checks if the current string stringToCheck ends with the string end

Attention: All strings are handled as null terminated word streams. For UTF-16 is end of the string 16#00_00

Attention: end of the string is ALWAYS the right side of the string even for writings which written from right to left like Hebrew or Arabic

Parameters

NameTypeCommentKind
stringToCheckPOINTER TO WORDcurrent string to checkinput
endPOINTER TO WORDstring must be the end of stringToCheckinput
ignoreCasesBOOLTRUE means ignore cases; FALSE means cases must be equal tooinput
trimBOOLTRUE means truncation of spaces on the right side of stringToCheckinput
messageAssertMessagemessage if the assertion is falseinput
normalizeStringsBOOLnormalize both strings for checkinput

Code

Declaration

METHOD endsWith
VAR_INPUT
(* current string to check *)
stringToCheck :POINTER TO WORD;
(* string must be the end of ``stringToCheck`` *)
end :POINTER TO WORD;
(* ``TRUE`` means ignore cases; ``FALSE`` means cases must be equal too *)
ignoreCases :BOOL;
(* ``TRUE`` means truncation of spaces on the right side of ``stringToCheck``*)
trim :BOOL;
(* message if the assertion is false *)
message :AssertMessage;
(*normalize both strings for check*)
normalizeStrings :BOOL := TRUE;
END_VAR
VAR
(* length of ``stringToCheck`` in characters *)
lengthStringToCheck :UDINT;
(* length of ``stringToCheck`` in words *)
lengthStringToCheckInWord :UDINT;
(* length of ``searchString`` *)
lengthEndString :UDINT;
(* length of ``searchString`` in words *)
lengthEndStringInWord :UDINT;

(* DWORD array we use to check *)
usedCodePointsToCheck, normalizedUsedCodePointsToCheck :POINTER TO CNM_UnicodeUtilities.UnicodeCodePoint;
usedCodePointToCheckCount :UDINT;

(* DWORD array we use to compare *)
usedEndCodePoints, normalizedUsedEndCodePoints :POINTER TO CNM_UnicodeUtilities.UnicodeCodePoint;
usedEndCodePointCount :UDINT;
END_VAR
VAR CONSTANT
(*After decomposition one codepoint can extend up to 4 codepoints*)
NORMALIZATION_FACTOR :UDINT := 4;
END_VAR

Implementation

CNM_UnicodeUtilities.GetUtf16StringLength(
utf16StringAddress := stringToCheck,
wordCount => lengthStringToCheckInWord
);

CNM_UnicodeUtilities.GetUtf16StringLength(
utf16StringAddress := end,
wordCount => lengthEndStringInWord
);

usedCodePointsToCheck := __NEW(CNM_UnicodeUtilities.UnicodeCodePoint, (lengthStringToCheckInWord+1));
IF (usedCodePointsToCheck = 0) THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('utf16endsWith, malloc failed'));
RETURN;
END_IF

usedEndCodePoints := __NEW(CNM_UnicodeUtilities.UnicodeCodePoint, (lengthEndStringInWord+1));
IF (usedEndCodePoints = 0) THEN
__DELETE(usedCodePointsToCheck);
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('utf16endsWith, malloc failed'));
RETURN;
END_IF

(* convert ``stringToCheck`` to code points *)
CNM_UnicodeUtilities.GetCodepointsFromUtf16String(
utf16StringAddress := stringToCheck,
utf16StringWordCount := lengthStringToCheckInWord,
codepointBuffer := usedCodePointsToCheck,
bufferSize := SIZEOF(CNM_UnicodeUtilities.UnicodeCodePoint)*(lengthStringToCheckInWord+1),
codePointCount => usedCodePointToCheckCount);

(* convert ``searchString`` to code points *)
CNM_UnicodeUtilities.GetCodepointsFromUtf16String(
utf16StringAddress := end,
utf16StringWordCount := lengthEndStringInWord,
codepointBuffer := usedEndCodePoints,
bufferSize := SIZEOF(CNM_UnicodeUtilities.UnicodeCodePoint)*(lengthEndStringInWord+1),
codePointCount => usedEndCodePointCount);

IF (((
NOT normalizeStrings
) OR_ELSE (
(lengthEndStringInWord = 0) OR_ELSE (lengthStringToCheckInWord = 0)
)
) AND_THEN (
NOT THIS^.isContainsCheckNecessary(
stringToCheck := usedCodePointsToCheck,
searchString := usedEndCodePoints,
lengthStringToCheck := usedCodePointToCheckCount * SIZEOF(CNM_UnicodeUtilities.UnicodeCodePoint),
lengthSearchString := usedEndCodePointCount * SIZEOF(CNM_UnicodeUtilities.UnicodeCodePoint),
additionalText := THIS^.getDebugInfo('utf16endsWith'),
message := message
)
)
) THEN
__DELETE(usedCodePointsToCheck);
__DELETE(usedEndCodePoints);
RETURN;
END_IF

IF normalizeStrings THEN
normalizedUsedCodePointsToCheck := __NEW(CNM_UnicodeUtilities.UnicodeCodePoint, (lengthStringToCheckInWord * NORMALIZATION_FACTOR));
IF (normalizedUsedCodePointsToCheck = 0) THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('utf16endsWith'));
__DELETE(usedCodePointsToCheck);
__DELETE(usedEndCodePoints);
RETURN;
END_IF
normalizedUsedEndCodePoints := __NEW(CNM_UnicodeUtilities.UnicodeCodePoint, (lengthEndStringInWord * NORMALIZATION_FACTOR));
IF (normalizedUsedEndCodePoints = 0) THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('utf16endsWith'));
__DELETE(usedCodePointsToCheck);
__DELETE(usedEndCodePoints);
__DELETE(normalizedUsedCodePointsToCheck);
RETURN;
END_IF

CNM_UnicodeUtilities.NormalizeCodepointsFormD(
codePoints := usedCodePointsToCheck,
codePointsCount := usedCodePointToCheckCount,
normalizedCodepoints := normalizedUsedCodePointsToCheck,
bufferSize := (lengthStringToCheckInWord * NORMALIZATION_FACTOR) * SIZEOF(CNM_UnicodeUtilities.UnicodeCodePoint),
normalizedCodepointsCount => usedCodePointToCheckCount
);
__DELETE(usedCodePointsToCheck);
usedCodePointsToCheck := normalizedUsedCodePointsToCheck;

CNM_UnicodeUtilities.NormalizeCodepointsFormD(
codePoints := usedEndCodePoints,
codePointsCount := usedEndCodePointCount,
normalizedCodepoints := normalizedUsedEndCodePoints,
bufferSize := (lengthEndStringInWord * NORMALIZATION_FACTOR) * SIZEOF(CNM_UnicodeUtilities.UnicodeCodePoint),
normalizedCodepointsCount => usedEndCodePointCount
);
__DELETE(usedEndCodePoints);
usedEndCodePoints := normalizedUsedEndCodePoints;
END_IF

IF trim THEN
CNM_UnicodeUtilities.TrimRightCodepoints(
codepoints := usedCodePointsToCheck,
codepointCount := usedCodePointToCheckCount,
newCodepointCount => usedCodePointToCheckCount
);
CNM_UnicodeUtilities.TrimRightCodepoints(
codepoints := usedEndCodePoints,
codepointCount := usedEndCodePointCount,
newCodepointCount => usedEndCodePointCount
);
END_IF

IF (ignoreCases) THEN
CNM_UnicodeUtilities.GetUpperCaseForCodepoint(usedCodePointsToCheck, usedCodePointToCheckCount);
CNM_UnicodeUtilities.GetUpperCaseForCodepoint(usedEndCodePoints, usedEndCodePointCount);
END_IF

IF ((usedCodePointToCheckCount < usedEndCodePointCount) OR_ELSE
(Tc2_System.MEMCMP(
ADR(usedCodePointsToCheck[usedCodePointToCheckCount - usedEndCodePointCount]),
usedEndCodePoints,
usedEndCodePointCount*SIZEOF(CNM_UnicodeUtilities.UnicodeCodePoint)
) <> CNM_ReturnTypes.ComparationResult.EQUAL)
) THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('utf16endsWith'));
END_IF;

__DELETE(usedCodePointsToCheck);
__DELETE(usedEndCodePoints);