Skip to content

Commit

Permalink
Merge pull request #11938 from keymanapp/fix/developer/11937-correct-…
Browse files Browse the repository at this point in the history
…handling-of-trailing-spaces-by-GetDelimitedString

fix(developer): correct handling of trailing spaces by GetDelimitedString() in kmcmplib compiler
  • Loading branch information
markcsinclair authored Jul 23, 2024
2 parents 98c12d5 + 76384a1 commit 1449f13
Show file tree
Hide file tree
Showing 2 changed files with 275 additions and 6 deletions.
35 changes: 30 additions & 5 deletions developer/src/kmcmplib/src/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1702,7 +1702,27 @@ KMX_DWORD ExpandKp(PFILE_KEYBOARD fk, PFILE_KEY kpp, KMX_DWORD storeIndex)
return CERR_None;
}


/**
* When called with a pointer to a wide-character C-string string, the open and close delimiters, and
* optional flags, returns a pointer to the section of the KMX_WCHAR string identified by the delimiters.
* The supplied string will be terminated by a null where the close delimiter was. The pointer to the supplied
* string is adjusted to point either to the null where the close delimiter was, or if there are trailing
* whitespaces after the close delimiter, to the last of these. Whitespaces before the open delimiter
* are always skipped. If the flag contains GDS_CUTLEAD, whitespaces after the open delimiter are skipped;
* if the flag contains GDS_CUTFOLL, whitespace immediately before the close delimiter is skipped by setting
* the first such character to null.
*
* @param p a pointer to a wide-character C-string
*
* @param Delimiters a pointer to a two-character wide-character C-string containing the open and close
* delimiters
*
* @param Flags include GDS_CUTLEAD and/or GDS_CUTFOLL to cut leading and/or following whitespace from
* the delimited string
*
* @return a pointer to the section of the wide-character C-string identified by the delimiters, or NULL if
* the delimiters cannot be found
*/
PKMX_WCHAR GetDelimitedString(PKMX_WCHAR *p, KMX_WCHAR const * Delimiters, KMX_WORD Flags)
{
PKMX_WCHAR q, r;
Expand All @@ -1724,15 +1744,20 @@ PKMX_WCHAR GetDelimitedString(PKMX_WCHAR *p, KMX_WCHAR const * Delimiters, KMX_W
while (iswspace(*q)) q++; // cut off leading spaces

if (Flags & GDS_CUTFOLL)
if (!iswspace(*(r - 1))) *r = 0;
if (!iswspace(*(r - 1))) *r = 0; // delete close delimiter
else
{
r--; // Cut off following spaces
while (iswspace(*r) && r > q) r--;
r++;
*r = 0; r = (PKMX_WCHAR) u16chr((r + 1), dClose);
if (!iswspace(*r)) r++;

*r = 0; // delete first following space

r = (PKMX_WCHAR) u16chr((r + 1), dClose);

*r = 0; // delete close delimiter
}
else *r = 0;
else *r = 0; // delete close delimiter

r++; while (iswspace(*r)) r++; // Ignore spaces after the close
if (*r == 0) r--; // Safety for terminating strings.
Expand Down
246 changes: 245 additions & 1 deletion developer/src/kmcmplib/tests/gtest-compiler-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ KMX_BOOL AddCompileError(KMX_DWORD msg);
KMX_DWORD ProcessBeginLine(PFILE_KEYBOARD fk, PKMX_WCHAR p);
KMX_DWORD ValidateMatchNomatchOutput(PKMX_WCHAR p);
KMX_BOOL IsValidKeyboardVersion(KMX_WCHAR *dpString);
PKMX_WCHAR GetDelimitedString(PKMX_WCHAR *p, KMX_WCHAR const * Delimiters, KMX_WORD Flags);
KMX_DWORD GetXStringImpl(PKMX_WCHAR tstr, PFILE_KEYBOARD fk, PKMX_WCHAR str, KMX_WCHAR const * token,
PKMX_WCHAR output, int max, int offset, PKMX_WCHAR *newp, int isUnicode
);
Expand Down Expand Up @@ -310,7 +311,250 @@ TEST_F(CompilerTest, ProcessKeyLineImpl_test) {

// KMX_DWORD ExpandKp_ReplaceIndex(PFILE_KEYBOARD fk, PFILE_KEY k, KMX_DWORD keyIndex, int nAnyIndex)
// KMX_DWORD ExpandKp(PFILE_KEYBOARD fk, PFILE_KEY kpp, KMX_DWORD storeIndex)
// PKMX_WCHAR GetDelimitedString(PKMX_WCHAR *p, KMX_WCHAR const * Delimiters, KMX_WORD Flags)

TEST_F(CompilerTest, GetDelimitedString_test) {
KMX_WCHAR str[LINESIZE];
PKMX_WCHAR p = str;
PKMX_WCHAR q = nullptr;

// no open delimiter, cut spaces after open and before close delimiter
u16cpy(str, u"");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD | GDS_CUTFOLL);
EXPECT_FALSE(q);

// no close delimiter, cut spaces after open and before close delimiter
u16cpy(str, u"(");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD | GDS_CUTFOLL);
EXPECT_FALSE(q);

// no argument, cut spaces after open and before close delimiter
u16cpy(str, u"()");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD | GDS_CUTFOLL);
EXPECT_EQ(0, u16cmp(u"", q));
EXPECT_FALSE(*p);
EXPECT_EQ(1, p-str); // deleted close delimiter

// no argument, single space, no flags
u16cpy(str, u"( )");
p = str;
q = GetDelimitedString(&p, u"()", 0x00);
EXPECT_EQ(0, u16cmp(u" ", q));
EXPECT_FALSE(*p);
EXPECT_EQ(2, p-str); // deleted close delimiter

// no argument, single space, cut spaces after open delimiter
u16cpy(str, u"( )");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD);
EXPECT_EQ(0, u16cmp(u"", q));
EXPECT_FALSE(*p);
EXPECT_EQ(2, p-str); // deleted close delimiter

