Skip to main content

contains

Short summary

This assertion method checks if the current string stringToCheck contains the search string searchString. 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
searchStringPOINTER TO BYTEstring must be found in stringToCheckinput
ignoreCasesBOOLTRUE means ignore cases; FALSE means that cases must be equal tooinput
messageAssertMessagemessage if the assertion is falseinput
normalizeStringsBOOLnormalize both strings for checkinput

Code

Declaration

{attribute 'analysis' := '-130'}
METHOD contains
VAR_INPUT
(* current string to check *)
stringToCheck :POINTER TO BYTE;
(* string must be found in ``stringToCheck`` *)
searchString :POINTER TO BYTE;
(* ``TRUE`` means ignore cases; ``FALSE`` means that cases must be equal too *)
ignoreCases :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 *)
usedSearchCodePoints, normalizedUsedSearchCodePoints :POINTER TO CNM_UnicodeUtilities.UnicodeCodePoint;
usedSearchCodePointCount :UDINT;

(* code point index for the comperation *)
codePointIndex :UDINT;
maxSearchIndex :LINT;
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 := searchString, byteCount => lengthSearchStringInByte);

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



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

usedSearchCodePoints := __NEW(CNM_UnicodeUtilities.UnicodeCodePoint, lengthSearchStringInByte);
IF (usedSearchCodePoints = 0) THEN
__DELETE(usedCodePointsToCheck);
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('contains, 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 := searchString,
utf8StringByteCount := lengthSearchStringInByte,
codePointBuffer := usedSearchCodePoints,
bufferSize := SIZEOF(CNM_UnicodeUtilities.UnicodeCodePoint) * lengthSearchStringInByte,
codePointsCount => usedSearchCodePointCount);



IF normalizeStrings THEN
normalizedUsedCodePointsToCheck := __NEW(CNM_UnicodeUtilities.UnicodeCodePoint, (lengthStringToCheckInByte * NORMALIZATION_FACTOR));
IF (normalizedUsedCodePointsToCheck = 0) THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('contains, malloc failed'));
__DELETE(usedCodePointsToCheck);
__DELETE(usedSearchCodePoints);
RETURN;
END_IF
normalizedUsedSearchCodePoints := __NEW(CNM_UnicodeUtilities.UnicodeCodePoint, (lengthSearchStringInByte * NORMALIZATION_FACTOR));
IF (normalizedUsedSearchCodePoints = 0) THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('contains, malloc failed'));
__DELETE(usedCodePointsToCheck);
__DELETE(usedSearchCodePoints);
__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 := usedSearchCodePoints,
codePointsCount := usedSearchCodePointCount,
normalizedCodepoints := normalizedUsedSearchCodePoints,
bufferSize := (lengthSearchStringInByte * NORMALIZATION_FACTOR) * SIZEOF(CNM_UnicodeUtilities.UnicodeCodePoint),
normalizedCodepointsCount => usedSearchCodePointCount
);
__DELETE(usedSearchCodePoints);
usedSearchCodePoints := normalizedUsedSearchCodePoints;
END_IF

IF (ignoreCases) THEN
CNM_UnicodeUtilities.GetUpperCaseForCodepoint(usedCodePointsToCheck, usedCodePointToCheckCount);
CNM_UnicodeUtilities.GetUpperCaseForCodepoint(usedSearchCodePoints, usedSearchCodePointCount);
END_IF
maxSearchIndex := TO_LINT(usedCodePointToCheckCount) - TO_LINT(usedSearchCodePointCount);
WHILE (codePointIndex <= maxSearchIndex) DO
IF (
Tc2_System.MEMCMP(
ADR(usedCodePointsToCheck[codePointIndex]),
usedSearchCodePoints,
usedSearchCodePointCount*SIZEOF(CNM_UnicodeUtilities.UnicodeCodePoint)
) = CNM_ReturnTypes.ComparationResult.EQUAL
) THEN
__DELETE(usedCodePointsToCheck);
__DELETE(usedSearchCodePoints);

RETURN;
END_IF;

codePointIndex := codePointIndex + 1;
END_WHILE

THIS^.assertionWasWrong(message, THIS^.getDebugInfo('contains'));

__DELETE(usedCodePointsToCheck);
__DELETE(usedSearchCodePoints);