/// <summary> /// Reads until the specified <paramref name="keychar" /> is encountered. <paramref name="keychar" /> will not be included in the returned string. /// </summary> /// <param name="reader">A <see cref="TextReader" /> object.</param> /// <param name="keychar">The <paramref name="reader" /> will advance its position to the character immediately after the next occurrence of this <paramref name="keychar" />.</param> /// <param name="returnIfKeycharNotFound"><c>true</c> if a string starting from the reader's current position to the end should be returned if no <paramref name="keychar"/> is encountered in reading; <c>false</c> if <c>null</c> should be returned in this situation.</param> /// <returns>A <see cref="string" /> read from the <see cref="TextReader" /> from its current position to the position of the specified <paramref name="keychar" />, or to the end of the <paramref name="reader"/> if no such <paramref name="keychar"/> is found.</returns> public static string ReadTo(this TextReader reader, char keychar, bool returnIfKeycharNotFound = true) { var sb = StringBuilderCache.Acquire(); int ci; while ((ci = reader.Read()) != -1) { if (ci == keychar) { return(StringBuilderCache.GetStringAndRelease(sb)); } else { sb.Append((char)ci); } } if (returnIfKeycharNotFound) { return(StringBuilderCache.GetStringAndRelease(sb)); } else { StringBuilderCache.Release(sb); return(null); } }
/// <summary> /// Reads until the specified <paramref name="keyword" /> is encountered. <paramref name="keyword" /> will be included at the end of the returned string. /// </summary> /// <param name="reader">A <see cref="TextReader" /> object.</param> /// <param name="keyword">The <paramref name="reader" /> will advance its position to the character immediately after the next occurrence of this <paramref name="keyword" />.</param> /// <param name="returnIfKeywordNotFound"><c>true</c> if a string starting from the reader's current position to the end should be returned if no <paramref name="keyword"/> is encountered in reading; <c>false</c> if <c>null</c> should be returned in this situation.</param> /// <returns>A <see cref="string" /> read from the <see cref="TextReader" /> from its current position to the position of the specified <paramref name="keyword" /> with <paramref name="keyword"/> at the end of the returned <see cref="string"/>, or to the end of the <paramref name="reader"/> if no such <paramref name="keyword"/> is found.</returns> public static string ReadAfter(this TextReader reader, string keyword, bool returnIfKeywordNotFound = true) { var i = 0; int ci; var sb = StringBuilderCache.Acquire(); while ((ci = reader.Read()) != -1) { var c = (char)ci; if (c == keyword[i]) { ++i; if (i == keyword.Length) { sb.Append(keyword); return(StringBuilderCache.GetStringAndRelease(sb)); } } else { if (i != 0) { sb.Append(keyword.Substring(0, i)); i = 0; } if (c == keyword[0]) { ++i; } else { sb.Append(c); } } } if (returnIfKeywordNotFound) { return(StringBuilderCache.GetStringAndRelease(sb)); } else { StringBuilderCache.Release(sb); return(null); } }
private static async Task <string> InternalReadAllTextAsync(string path, Encoding encoding, CancellationToken cancellationToken) { Debug.Assert(!string.IsNullOrEmpty(path)); Debug.Assert(encoding != null); char[] buffer = null; StringBuilder sb = null; StreamReader sr = AsyncStreamReader(path, encoding); try { cancellationToken.ThrowIfCancellationRequested(); sb = StringBuilderCache.Acquire(); buffer = ArrayPool <char> .Shared.Rent(sr.CurrentEncoding.GetMaxCharCount(DefaultBufferSize)); for (;;) { int read = await sr.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); if (read == 0) { return(sb.ToString()); } sb.Append(buffer, 0, read); cancellationToken.ThrowIfCancellationRequested(); } } finally { sr.Dispose(); if (buffer != null) { ArrayPool <char> .Shared.Return(buffer); } if (sb != null) { StringBuilderCache.Release(sb); } } }
private void WriteFormatHelper(string format, ParamsArray args, bool appendNewLine) { StringBuilder sb = StringBuilderCache.Acquire((format?.Length ?? 0) + args.Length * 8) .AppendFormatHelper(null, format !, args); // AppendFormatHelper will appropriately throw ArgumentNullException for a null format StringBuilder.ChunkEnumerator chunks = sb.GetChunks(); bool more = chunks.MoveNext(); while (more) { ReadOnlySpan <char> current = chunks.Current.Span; more = chunks.MoveNext(); // If final chunk, include the newline if needed WriteSpan(current, appendNewLine: more?false: appendNewLine); } StringBuilderCache.Release(sb); }
public override string GetCurrentDirectory() { StringBuilder sb = StringBuilderCache.Acquire(Interop.mincore.MAX_PATH + 1); if (Interop.mincore.GetCurrentDirectory(sb.Capacity, sb) == 0) { throw Win32Marshal.GetExceptionForLastWin32Error(); } String currentDirectory = sb.ToString(); // Note that if we have somehow put our command prompt into short // file name mode (ie, by running edlin or a DOS grep, etc), then // this will return a short file name. if (currentDirectory.IndexOf('~') >= 0) { int r = Interop.mincore.GetLongPathName(currentDirectory, sb, sb.Capacity); if (r == 0 || r >= Interop.mincore.MAX_PATH) { int errorCode = Marshal.GetLastWin32Error(); if (r >= Interop.mincore.MAX_PATH) { errorCode = Interop.mincore.Errors.ERROR_FILENAME_EXCED_RANGE; } if (errorCode != Interop.mincore.Errors.ERROR_FILE_NOT_FOUND && errorCode != Interop.mincore.Errors.ERROR_PATH_NOT_FOUND && errorCode != Interop.mincore.Errors.ERROR_INVALID_FUNCTION && // by design - enough said. errorCode != Interop.mincore.Errors.ERROR_ACCESS_DENIED) { throw Win32Marshal.GetExceptionForWin32Error(errorCode); } } currentDirectory = sb.ToString(); } StringBuilderCache.Release(sb); return(currentDirectory); }
private static string NormalizePath( string path, bool fullCheck, int maxPathLength, bool expandShortPaths) // ignored on Unix { Debug.Assert(path != null); if (path.Length == 0) { throw new ArgumentException(SR.Arg_PathIllegal); } if (fullCheck) { PathInternal.CheckInvalidPathChars(path); // Expand with current directory if necessary if (!IsPathRooted(path)) { path = Combine(Interop.libc.getcwd(), path); } } // Remove "//", "/./", and "/../" from the path. We would ideally use realpath // to do this, but it resolves symlinks, requires that the file actually exist, // and turns it into a full path, which we only want if fullCheck is true. // Instead, we do the normalization manually, copying each character to the output, // except the ones we're removing, such that the builder contains the normalized path // at the end. var sb = StringBuilderCache.Acquire(path.Length); int componentCharCount = 0; for (int i = 0; i < path.Length; i++) { char c = path[i]; if (PathInternal.IsDirectorySeparator(c) && i + 1 < path.Length) { componentCharCount = 0; // Skip this character if it's a directory separator and if the next character is, too, // e.g. "parent//child" => "parent/child" if (PathInternal.IsDirectorySeparator(path[i + 1])) { continue; } // Skip this character and the next if it's referring to the current directory, // e.g. "parent/./child" =? "parent/child" if ((i + 2 == path.Length || PathInternal.IsDirectorySeparator(path[i + 2])) && path[i + 1] == '.') { i++; continue; } // Skip this character and the next two if it's referring to the parent directory, // e.g. "parent/child/../grandchild" => "parent/grandchild" if (i + 2 < path.Length && (i + 3 == path.Length || PathInternal.IsDirectorySeparator(path[i + 3])) && path[i + 1] == '.' && path[i + 2] == '.') { // Unwind back to the last slash (and if there isn't one, clear out everything). int s; for (s = sb.Length - 1; s >= 0; s--) { if (PathInternal.IsDirectorySeparator(sb[s])) { sb.Length = s; break; } } if (s < 0) { sb.Length = 0; } i += 2; continue; } } if (++componentCharCount > MaxComponentLength) { throw new PathTooLongException(SR.IO_PathTooLong); } sb.Append(c); } Debug.Assert(sb.Length < path.Length || sb.ToString() == path, "Either we've removed characters, or the string should be unmodified from the input path."); if (sb.Length > MaxPath) { throw new PathTooLongException(SR.IO_PathTooLong); } string result = sb.Length == 0 ? (fullCheck ? DirectorySeparatorCharAsString : string.Empty) : sb.Length == path.Length ? path : sb.ToString(); StringBuilderCache.Release(sb); return(result); }
// We rely on Windows to remove relative segments on Windows. This would need to be updated to // handle the proper rooting on Windows if we for some reason need it. /// <summary> /// Try to remove relative segments from the given path (without combining with a root). /// </summary> /// <param name="skip">Skip the specified number of characters before evaluating.</param> internal static string RemoveRelativeSegments(string path, int skip = 0) { bool flippedSeparator = false; // Remove "//", "/./", and "/../" from the path by copying each character to the output, // except the ones we're removing, such that the builder contains the normalized path // at the end. var sb = StringBuilderCache.Acquire(path.Length); if (skip > 0) { sb.Append(path, 0, skip); } int componentCharCount = 0; for (int i = skip; i < path.Length; i++) { char c = path[i]; if (PathInternal.IsDirectorySeparator(c) && i + 1 < path.Length) { componentCharCount = 0; // Skip this character if it's a directory separator and if the next character is, too, // e.g. "parent//child" => "parent/child" if (PathInternal.IsDirectorySeparator(path[i + 1])) { continue; } // Skip this character and the next if it's referring to the current directory, // e.g. "parent/./child" =? "parent/child" if ((i + 2 == path.Length || PathInternal.IsDirectorySeparator(path[i + 2])) && path[i + 1] == '.') { i++; continue; } // Skip this character and the next two if it's referring to the parent directory, // e.g. "parent/child/../grandchild" => "parent/grandchild" if (i + 2 < path.Length && (i + 3 == path.Length || PathInternal.IsDirectorySeparator(path[i + 3])) && path[i + 1] == '.' && path[i + 2] == '.') { // Unwind back to the last slash (and if there isn't one, clear out everything). int s; for (s = sb.Length - 1; s >= 0; s--) { if (PathInternal.IsDirectorySeparator(sb[s])) { sb.Length = s; break; } } if (s < 0) { sb.Length = 0; } i += 2; continue; } } if (++componentCharCount > PathInternal.MaxComponentLength) { throw new PathTooLongException(); } // Normalize the directory separator if needed if (c != Path.DirectorySeparatorChar && c == Path.AltDirectorySeparatorChar) { c = Path.DirectorySeparatorChar; flippedSeparator = true; } sb.Append(c); } if (flippedSeparator || sb.Length != path.Length) { return(StringBuilderCache.GetStringAndRelease(sb)); } else { // We haven't changed the source path, return the original StringBuilderCache.Release(sb); return(path); } }
static string _innerReadToNewlineDelimiter(this TextReader reader, string keyword, bool returnIfKeywordNotFound) { var i = 0; var j = 0; int ci; var sb = StringBuilderCache.Acquire(); var delimiter = Environment.NewLine; bool secondHit = false; while ((ci = reader.Read()) != -1) { var c = (char)ci; if (c == delimiter[j]) { ++j; if (j == delimiter.Length) { if (secondHit) { break; } else { while ((ci = reader.Read()) != -1 && ci != delimiter[0] && ((char)ci).IsWhiteSpace()) { ; } if (ci == -1) { break; } else if (ci == delimiter[0]) { secondHit = true; j = 1; continue; } else { c = (char)ci; } } } } else if (c == delimiter.Last()) { while ((ci = reader.Read()) != -1 && ci != delimiter[0] && ((char)ci).IsWhiteSpace()) { ; } if (ci == -1) { break; } else if (ci == delimiter[0]) { secondHit = true; j = 1; continue; } else { c = (char)ci; } } else { if (c == delimiter[0]) { j = 1; } else { j = 0; } } if (c == keyword[i]) { ++i; if (i == keyword.Length) { return(StringBuilderCache.GetStringAndRelease(sb)); } } else { if (i != 0) { sb.Append(keyword.Substring(0, i)); i = 0; } if (c == keyword[0]) { ++i; } else { sb.Append(c); } } } if (returnIfKeywordNotFound) { return(StringBuilderCache.GetStringAndRelease(sb)); } else { StringBuilderCache.Release(sb); return(null); } }
public static string ReadTo(this TextReader reader, string keyword, string delimiter, bool returnIfKeywordNotFound = false) { if (delimiter == Environment.NewLine) { return(_innerReadToNewlineDelimiter(reader, keyword, returnIfKeywordNotFound)); } var i = 0; var j = 0; int ci; var sb = StringBuilderCache.Acquire(); while ((ci = reader.Read()) != -1) { var c = (char)ci; if (c == delimiter[j]) { ++j; if (j == delimiter.Length) { break; } } else { if (c == delimiter[0]) { j = 1; } else { j = 0; } } if (c == keyword[i]) { ++i; if (i == keyword.Length) { return(StringBuilderCache.GetStringAndRelease(sb)); } } else { if (i != 0) { sb.Append(keyword.Substring(0, i)); i = 0; } if (c == keyword[0]) { ++i; } else { sb.Append(c); } } } if (returnIfKeywordNotFound) { return(StringBuilderCache.GetStringAndRelease(sb)); } else { StringBuilderCache.Release(sb); return(null); } }