// no argument, single space, cut spaces before close delimiter
u16cpy(str, u"( )");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTFOLL);
EXPECT_EQ(0, u16cmp(u"", q));
EXPECT_FALSE(*p);
EXPECT_EQ(2, p-str); // deleted close delimiter

// no argument, single space, cut spaces after open and before close delimiter
u16cpy(str, u"( )");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD | GDS_CUTFOLL);
EXPECT_EQ(0, u16cmp(u"", q));
EXPECT_FALSE(*p);
EXPECT_EQ(2, p-str); // deleted close delimiter

// no argument, two spaces, no flags
u16cpy(str, u"( )");
p = str;
q = GetDelimitedString(&p, u"()", 0x00);
EXPECT_EQ(0, u16cmp(u" ", q));
EXPECT_FALSE(*p);
EXPECT_EQ(3, p-str); // deleted close delimiter

// no argument, two spaces, cut spaces after open delimiter
u16cpy(str, u"( )");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD);
EXPECT_EQ(0, u16cmp(u"", q));
EXPECT_FALSE(*p);
EXPECT_EQ(3, p-str); // deleted close delimiter

// no argument, two spaces, cut spaces before close delimiter
u16cpy(str, u"( )");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTFOLL);
EXPECT_EQ(0, u16cmp(u"", q));
EXPECT_FALSE(*p);
EXPECT_EQ(3, p-str); // deleted close delimiter

// no argument, two spaces, cut spaces after open and before close delimiter
u16cpy(str, u"( )");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD | GDS_CUTFOLL);
EXPECT_EQ(0, u16cmp(u"", q));
EXPECT_FALSE(*p);
EXPECT_EQ(3, p-str); // deleted close delimiter

// single-character argument, cut spaces after open and before close delimiter, valid
u16cpy(str, u"(b)");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD | GDS_CUTFOLL);
EXPECT_EQ(0, u16cmp(u"b", q));
EXPECT_FALSE(*p);
EXPECT_EQ(2, p-str); // deleted close delimiter

// multi-character argument, cut spaces after open and before close delimiter, valid
u16cpy(str, u"(abc)");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD | GDS_CUTFOLL);
EXPECT_EQ(0, u16cmp(u"abc", q));
EXPECT_FALSE(*p);
EXPECT_EQ(4, p-str); // deleted close delimiter

// multi-word argument, cut spaces after open and before close delimiter, valid
u16cpy(str, u"(abc def)");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD | GDS_CUTFOLL);
EXPECT_EQ(0, u16cmp(u"abc def", q));
EXPECT_FALSE(*p);
EXPECT_EQ(8, p-str); // deleted close delimiter

// single-character argument, leading single space, cut spaces after open and before close delimiter, valid
u16cpy(str, u" (b)");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD | GDS_CUTFOLL);
EXPECT_EQ(0, u16cmp(u"b", q));
EXPECT_FALSE(*p);
EXPECT_EQ(3, p-str); // deleted close delimiter

// single-character argument, leading double space, cut open and close delimiter, valid
u16cpy(str, u" (b)");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD | GDS_CUTFOLL);
EXPECT_EQ(0, u16cmp(u"b", q));
EXPECT_FALSE(*p);
EXPECT_EQ(4, p-str); // deleted close delimiter

// single-character argument, space before argument, cut spaces after open and before close delimiter, valid
u16cpy(str, u"( b)");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD | GDS_CUTFOLL);
EXPECT_EQ(0, u16cmp(u"b", q));
EXPECT_FALSE(*p);
EXPECT_EQ(3, p-str); // deleted close delimiter

