| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of dart.io; | 5 part of dart.io; |
| 6 | 6 |
| 7 const int _STDIO_HANDLE_TYPE_TERMINAL = 0; | 7 const int _STDIO_HANDLE_TYPE_TERMINAL = 0; |
| 8 const int _STDIO_HANDLE_TYPE_PIPE = 1; | 8 const int _STDIO_HANDLE_TYPE_PIPE = 1; |
| 9 const int _STDIO_HANDLE_TYPE_FILE = 2; | 9 const int _STDIO_HANDLE_TYPE_FILE = 2; |
| 10 const int _STDIO_HANDLE_TYPE_SOCKET = 3; | 10 const int _STDIO_HANDLE_TYPE_SOCKET = 3; |
| 11 const int _STDIO_HANDLE_TYPE_OTHER = 4; | 11 const int _STDIO_HANDLE_TYPE_OTHER = 4; |
| 12 | 12 |
| 13 | |
| 14 class _StdStream extends Stream<List<int>> { | 13 class _StdStream extends Stream<List<int>> { |
| 15 final Stream<List<int>> _stream; | 14 final Stream<List<int>> _stream; |
| 16 | 15 |
| 17 _StdStream(this._stream); | 16 _StdStream(this._stream); |
| 18 | 17 |
| 19 StreamSubscription<List<int>> listen(void onData(List<int> event), | 18 StreamSubscription<List<int>> listen(void onData(List<int> event), |
| 20 {Function onError, | 19 {Function onError, void onDone(), bool cancelOnError}) { |
| 21 void onDone(), | 20 return _stream.listen(onData, |
| 22 bool cancelOnError}) { | 21 onError: onError, onDone: onDone, cancelOnError: cancelOnError); |
| 23 return _stream.listen( | |
| 24 onData, | |
| 25 onError: onError, | |
| 26 onDone: onDone, | |
| 27 cancelOnError: cancelOnError); | |
| 28 } | 22 } |
| 29 } | 23 } |
| 30 | 24 |
| 31 | |
| 32 /** | 25 /** |
| 33 * [Stdin] allows both synchronous and asynchronous reads from the standard | 26 * [Stdin] allows both synchronous and asynchronous reads from the standard |
| 34 * input stream. | 27 * input stream. |
| 35 * | 28 * |
| 36 * Mixing synchronous and asynchronous reads is undefined. | 29 * Mixing synchronous and asynchronous reads is undefined. |
| 37 */ | 30 */ |
| 38 class Stdin extends _StdStream implements Stream<List<int>> { | 31 class Stdin extends _StdStream implements Stream<List<int>> { |
| 39 Stdin._(Stream<List<int>> stream) : super(stream); | 32 Stdin._(Stream<List<int>> stream) : super(stream); |
| 40 | 33 |
| 41 /** | 34 /** |
| 42 * Synchronously read a line from stdin. This call will block until a full | 35 * Synchronously read a line from stdin. This call will block until a full |
| 43 * line is available. | 36 * line is available. |
| 44 * | 37 * |
| 45 * The argument [encoding] can be used to changed how the input should be | 38 * The argument [encoding] can be used to changed how the input should be |
| 46 * decoded. Default is [SYSTEM_ENCODING]. | 39 * decoded. Default is [SYSTEM_ENCODING]. |
| 47 * | 40 * |
| 48 * If [retainNewlines] is `false`, the returned String will not contain the | 41 * If [retainNewlines] is `false`, the returned String will not contain the |
| 49 * final newline. If `true`, the returned String will contain the line | 42 * final newline. If `true`, the returned String will contain the line |
| 50 * terminator. Default is `false`. | 43 * terminator. Default is `false`. |
| 51 * | 44 * |
| 52 * If end-of-file is reached after any bytes have been read from stdin, | 45 * If end-of-file is reached after any bytes have been read from stdin, |
| 53 * that data is returned. | 46 * that data is returned. |
| 54 * Returns `null` if no bytes preceded the end of input. | 47 * Returns `null` if no bytes preceded the end of input. |
| 55 */ | 48 */ |
| 56 String readLineSync({Encoding encoding: SYSTEM_ENCODING, | 49 String readLineSync( |
| 57 bool retainNewlines: false}) { | 50 {Encoding encoding: SYSTEM_ENCODING, bool retainNewlines: false}) { |
| 58 const CR = 13; | 51 const CR = 13; |
| 59 const LF = 10; | 52 const LF = 10; |
| 60 final List<int> line = <int>[]; | 53 final List<int> line = <int>[]; |
| 61 // On Windows, if lineMode is disabled, only CR is received. | 54 // On Windows, if lineMode is disabled, only CR is received. |
| 62 bool crIsNewline = Platform.isWindows && | 55 bool crIsNewline = Platform.isWindows && |
| 63 (stdioType(stdin) == StdioType.TERMINAL) && | 56 (stdioType(stdin) == StdioType.TERMINAL) && |
| 64 !lineMode; | 57 !lineMode; |
| 65 if (retainNewlines) { | 58 if (retainNewlines) { |
| 66 int byte; | 59 int byte; |
| 67 do { | 60 do { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 80 int byte = readByteSync(); | 73 int byte = readByteSync(); |
| 81 if (byte < 0) { | 74 if (byte < 0) { |
| 82 if (line.isEmpty) return null; | 75 if (line.isEmpty) return null; |
| 83 break; | 76 break; |
| 84 } | 77 } |
| 85 if (byte == LF || byte == CR) break; | 78 if (byte == LF || byte == CR) break; |
| 86 line.add(byte); | 79 line.add(byte); |
| 87 } | 80 } |
| 88 } else { | 81 } else { |
| 89 // Case having to handel CR LF as a single unretained line terminator. | 82 // Case having to handel CR LF as a single unretained line terminator. |
| 90 outer: while (true) { | 83 outer: |
| 84 while (true) { |
| 91 int byte = readByteSync(); | 85 int byte = readByteSync(); |
| 92 if (byte == LF) break; | 86 if (byte == LF) break; |
| 93 if (byte == CR) { | 87 if (byte == CR) { |
| 94 do { | 88 do { |
| 95 byte = readByteSync(); | 89 byte = readByteSync(); |
| 96 if (byte == LF) break outer; | 90 if (byte == LF) break outer; |
| 97 | 91 |
| 98 line.add(CR); | 92 line.add(CR); |
| 99 } while (byte == CR); | 93 } while (byte == CR); |
| 100 // Fall through and handle non-CR character. | 94 // Fall through and handle non-CR character. |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 144 | 138 |
| 145 /** | 139 /** |
| 146 * Synchronously read a byte from stdin. This call will block until a byte is | 140 * Synchronously read a byte from stdin. This call will block until a byte is |
| 147 * available. | 141 * available. |
| 148 * | 142 * |
| 149 * If at end of file, -1 is returned. | 143 * If at end of file, -1 is returned. |
| 150 */ | 144 */ |
| 151 external int readByteSync(); | 145 external int readByteSync(); |
| 152 } | 146 } |
| 153 | 147 |
| 154 | |
| 155 /** | 148 /** |
| 156 * [Stdout] represents the [IOSink] for either `stdout` or `stderr`. | 149 * [Stdout] represents the [IOSink] for either `stdout` or `stderr`. |
| 157 * | 150 * |
| 158 * It provides a *blocking* `IOSink`, so using this to write will block until | 151 * It provides a *blocking* `IOSink`, so using this to write will block until |
| 159 * the output is written. | 152 * the output is written. |
| 160 * | 153 * |
| 161 * In some situations this blocking behavior is undesirable as it does not | 154 * In some situations this blocking behavior is undesirable as it does not |
| 162 * provide the same non-blocking behavior as dart:io in general exposes. | 155 * provide the same non-blocking behavior as dart:io in general exposes. |
| 163 * Use the property [nonBlocking] to get an `IOSink` which has the non-blocking | 156 * Use the property [nonBlocking] to get an `IOSink` which has the non-blocking |
| 164 * behavior. | 157 * behavior. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 * Get a non-blocking `IOSink`. | 194 * Get a non-blocking `IOSink`. |
| 202 */ | 195 */ |
| 203 IOSink get nonBlocking { | 196 IOSink get nonBlocking { |
| 204 if (_nonBlocking == null) { | 197 if (_nonBlocking == null) { |
| 205 _nonBlocking = new IOSink(new _FileStreamConsumer.fromStdio(_fd)); | 198 _nonBlocking = new IOSink(new _FileStreamConsumer.fromStdio(_fd)); |
| 206 } | 199 } |
| 207 return _nonBlocking; | 200 return _nonBlocking; |
| 208 } | 201 } |
| 209 } | 202 } |
| 210 | 203 |
| 211 | |
| 212 class StdoutException implements IOException { | 204 class StdoutException implements IOException { |
| 213 final String message; | 205 final String message; |
| 214 final OSError osError; | 206 final OSError osError; |
| 215 | 207 |
| 216 const StdoutException(this.message, [this.osError]); | 208 const StdoutException(this.message, [this.osError]); |
| 217 | 209 |
| 218 String toString() { | 210 String toString() { |
| 219 return "StdoutException: $message${osError == null ? "" : ", $osError"}"; | 211 return "StdoutException: $message${osError == null ? "" : ", $osError"}"; |
| 220 } | 212 } |
| 221 } | 213 } |
| 222 | 214 |
| 223 | |
| 224 class StdinException implements IOException { | 215 class StdinException implements IOException { |
| 225 final String message; | 216 final String message; |
| 226 final OSError osError; | 217 final OSError osError; |
| 227 | 218 |
| 228 const StdinException(this.message, [this.osError]); | 219 const StdinException(this.message, [this.osError]); |
| 229 | 220 |
| 230 String toString() { | 221 String toString() { |
| 231 return "StdinException: $message${osError == null ? "" : ", $osError"}"; | 222 return "StdinException: $message${osError == null ? "" : ", $osError"}"; |
| 232 } | 223 } |
| 233 } | 224 } |
| 234 | 225 |
| 235 | |
| 236 class _StdConsumer implements StreamConsumer<List<int>> { | 226 class _StdConsumer implements StreamConsumer<List<int>> { |
| 237 final _file; | 227 final _file; |
| 238 | 228 |
| 239 _StdConsumer(int fd) : _file = _File._openStdioSync(fd); | 229 _StdConsumer(int fd) : _file = _File._openStdioSync(fd); |
| 240 | 230 |
| 241 Future addStream(Stream<List<int>> stream) { | 231 Future addStream(Stream<List<int>> stream) { |
| 242 var completer = new Completer(); | 232 var completer = new Completer(); |
| 243 var sub; | 233 var sub; |
| 244 sub = stream.listen( | 234 sub = stream.listen((data) { |
| 245 (data) { | 235 try { |
| 246 try { | 236 _file.writeFromSync(data); |
| 247 _file.writeFromSync(data); | 237 } catch (e, s) { |
| 248 } catch (e, s) { | 238 sub.cancel(); |
| 249 sub.cancel(); | 239 completer.completeError(e, s); |
| 250 completer.completeError(e, s); | 240 } |
| 251 } | 241 }, |
| 252 }, | |
| 253 onError: completer.completeError, | 242 onError: completer.completeError, |
| 254 onDone: completer.complete, | 243 onDone: completer.complete, |
| 255 cancelOnError: true); | 244 cancelOnError: true); |
| 256 return completer.future; | 245 return completer.future; |
| 257 } | 246 } |
| 258 | 247 |
| 259 Future close() { | 248 Future close() { |
| 260 _file.closeSync(); | 249 _file.closeSync(); |
| 261 return new Future.value(); | 250 return new Future.value(); |
| 262 } | 251 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 278 _IOSinkImpl sink = _sink; | 267 _IOSinkImpl sink = _sink; |
| 279 _StdConsumer target = sink._target; | 268 _StdConsumer target = sink._target; |
| 280 target._file.translation = t; | 269 target._file.translation = t; |
| 281 } | 270 } |
| 282 } | 271 } |
| 283 | 272 |
| 284 void write(object) { | 273 void write(object) { |
| 285 _translation = _FileTranslation.text; | 274 _translation = _FileTranslation.text; |
| 286 _sink.write(object); | 275 _sink.write(object); |
| 287 } | 276 } |
| 288 void writeln([object = "" ]) { | 277 |
| 278 void writeln([object = ""]) { |
| 289 _translation = _FileTranslation.text; | 279 _translation = _FileTranslation.text; |
| 290 _sink.writeln(object); | 280 _sink.writeln(object); |
| 291 } | 281 } |
| 282 |
| 292 void writeAll(objects, [sep = ""]) { | 283 void writeAll(objects, [sep = ""]) { |
| 293 _translation = _FileTranslation.text; | 284 _translation = _FileTranslation.text; |
| 294 _sink.writeAll(objects, sep); | 285 _sink.writeAll(objects, sep); |
| 295 } | 286 } |
| 287 |
| 296 void add(List<int> data) { | 288 void add(List<int> data) { |
| 297 _translation = _FileTranslation.binary; | 289 _translation = _FileTranslation.binary; |
| 298 _sink.add(data); | 290 _sink.add(data); |
| 299 } | 291 } |
| 292 |
| 300 void addError(error, [StackTrace stackTrace]) { | 293 void addError(error, [StackTrace stackTrace]) { |
| 301 _sink.addError(error, stackTrace); | 294 _sink.addError(error, stackTrace); |
| 302 } | 295 } |
| 296 |
| 303 void writeCharCode(int charCode) { | 297 void writeCharCode(int charCode) { |
| 304 _translation = _FileTranslation.text; | 298 _translation = _FileTranslation.text; |
| 305 _sink.writeCharCode(charCode); | 299 _sink.writeCharCode(charCode); |
| 306 } | 300 } |
| 301 |
| 307 Future addStream(Stream<List<int>> stream) { | 302 Future addStream(Stream<List<int>> stream) { |
| 308 _translation = _FileTranslation.binary; | 303 _translation = _FileTranslation.binary; |
| 309 return _sink.addStream(stream); | 304 return _sink.addStream(stream); |
| 310 } | 305 } |
| 306 |
| 311 Future flush() => _sink.flush(); | 307 Future flush() => _sink.flush(); |
| 312 Future close() => _sink.close(); | 308 Future close() => _sink.close(); |
| 313 Future get done => _sink.done; | 309 Future get done => _sink.done; |
| 314 } | 310 } |
| 315 | 311 |
| 316 class _StdFileSink extends _StdSinkHelper { | 312 class _StdFileSink extends _StdSinkHelper { |
| 317 // The target of `sink` is expected to be a _StdConsumer. | 313 // The target of `sink` is expected to be a _StdConsumer. |
| 318 _StdFileSink(IOSink sink) : super(sink, true); | 314 _StdFileSink(IOSink sink) : super(sink, true); |
| 319 } | 315 } |
| 320 | 316 |
| 321 class _StdSocketSink extends _StdSinkHelper { | 317 class _StdSocketSink extends _StdSinkHelper { |
| 322 _StdSocketSink(IOSink sink) : super(sink, false); | 318 _StdSocketSink(IOSink sink) : super(sink, false); |
| 323 } | 319 } |
| 324 | 320 |
| 325 /// The type of object a standard IO stream is attached to. | 321 /// The type of object a standard IO stream is attached to. |
| 326 class StdioType { | 322 class StdioType { |
| 327 static const StdioType TERMINAL = const StdioType._("terminal"); | 323 static const StdioType TERMINAL = const StdioType._("terminal"); |
| 328 static const StdioType PIPE = const StdioType._("pipe"); | 324 static const StdioType PIPE = const StdioType._("pipe"); |
| 329 static const StdioType FILE = const StdioType._("file"); | 325 static const StdioType FILE = const StdioType._("file"); |
| 330 static const StdioType OTHER = const StdioType._("other"); | 326 static const StdioType OTHER = const StdioType._("other"); |
| 331 final String name; | 327 final String name; |
| 332 const StdioType._(this.name); | 328 const StdioType._(this.name); |
| 333 String toString() => "StdioType: $name"; | 329 String toString() => "StdioType: $name"; |
| 334 } | 330 } |
| 335 | 331 |
| 336 | |
| 337 Stdin _stdin; | 332 Stdin _stdin; |
| 338 Stdout _stdout; | 333 Stdout _stdout; |
| 339 Stdout _stderr; | 334 Stdout _stderr; |
| 340 | 335 |
| 341 | |
| 342 /// The standard input stream of data read by this program. | 336 /// The standard input stream of data read by this program. |
| 343 Stdin get stdin { | 337 Stdin get stdin { |
| 344 if (_stdin == null) { | 338 if (_stdin == null) { |
| 345 _stdin = _StdIOUtils._getStdioInputStream(); | 339 _stdin = _StdIOUtils._getStdioInputStream(); |
| 346 } | 340 } |
| 347 return _stdin; | 341 return _stdin; |
| 348 } | 342 } |
| 349 | 343 |
| 350 | |
| 351 /// The standard output stream of data written by this program. | 344 /// The standard output stream of data written by this program. |
| 352 Stdout get stdout { | 345 Stdout get stdout { |
| 353 if (_stdout == null) { | 346 if (_stdout == null) { |
| 354 _stdout = _StdIOUtils._getStdioOutputStream(1); | 347 _stdout = _StdIOUtils._getStdioOutputStream(1); |
| 355 } | 348 } |
| 356 return _stdout; | 349 return _stdout; |
| 357 } | 350 } |
| 358 | 351 |
| 359 | |
| 360 /// The standard output stream of errors written by this program. | 352 /// The standard output stream of errors written by this program. |
| 361 Stdout get stderr { | 353 Stdout get stderr { |
| 362 if (_stderr == null) { | 354 if (_stderr == null) { |
| 363 _stderr = _StdIOUtils._getStdioOutputStream(2); | 355 _stderr = _StdIOUtils._getStdioOutputStream(2); |
| 364 } | 356 } |
| 365 return _stderr; | 357 return _stderr; |
| 366 } | 358 } |
| 367 | 359 |
| 368 | |
| 369 /// For a stream, returns whether it is attached to a file, pipe, terminal, or | 360 /// For a stream, returns whether it is attached to a file, pipe, terminal, or |
| 370 /// something else. | 361 /// something else. |
| 371 StdioType stdioType(object) { | 362 StdioType stdioType(object) { |
| 372 if (object is _StdStream) { | 363 if (object is _StdStream) { |
| 373 object = object._stream; | 364 object = object._stream; |
| 374 } else if (object == stdout || object == stderr) { | 365 } else if (object == stdout || object == stderr) { |
| 375 switch (_StdIOUtils._getStdioHandleType(object == stdout ? 1 : 2)) { | 366 switch (_StdIOUtils._getStdioHandleType(object == stdout ? 1 : 2)) { |
| 376 case _STDIO_HANDLE_TYPE_TERMINAL: return StdioType.TERMINAL; | 367 case _STDIO_HANDLE_TYPE_TERMINAL: |
| 377 case _STDIO_HANDLE_TYPE_PIPE: return StdioType.PIPE; | 368 return StdioType.TERMINAL; |
| 378 case _STDIO_HANDLE_TYPE_FILE: return StdioType.FILE; | 369 case _STDIO_HANDLE_TYPE_PIPE: |
| 370 return StdioType.PIPE; |
| 371 case _STDIO_HANDLE_TYPE_FILE: |
| 372 return StdioType.FILE; |
| 379 } | 373 } |
| 380 } | 374 } |
| 381 if (object is _FileStream) { | 375 if (object is _FileStream) { |
| 382 return StdioType.FILE; | 376 return StdioType.FILE; |
| 383 } | 377 } |
| 384 if (object is Socket) { | 378 if (object is Socket) { |
| 385 int socketType = _StdIOUtils._socketType(object); | 379 int socketType = _StdIOUtils._socketType(object); |
| 386 if (socketType == null) return StdioType.OTHER; | 380 if (socketType == null) return StdioType.OTHER; |
| 387 switch (socketType) { | 381 switch (socketType) { |
| 388 case _STDIO_HANDLE_TYPE_TERMINAL: | 382 case _STDIO_HANDLE_TYPE_TERMINAL: |
| 389 return StdioType.TERMINAL; | 383 return StdioType.TERMINAL; |
| 390 case _STDIO_HANDLE_TYPE_PIPE: | 384 case _STDIO_HANDLE_TYPE_PIPE: |
| 391 return StdioType.PIPE; | 385 return StdioType.PIPE; |
| 392 case _STDIO_HANDLE_TYPE_FILE: | 386 case _STDIO_HANDLE_TYPE_FILE: |
| 393 return StdioType.FILE; | 387 return StdioType.FILE; |
| 394 } | 388 } |
| 395 } | 389 } |
| 396 if (object is _IOSinkImpl) { | 390 if (object is _IOSinkImpl) { |
| 397 try { | 391 try { |
| 398 if (object._target is _FileStreamConsumer) { | 392 if (object._target is _FileStreamConsumer) { |
| 399 return StdioType.FILE; | 393 return StdioType.FILE; |
| 400 } | 394 } |
| 401 } catch (e) { | 395 } catch (e) { |
| 402 // Only the interface implemented, _sink not available. | 396 // Only the interface implemented, _sink not available. |
| 403 } | 397 } |
| 404 } | 398 } |
| 405 return StdioType.OTHER; | 399 return StdioType.OTHER; |
| 406 } | 400 } |
| 407 | 401 |
| 408 | |
| 409 class _StdIOUtils { | 402 class _StdIOUtils { |
| 410 external static _getStdioOutputStream(int fd); | 403 external static _getStdioOutputStream(int fd); |
| 411 external static Stdin _getStdioInputStream(); | 404 external static Stdin _getStdioInputStream(); |
| 405 |
| 412 /// Returns the socket type or `null` if [socket] is not a builtin socket. | 406 /// Returns the socket type or `null` if [socket] is not a builtin socket. |
| 413 external static int _socketType(Socket socket); | 407 external static int _socketType(Socket socket); |
| 414 external static _getStdioHandleType(int fd); | 408 external static _getStdioHandleType(int fd); |
| 415 } | 409 } |
| OLD | NEW |