Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(360)

Unified Diff: lib/src/cr_lf_remover.dart

Issue 1226083002: Fix several Windows issues. (Closed) Base URL: git@github.com:dart-lang/pub.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | lib/src/executable.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/src/cr_lf_remover.dart
diff --git a/lib/src/cr_lf_remover.dart b/lib/src/cr_lf_remover.dart
new file mode 100644
index 0000000000000000000000000000000000000000..be85c5bae097e95cdc3110914b3a37b1e580be99
--- /dev/null
+++ b/lib/src/cr_lf_remover.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS d.file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library pub.cr_lf_remover;
+
+import 'dart:convert';
+
+import 'package:charcode/ascii.dart';
+
+/// A converter that removes CR characters immediately preceding LF characters.
+///
+/// This is useful when piping output from a Dart process on Windows. Due to
+/// sdk#19334, an extra CR is added before every LF, even if one already
+/// existed, which can cause data to become corrupted. By converting CR LFs to
+/// LFs, this class ensures that when the output is emitted through the parent
+/// process's stdout it will be identical to the output emitted by the child.
+///
+/// Note that this will only work properly for Dart subprocesses, because
+/// sdk#19334 guarantees that they will *never* emit an LF without a preceding
+/// CR.
+class CRLFRemover extends Converter<List<int>, List<int>> {
+ const CRLFRemover();
+
+ List<int> convert(List<int> data) {
+ var result;
+ var sink = startChunkedConversion(
+ new ByteConversionSink.withCallback((result_) => result = result_));
+ sink.add(data);
+ sink.close();
+ return result;
+ }
+
+ ChunkedConversionSink startChunkedConversion(Sink<List<int>> sink) {
+ if (sink is! ByteConversionSink) sink = new ByteConversionSink.from(sink);
Bob Nystrom 2015/07/08 22:12:15 Document this.
nweiz 2015/07/09 00:30:14 Done.
+ return new _CRLFSink(sink);
+ }
+}
+
+/// The custom sink used to do chunked removal of CRs.
+class _CRLFSink extends ByteConversionSink {
+ /// Whether the last chunk ended in CR.
+ ///
+ /// If it did, that CR wasn't printed in case it needs to be removed.
+ var _wasCR = false;
+
+ /// The underlying sink.
+ final ByteConversionSink _sink;
+
+ _CRLFSink(this._sink);
+
+ void add(Iterable<int> chunk) {
+ if (chunk is! List) chunk = chunk.toList();
+ addSlice(chunk, 0, chunk.length, false);
+ }
+
+ void addSlice(List<int> chunk, int start, int end, bool isLast) {
+ var wasCR = _wasCR;
+ var nextSliceStart = start;
+ for (var i = start; i < end; i++) {
+ if (wasCR && chunk[i] == $lf) {
+ if (i != start) {
+ _sink.addSlice(chunk, nextSliceStart, i - 1, false);
+ nextSliceStart = i;
+ }
+ } else if (_wasCR && i == start) {
+ // If the last chunk ended in a CR and this chunk *doesn't* start with
+ // an LF, we need to write the CR from the last chunk.
+ _sink.add([$cr]);
+ }
+
+ wasCR = chunk[i] == $cr;
+ }
+
+ _wasCR = wasCR;
+ var finalSliceEnd = wasCR ? end - 1 : end;
+ _sink.addSlice(chunk, nextSliceStart, finalSliceEnd, isLast);
+ }
+
+ void close() {
+ if (_wasCR) _sink.add([$cr]);
+ _sink.close();
+ }
+}
« no previous file with comments | « no previous file | lib/src/executable.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698