TStr TNodeJsFPath::GetCanonicalPath(const TStr& FPath) { // Get absolute path TStr AbsFPath = TStr::GetNrAbsFPath(FPath); // Remove any redundancies TStrV CanonV; AbsFPath.SplitOnAllCh('/', CanonV); TSStack<TStr> CanonS; TStr CurrStr; for (int ElN = 0; ElN < CanonV.Len(); ++ElN) { CurrStr = CanonV.GetVal(ElN); if (CurrStr == "..") { EAssertR(!CanonS.Empty(), "Stack empty"); CanonS.Pop(); } else if (CurrStr != ".") { CanonS.Push(CurrStr+"/"); } } // Assemble the canonical path (from left to right EAssertR(!CanonS.Empty(), "Stack empty"); // We start with drive letter (Windows) or slash (Unix) TChA CanonFPath = AbsFPath.LeftOf('/'); CanonFPath += '/'; // Get the rest of the path for (int CanonN = CanonS.Len() - 1; CanonN >= 0; CanonN--) { CanonFPath += CanonS[CanonN]; } // Done return CanonFPath; }
TEST(TStr, LeftOfRightOf) { TStr Str = "abcdef"; TStr Empty = ""; EXPECT_EQ(Str.LeftOf('d'), "abc"); EXPECT_EQ(Str.RightOf('c'), "def"); EXPECT_EQ(Str.LeftOf('a'), ""); EXPECT_EQ(Empty.RightOf('c'), ""); // edge cases EXPECT_EQ(Str.RightOf('f'), ""); EXPECT_EQ(Empty.LeftOf('d'), ""); TStr Str2 = "abcdefabcdef"; EXPECT_EQ(Str2.LeftOfLast('d'), "abcdefabc"); EXPECT_EQ(Str2.RightOfLast('c'), "def"); EXPECT_EQ(Empty.LeftOfLast('d'), ""); EXPECT_EQ(Empty.RightOfLast('c'), ""); // edge cases Str2 = "xabcdefabcdef"; EXPECT_EQ(Str2.LeftOfLast('x'), ""); EXPECT_EQ(Str2.RightOfLast('f'), ""); }