// single-character argument, space before argument, no flags, valid
u16cpy(str, u"( b)");
p = str;
q = GetDelimitedString(&p, u"()", 0x00);
EXPECT_EQ(0, u16cmp(u" b", q));
EXPECT_FALSE(*p);
EXPECT_EQ(3, p-str); // deleted close delimiter

// single-character argument, double space before argument, cut spaces after open and before close delimiter, valid
u16cpy(str, u"( b)");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD | GDS_CUTFOLL);
EXPECT_EQ(0, u16cmp(u"b", q));
EXPECT_FALSE(*p);
EXPECT_EQ(4, p-str); // deleted close delimiter

// single-character argument, double space before argument, no flags, valid
u16cpy(str, u"( b)");
p = str;
q = GetDelimitedString(&p, u"()", 0x00);
EXPECT_EQ(0, u16cmp(u" b", q));
EXPECT_FALSE(*p);
EXPECT_EQ(4, p-str); // deleted close delimiter

// single-character argument, space after argument, cut spaces after open and before close delimiter, valid
u16cpy(str, u"(b )");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD | GDS_CUTFOLL);
EXPECT_EQ(0, u16cmp(u"b", q));
EXPECT_FALSE(*p);
EXPECT_EQ(3, p-str); // deleted close delimiter

// single-character argument, space after argument, no flags, valid
u16cpy(str, u"(b )");
p = str;
q = GetDelimitedString(&p, u"()", 0x00);
EXPECT_EQ(0, u16cmp(u"b ", q));
EXPECT_FALSE(*p);
EXPECT_EQ(3, p-str); // deleted close delimiter

// single-character argument, two spaces after argument, cut spaces after open and before close delimiter, valid
u16cpy(str, u"(b )");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD | GDS_CUTFOLL);
EXPECT_EQ(0, u16cmp(u"b", q));
EXPECT_FALSE(*p);
EXPECT_EQ(4, p-str); // deleted close delimiter

// single-character argument, two spaces after argument, no flags, valid
u16cpy(str, u"(b )");
p = str;
q = GetDelimitedString(&p, u"()", 0x00);
EXPECT_EQ(0, u16cmp(u"b ", q));
EXPECT_FALSE(*p);
EXPECT_EQ(4, p-str); // deleted close delimiter

// single-character argument, space after close delimiter, cut spaces after open and before close delimiter, valid
u16cpy(str, u"(b) ");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD | GDS_CUTFOLL);
EXPECT_EQ(0, u16cmp(u"b", q));
EXPECT_EQ(' ', *p);
EXPECT_EQ(3, p-str); // space after the close delimiter

// single-character argument, two spaces after close delimiter, cut spaces after open and before close delimiter, valid
u16cpy(str, u"(b) ");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD | GDS_CUTFOLL);
EXPECT_EQ(0, u16cmp(u"b", q));
EXPECT_EQ(' ', *p);
EXPECT_EQ(4, p-str); // last space after the close delimiter

// single-character argument, two spaces after argument and two spaces after close delimiter,
// cut spaces after open and before close delimiter, valid
u16cpy(str, u"(b ) ");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD | GDS_CUTFOLL);
EXPECT_EQ(0, u16cmp(u"b", q));
EXPECT_EQ(' ', *p);
EXPECT_EQ(6, p-str); // last space after the close delimiter

// single-character argument, two spaces after argument and two spaces after close delimiter, no flags, valid
u16cpy(str, u"(b ) ");
p = str;
q = GetDelimitedString(&p, u"()", 0x00);
EXPECT_EQ(0, u16cmp(u"b ", q));
EXPECT_EQ(' ', *p);
EXPECT_EQ(6, p-str); // last space after the close delimiter

// single-character argument, two spaces and text after close delimiter, cut spaces after open and before close delimiter, valid
u16cpy(str, u"(b) def");
p = str;
q = GetDelimitedString(&p, u"()", GDS_CUTLEAD | GDS_CUTFOLL);
EXPECT_EQ(0, u16cmp(u"b", q));
EXPECT_EQ('d', *p);
EXPECT_EQ(5, p-str); // first text character after the close delimiter

// single-character argument, two spaces and text after close delimiter, no flags, valid
u16cpy(str, u"(b) def");
p = str;
q = GetDelimitedString(&p, u"()", 0x00);
EXPECT_EQ(0, u16cmp(u"b", q));
EXPECT_EQ('d', *p);
EXPECT_EQ(5, p-str); // first text character after the close delimiter
}

// LinePrefixType GetLinePrefixType(PKMX_WCHAR *p)
// int LineTokenType(PKMX_WCHAR *str)
// KMX_BOOL StrValidChrs(PKMX_WCHAR q, KMX_WCHAR const * chrs)
Expand Down

0 comments on commit 1449f13

Please sign in to comment.