public static unsafe string SimplifyPathImpl()

in Sharpmake/PathUtil.cs [199:295]


        public static unsafe string SimplifyPathImpl(string path)
        {
            // First construct a path helper to help with the conversion
            char* arrayPtr = stackalloc char[path.Length + 1];

            int consecutiveDotsCounter = 0;
            bool pathSeparatorWritePending = IsPathSeparator(path[^1]); // Explicitly handle path with a trailing path separator (we want to keep it)
            int writePosition = path.Length;
            int dotDotCounter = 0;

            // Start by the end of the path to easily handle '..' case
            for (int index = path.Length - 1; index >= 0; --index)
            {
                char currentChar = path[index];
                if (IsPathSeparator(currentChar))
                {
                    pathSeparatorWritePending = pathSeparatorWritePending
                        || (consecutiveDotsCounter == -1 && dotDotCounter == 0); // We want to consider this path separator only if we are not on a '.' or '..'

                    HandleDotDotCounter(ref consecutiveDotsCounter, ref dotDotCounter, path);
                }
                else
                {
                    // Count consecutive dots (if there is only dots in the name)
                    if (currentChar == '.' && consecutiveDotsCounter != -1)
                    {
                        ++consecutiveDotsCounter;
                        continue;
                    }

                    if (dotDotCounter == 0)
                    {
                        // Write pending path separator
                        if (pathSeparatorWritePending)
                        {
                            arrayPtr[writePosition--] = Path.DirectorySeparatorChar;
                            pathSeparatorWritePending = false;
                        }

                        // Write held back '.'
                        for (int i = 0; i < consecutiveDotsCounter; ++i)
                        {
                            arrayPtr[writePosition--] = '.';
                        }

                        arrayPtr[writePosition--] = currentChar;
                    }

                    // We encountered something else than '.', now we don't care about them until next path separator
                    consecutiveDotsCounter = -1;
                }
            }

            // Handle additional '..' that was not taken into account nor consummed
            HandleDotDotCounter(ref consecutiveDotsCounter, ref dotDotCounter, path);
            for (int i = 0; i < dotDotCounter; ++i)
            {
                if (pathSeparatorWritePending)
                    arrayPtr[writePosition--] = Path.DirectorySeparatorChar;
                arrayPtr[writePosition--] = '.';
                arrayPtr[writePosition--] = '.';
                pathSeparatorWritePending = true;
            }

            // Handle rooted path on Unix platforms
            if (path[0] == '/')
                arrayPtr[writePosition--] = '/';

            return new string(arrayPtr, writePosition + 1, path.Length - writePosition);

            static bool IsPathSeparator(char c) => c == Path.DirectorySeparatorChar || c == OtherSeparator;

            static void HandleDotDotCounter(ref int consecutiveDotsCounter, ref int dotDotCounter, string path)
            {
                switch (consecutiveDotsCounter)
                {
                    case -1:
                        // We encountered a real folder name (not made exclusively of dots), and it have been skipped if dotDotCounter was not 0, so we decrement it
                        if (dotDotCounter > 0)
                            --dotDotCounter;
                        break;
                    case 0:
                        break;
                    case 1:
                        // skip: "./"
                        break;
                    case 2:
                        ++dotDotCounter;
                        break;
                    default:
                        throw new ArgumentException($"Invalid path format: '{path}' (folder made of three or more consecutive dots detected)");
                }

                // We are on a path separator, consecutive dots counter must be reset
                consecutiveDotsCounter = 0;
            }
        }