Skip to main content

endsWith

Short summary

This assertion method checks if the current string stringToCheck ends with the string end. Processed strings must be in UTF-8 encoding

Attention: All strings are handled as null-terminated byte streams

Parameters

NameTypeCommentKind
stringToCheckPOINTER TO BYTEcurrent string to checkinput
endPOINTER TO BYTEstring must be the end of stringToCheckinput
ignoreCasesBOOLTRUE means ignore cases; FALSE means that 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 BYTE;
(* string must be the end of ``stringToCheck`` *)
end :POINTER TO BYTE;
(* ``TRUE`` means ignore cases; ``FALSE`` means that 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 bytes *)
lengthStringToCheckInByte :UDINT;
(* length of ``searchString`` in bytes *)
lengthSearchStringInByte :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.GetUtf8StringLength(stringAddress := stringToCheck, byteCount => lengthStringToCheckInByte);
CNM_UnicodeUtilities.GetUtf8StringLength(stringAddress := end, byteCount => lengthSearchStringInByte);

RETURN (((
NOT normalizeStrings
) OR_ELSE (
lengthStringToCheckInByte = 0
) OR_ELSE (
lengthSearchStringInByte = 0
)
) AND_THEN (
NOT THIS^.isContainsCheckNecessary(
stringToCheck := stringToCheck,
searchString := end,
lengthStringToCheck := lengthStringToCheckInByte,
lengthSearchString := lengthSearchStringInByte,
additionalText := THIS^.getDebugInfo('endsWith'),
message := message
)
)
);

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

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

(* convert ``stringToCheck`` to code points *)
CNM_UnicodeUtilities.GetCodepointsFromUtf8String(
utf8StringAddress := stringToCheck,
utf8StringByteCount := lengthStringToCheckInByte,
codePointBuffer := usedCodePointsToCheck,
bufferSize := SIZEOF(CNM_UnicodeUtilities.UnicodeCodePoint) * lengthStringToCheckInByte,
codePointsCount => usedCodePointToCheckCount);

(* convert ``searchString`` to code points *)
CNM_UnicodeUtilities.GetCodepointsFromUtf8String(
utf8StringAddress := end,
utf8StringByteCount := lengthSearchStringInByte,
codePointBuffer := usedEndCodePoints,
bufferSize := SIZEOF(CNM_UnicodeUtilities.UnicodeCodePoint) * lengthSearchStringInByte,
codePointsCount => usedEndCodePointCount);

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

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

CNM_UnicodeUtilities.NormalizeCodepointsFormD(
codePoints := usedEndCodePoints,
codePointsCount := usedEndCodePointCount,
normalizedCodepoints := normalizedUsedEndCodePoints,
bufferSize := (lengthSearchStringInByte * 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('endsWith'));
END_IF;

__DELETE(usedCodePointsToCheck);
__DELETE(usedEndCodePoints);