Skip to main content

lengthIsExact

Short summary

This assertion method checks if the current string stringToCheck is length is equal to expectedLength

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

Parameters

NameTypeCommentKind
stringToCheckPOINTER TO WORDcurrent string to checkinput
expectedLengthUDINTexpected length of stringToCheckinput
stringLengthUnitUnicodeStringLengthUnitstring length units of measurementinput
messageAssertMessagemessage if the assertion is falseinput

Code

Declaration

METHOD lengthIsExact
VAR_INPUT
(* current string to check *)
stringToCheck :POINTER TO WORD;
(* expected length of ``stringToCheck`` *)
expectedLength :UDINT;
(* string length units of measurement *)
stringLengthUnit :UnicodeStringLengthUnit;
(* message if the assertion is false *)
message :AssertMessage;
END_VAR
VAR
(* length of ``stringToCheck`` *)
stringToCheckWordCount, stringToCheckCodePointCount, stringToCheckByteCount :UDINT;
normalizedStringBuffer :POINTER TO WORD;
buffersize, normalizedLength :UDINT;
width :DINT;
visibleCharacters :UDINT := 0;
END_VAR
VAR CONSTANT
(*After decomposition one codepoint can extend up to 4 codepoints*)
NORMALIZATION_FACTOR :UDINT := 4;
END_VAR

Implementation

CNM_UnicodeUtilities.GetUtf16StringLength(
stringToCheck,
wordCount => stringToCheckWordCount,
characterCount => stringToCheckCodePointCount
);
stringToCheckByteCount := 2 * stringToCheckWordCount;

// check if string is empty
IF (stringToCheckWordCount = 0) THEN
IF (expectedLength <> 0) THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('utf16LengthIsExact'));
END_IF
RETURN;
END_IF

CASE (stringLengthUnit) OF
UnicodeStringLengthUnit.BYTES:
IF (stringToCheckByteCount <> expectedLength) THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('utf16LengthIsExact'));
END_IF

UnicodeStringLengthUnit.CHARACTERS:
IF (stringToCheckCodePointCount <> expectedLength) THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('utf16LengthIsExact'));
END_IF

UnicodeStringLengthUnit.CHARACTERS_NFC:
// string size cant increase with NFC
normalizedStringBuffer := __NEW(WORD, (stringToCheckWordCount+1));
IF normalizedStringBuffer = 0 THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('utf16LengthIsExact, malloc failed'));
RETURN;
END_IF

buffersize := stringToCheckByteCount+SIZEOF(WORD);

CNM_UnicodeUtilities.NormalizeUtf16String(
utf16StringBuffer := stringToCheck,
normalForm := CNM_UnicodeUtilities.NormalizationForm.NFC,
normalizedStringBuffer := normalizedStringBuffer,
bufferSize := buffersize,
normalizedStringLength => normalizedLength
);

CNM_UnicodeUtilities.GetUtf16StringLength(
utf16StringAddress := normalizedStringBuffer,
characterCount => stringToCheckCodePointCount
);

__DELETE(normalizedStringBuffer);

IF (stringToCheckCodePointCount <> expectedLength) THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('utf16LengthIsExact'));
END_IF

UnicodeStringLengthUnit.CHARACTERS_NFD:
// string size can increase with NFD
normalizedStringBuffer := __NEW(WORD, ( NORMALIZATION_FACTOR * stringToCheckWordCount + 1));
IF normalizedStringBuffer = 0 THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('utf16LengthIsBetween, malloc failed'));
RETURN;
END_IF

// stringsize can increase for NFD + NULL terminator word
buffersize := stringToCheckByteCount * NORMALIZATION_FACTOR + SIZEOF(WORD);

CNM_UnicodeUtilities.NormalizeUtf16String(
utf16StringBuffer := stringToCheck,
normalForm := CNM_UnicodeUtilities.NormalizationForm.NFD,
normalizedStringBuffer := normalizedStringBuffer,
bufferSize := buffersize,
normalizedStringLength => normalizedLength
);

CNM_UnicodeUtilities.GetUtf16StringLength(
utf16StringAddress := normalizedStringBuffer,
characterCount => stringToCheckCodePointCount
);

__DELETE(normalizedStringBuffer);

IF (stringToCheckCodePointCount <> expectedLength) THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('utf16LengthIsExact'));
END_IF

UnicodeStringLengthUnit.VISIBLE_CHARACTERS:
CNM_UnicodeUtilities.GetUtf16StringWidth( utf16StringBuffer := stringToCheck, visibleCharacters => visibleCharacters);
IF (visibleCharacters <> expectedLength)THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('utf16lengthIsExact'));
END_IF

UnicodeStringLengthUnit.WIDTH:
width := CNM_UnicodeUtilities.GetUtf16StringWidth(stringToCheck);
IF ((width < 0) OR_ELSE (TO_UDINT(width) <> expectedLength)) THEN
THIS^.assertionWasWrong(message, THIS^.getDebugInfo('utf16LengthIsExact'));
END_IF
ELSE
; // do nothing
END_CASE