From e1b043c61f888abadecad7790353ff38a633fb52 Mon Sep 17 00:00:00 2001
From: "Erik C. Thauvin"
Date: Wed, 13 Oct 2021 21:36:40 -0700
Subject: [PATCH] Made cat() a fully standalone library function.
---
README.md | 49 ++++-
bin/dcat.dart | 30 ++-
doc/api/dcat/CatResult-class.html | 278 +++++++++++++++++++++++++
doc/api/dcat/CatResult/CatResult.html | 137 ++++++++++++
doc/api/dcat/CatResult/addMessage.html | 155 ++++++++++++++
doc/api/dcat/CatResult/exitCode.html | 143 +++++++++++++
doc/api/dcat/CatResult/messages.html | 143 +++++++++++++
doc/api/dcat/cat.html | 61 ++++--
doc/api/dcat/dcat-library.html | 38 ++--
doc/api/dcat/exitFailure-constant.html | 3 +-
doc/api/dcat/exitSuccess-constant.html | 3 +-
doc/api/dcat/printError.html | 145 -------------
doc/api/index.html | 36 +++-
doc/api/index.json | 2 +-
lib/dcat.dart | 108 ++++++----
pubspec.lock | 6 +-
pubspec.yaml | 2 +-
test/dcat_test.dart | 114 +++++++---
test/test.7z | Bin 460 -> 465 bytes
19 files changed, 1182 insertions(+), 271 deletions(-)
create mode 100644 doc/api/dcat/CatResult-class.html
create mode 100644 doc/api/dcat/CatResult/CatResult.html
create mode 100644 doc/api/dcat/CatResult/addMessage.html
create mode 100644 doc/api/dcat/CatResult/exitCode.html
create mode 100644 doc/api/dcat/CatResult/messages.html
delete mode 100644 doc/api/dcat/printError.html
diff --git a/README.md b/README.md
index 3ed52dd..fa9a18c 100644
--- a/README.md
+++ b/README.md
@@ -2,13 +2,13 @@
[](https://github.com/ethauvin/dcat/actions/workflows/dart.yml)
[](https://codecov.io/gh/ethauvin/dcat)
-# dcat: Concatenate File(s) to Standard Output
+# dcat: Concatenate File(s) to Standard Output or File
-A **cat** command-line implementation in [Dart](https://dart.dev/), inspired by the [Write command-line apps sample code](https://dart.dev/tutorials/server/cmdline).
+A **cat** command-line and library implementation in [Dart](https://dart.dev/), inspired by the [Write command-line apps sample code](https://dart.dev/tutorials/server/cmdline).
## Synopsis
-**dcat** copies each file, or standard input if none are given, to standard output.
+**dcat** copies each file, or standard input if none are given, to standard output or file.
## Command-Line Usage
@@ -49,6 +49,49 @@ dart compile exe -o bin/dcat bin/dcat.dart
dart compile exe bin/dcat.dart
```
+## Library Usage
+```dart
+import 'package:dcat/dcat.dart';
+
+final result = await cat(['path/to/file', 'path/to/otherfile]'], File('path/to/outfile'));
+if (result.exitCode == exitFailure) {
+ for (final message in result.messages) {
+ print("Error: $message");
+ }
+}
+```
+
+The `cat` function supports the following parameters:
+
+Parameter | Description | Type
+:--------------- |:----------------------------- | :-------------------
+paths | The file paths. | String[]
+output | The standard output or file. | IOSink or File
+input | The standard input. | Stream\>?
+log | The log for debugging. | List\?
+showEnds | Same as `-e` | bool
+numberNonBlank | Same as `-b` | bool
+showLineNumbers | Same as `-n` | bool
+showTabs | Same as `-T` | bool
+squeezeBlank | Same as `-s` | bool
+showNonPrinting | Same as `-v` | bool
+
+* `paths` and `output` are required.
+* `output` should be an `IOSink` like `stdout` or a `File`.
+* `input` can be `stdin`.
+* `log` is used for debugging/testing purposes.
+
+The remaining optional parameters are similar to the [GNU cat](https://www.gnu.org/software/coreutils/manual/html_node/cat-invocation.html#cat-invocation) utility.
+
+A `CatResult` object is returned which contains the `exitCode` (`exitSuccess` or `exitFailure`) and error `messages` if any:
+
+```dart
+final result = await cat(['path/to/file'], stdout);
+if (result.exitCode == exitSuccess) {
+ ...
+}
+```
+
## Differences from [GNU cat](https://www.gnu.org/software/coreutils/manual/html_node/cat-invocation.html#cat-invocation)
- No binary file support.
- A line is considered terminated by either a `CR` (carriage return), a `LF` (line feed), a `CR+LF` sequence (DOS line ending).
diff --git a/bin/dcat.dart b/bin/dcat.dart
index 0603278..4626893 100644
--- a/bin/dcat.dart
+++ b/bin/dcat.dart
@@ -27,8 +27,9 @@ const versionFlag = 'version';
/// Usage: `dcat [option] [file]…`
Future main(List arguments) async {
final parser = ArgParser();
- Future returnCode;
+
exitCode = exitSuccess;
+
parser.addFlag(showAllFlag,
negatable: false, abbr: 'A', help: 'equivalent to -vET');
parser.addFlag(nonBlankFlag,
@@ -63,16 +64,14 @@ Future main(List arguments) async {
try {
argResults = parser.parse(arguments);
} on FormatException catch (e) {
- exitCode = await printError(
- "${e.message}\nTry '$appName --$helpFlag' for more information.",
- appName: appName);
- return exitCode;
+ return printError(
+ "${e.message}\nTry '$appName --$helpFlag' for more information.");
}
if (argResults[helpFlag]) {
- returnCode = usage(parser.usage);
+ exitCode = await usage(parser.usage);
} else if (argResults[versionFlag]) {
- returnCode = printVersion();
+ exitCode = await printVersion();
} else {
final paths = argResults.rest;
var showEnds = argResults[showEndsFlag];
@@ -91,20 +90,31 @@ Future main(List arguments) async {
showNonPrinting = showEnds = showTabs = true;
}
- returnCode = cat(paths,
- appName: appName,
+ final result = await cat(paths, stdout,
+ input: stdin,
showEnds: showEnds,
showLineNumbers: argResults[numberFlag],
numberNonBlank: argResults[nonBlankFlag],
showTabs: showTabs,
squeezeBlank: argResults[squeezeBlank],
showNonPrinting: showNonPrinting);
+
+ for (final message in result.messages) {
+ await printError(message);
+ }
+
+ exitCode = result.exitCode;
}
- exitCode = await returnCode;
return exitCode;
}
+/// Prints the error [message] to [stderr].
+Future printError(String message) async {
+ stderr.writeln("$appName: $message");
+ return exitFailure;
+}
+
/// Prints the version info.
Future printVersion() async {
print('''$appName (Dart cat) $appVersion
diff --git a/doc/api/dcat/CatResult-class.html b/doc/api/dcat/CatResult-class.html
new file mode 100644
index 0000000..0b9dff6
--- /dev/null
+++ b/doc/api/dcat/CatResult-class.html
@@ -0,0 +1,278 @@
+
+
+
+
+
+
+
+ CatResult class - dcat library - Dart API
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - dcat
+ - dcat
+ - CatResult class
+
+ CatResult
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Constructors
+
+
+ -
+ CatResult()
+
+ -
+
+
+
+
+
+
+ Properties
+
+
+ -
+ exitCode
+ ↔ int
+
+
+-
+ The exit code.
+
read / write
+
+
+
+ -
+ hashCode
+ → int
+
+
+-
+ The hash code for this object. [...]
+
read-only, inherited
+
+
+
+ -
+ messages
+ → List<String>
+
+
+-
+ The error messages.
+
final
+
+
+
+ -
+ runtimeType
+ → Type
+
+
+-
+ A representation of the runtime type of the object.
+
read-only, inherited
+
+
+
+
+
+
+
+ Methods
+
+ -
+ addMessage(int exitCode, String message, {String? path})
+ → void
+
+
+
+
+-
+ Add a message.
+
+
+
+
+ -
+ noSuchMethod(Invocation invocation)
+ → dynamic
+
+
+
+
+-
+ Invoked when a non-existent method or property is accessed. [...]
+
inherited
+
+
+
+ -
+ toString()
+ → String
+
+
+
+
+-
+ A string representation of this object. [...]
+
inherited
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/api/dcat/CatResult/CatResult.html b/doc/api/dcat/CatResult/CatResult.html
new file mode 100644
index 0000000..00dc26c
--- /dev/null
+++ b/doc/api/dcat/CatResult/CatResult.html
@@ -0,0 +1,137 @@
+
+
+
+
+
+
+
+ CatResult constructor - CatResult class - dcat library - Dart API
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Implementation
+ CatResult();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/api/dcat/CatResult/addMessage.html b/doc/api/dcat/CatResult/addMessage.html
new file mode 100644
index 0000000..ceb40a2
--- /dev/null
+++ b/doc/api/dcat/CatResult/addMessage.html
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+
+ addMessage method - CatResult class - dcat library - Dart API
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void
+addMessage(- int exitCode,
+- String message,
+- {String? path}
+
)
+
+
+
+
+
+
+
+
+
+
+ Implementation
+ void addMessage(int exitCode, String message, {String? path}) {
+ this.exitCode = exitCode;
+ if (path != null && path.isNotEmpty) {
+ messages.add('$path: $message');
+ } else {
+ messages.add(message);
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/api/dcat/CatResult/exitCode.html b/doc/api/dcat/CatResult/exitCode.html
new file mode 100644
index 0000000..78902db
--- /dev/null
+++ b/doc/api/dcat/CatResult/exitCode.html
@@ -0,0 +1,143 @@
+
+
+
+
+
+
+
+ exitCode property - CatResult class - dcat library - Dart API
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ int
+ exitCode
+ read / write
+
+
+
+
+
+
+
+ Implementation
+ int exitCode = exitSuccess;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/api/dcat/CatResult/messages.html b/doc/api/dcat/CatResult/messages.html
new file mode 100644
index 0000000..0163b3a
--- /dev/null
+++ b/doc/api/dcat/CatResult/messages.html
@@ -0,0 +1,143 @@
+
+
+
+
+
+
+
+ messages property - CatResult class - dcat library - Dart API
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Implementation
+ final List<String> messages = [];
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/api/dcat/cat.html b/doc/api/dcat/cat.html
index 47be894..975ead7 100644
--- a/doc/api/dcat/cat.html
+++ b/doc/api/dcat/cat.html
@@ -52,9 +52,10 @@
- Concatenates files in paths
to stdout
-The parameters are similar to the GNU cat utility.
-Specify a log
for debugging or testing purpose.
+ Concatenates files in paths
to stdout or File.
+
+output
should be an IOSink like stdout or a File.
+input
can be stdin.
+log
is used for debugging/testing purposes.
+
+The remaining optional parameters are similar to the GNU cat utility.
Implementation
- Future<int> cat(List<String> paths,
- {String appName = '',
+ Future<CatResult> cat(List<String> paths, Object output,
+ {Stream<List<int>>? input,
List<String>? log,
bool showEnds = false,
bool numberNonBlank = false,
@@ -85,19 +90,34 @@ Specify a log
for debugging or testing purpose.
bool showTabs = false,
bool squeezeBlank = false,
bool showNonPrinting = false}) async {
+ var result = CatResult();
var lineNumber = 1;
- var returnCode = 0;
log?.clear();
if (paths.isEmpty) {
- final lines = await _readStdin();
- await _writeLines(lines, lineNumber, log, showEnds, showLineNumbers,
- numberNonBlank, showTabs, squeezeBlank, showNonPrinting);
+ if (input != null) {
+ final lines = await _readStream(input);
+ try {
+ await _writeLines(
+ lines,
+ lineNumber,
+ output,
+ log,
+ showEnds,
+ showLineNumbers,
+ numberNonBlank,
+ showTabs,
+ squeezeBlank,
+ showNonPrinting);
+ } catch (e) {
+ result.addMessage(exitFailure, '$e');
+ }
+ }
} else {
for (final path in paths) {
try {
final Stream<String> lines;
- if (path == '-') {
- lines = await _readStdin();
+ if (path == '-' && input != null) {
+ lines = await _readStream(input);
} else {
lines = utf8.decoder
.bind(File(path).openRead())
@@ -106,6 +126,7 @@ Specify a log
for debugging or testing purpose.
lineNumber = await _writeLines(
lines,
lineNumber,
+ output,
log,
showEnds,
showLineNumbers,
@@ -121,17 +142,16 @@ Specify a log
for debugging or testing purpose.
} else {
message = e.message;
}
- returnCode = await printError(message, appName: appName, path: path);
+ result.addMessage(exitFailure, message, path: path);
} on FormatException {
- returnCode = await printError('Binary file not supported.',
- appName: appName, path: path);
+ result.addMessage(exitFailure, 'Binary file not supported.',
+ path: path);
} catch (e) {
- returnCode =
- await printError(e.toString(), appName: appName, path: path);
+ result.addMessage(exitFailure, '$e', path: path);
}
}
}
- return returnCode;
+ return result;
}
@@ -154,6 +174,8 @@ Specify a log
for debugging or testing purpose.
dcat library
+ - Classes
+ - CatResult
@@ -164,7 +186,6 @@ Specify a log
for debugging or testing purpose.
- Functions
- cat
- - printError
diff --git a/doc/api/dcat/dcat-library.html b/doc/api/dcat/dcat-library.html
index 68ffe31..5ab06b8 100644
--- a/doc/api/dcat/dcat-library.html
+++ b/doc/api/dcat/dcat-library.html
@@ -50,10 +50,24 @@
- Library to concatenate file(s) to standard output,
+ A library to concatenate files to standard output or file.
+
@@ -100,27 +114,14 @@
-
- cat(List<String> paths, {String appName = '', List<String>? log, bool showEnds = false, bool numberNonBlank = false, bool showLineNumbers = false, bool showTabs = false, bool squeezeBlank = false, bool showNonPrinting = false})
- → Future<int>
+ cat(List<String> paths, Object output, {Stream<List<int>>? input, List<String>? log, bool showEnds = false, bool numberNonBlank = false, bool showLineNumbers = false, bool showTabs = false, bool squeezeBlank = false, bool showNonPrinting = false})
+ → Future<CatResult>
-
- Concatenates files in
paths
to stdout [...]
-
-
-
-
- -
- printError(String message, {String appName = '', String path = ''})
- → Future<int>
-
-
-
-
--
- Prints the
appName
, path
and error message
to stderr.
+ Concatenates files in paths
to stdout or File. [...]
@@ -157,6 +158,8 @@