Added support for binary files and -M notation.

This commit is contained in:
Erik C. Thauvin 2021-10-17 21:04:08 -07:00
parent 6ad6a84346
commit 4965306762
10 changed files with 148 additions and 142 deletions

View file

@ -5,7 +5,6 @@
/// A library to concatenate files to standard output or file.
library dcat;
import 'dart:convert';
import 'dart:io';
/// Failure exit code.
@ -57,20 +56,20 @@ class _LastLine {
/// The remaining optional parameters are similar to the [GNU cat utility](https://www.gnu.org/software/coreutils/manual/html_node/cat-invocation.html#cat-invocation).
Future<CatResult> cat(List<String> paths, IOSink output,
{Stream<List<int>>? input,
bool showEnds = false,
bool numberNonBlank = false,
bool showEnds = false,
bool showLineNumbers = false,
bool showNonPrinting = false,
bool showTabs = false,
bool squeezeBlank = false,
bool showNonPrinting = false}) async {
bool squeezeBlank = false}) async {
final result = CatResult();
final lastLine = _LastLine();
if (paths.isEmpty) {
if (input != null) {
try {
await _writeStream(input, lastLine, output, showEnds, showLineNumbers,
numberNonBlank, showTabs, squeezeBlank, showNonPrinting);
await _writeStream(input, lastLine, output, numberNonBlank, showEnds,
showLineNumbers, showNonPrinting, showTabs, squeezeBlank);
} catch (e) {
result.addMessage(exitFailure, _formatError(e));
}
@ -84,8 +83,8 @@ Future<CatResult> cat(List<String> paths, IOSink output,
} else {
stream = File(path).openRead();
}
await _writeStream(stream, lastLine, output, showEnds, showLineNumbers,
numberNonBlank, showTabs, squeezeBlank, showNonPrinting);
await _writeStream(stream, lastLine, output, numberNonBlank, showEnds,
showLineNumbers, showNonPrinting, showTabs, squeezeBlank);
} catch (e) {
result.addMessage(exitFailure, _formatError(e), path: path);
}
@ -104,8 +103,6 @@ String _formatError(Object e) {
} else {
message = e.message;
}
} else if (e is FormatException) {
message = 'Binary file not supported.';
} else {
message = '$e';
}
@ -114,15 +111,15 @@ String _formatError(Object e) {
// Writes parsed data from a stream
Future<void> _writeStream(
Stream stream,
Stream<List<int>> stream,
_LastLine lastLine,
IOSink out,
bool numberNonBlank,
bool showEnds,
bool showLineNumbers,
bool numberNonBlank,
bool showNonPrinting,
bool showTabs,
bool squeezeBlank,
bool showNonPrinting) async {
bool squeezeBlank) async {
// No flags
if (!showEnds &&
!showLineNumbers &&
@ -130,15 +127,17 @@ Future<void> _writeStream(
!showTabs &&
!squeezeBlank &&
!showNonPrinting) {
await stream.transform(utf8.decoder).forEach(out.write);
await stream.forEach(out.add);
} else {
const caret = 94;
const questionMark = 63;
const tab = 9;
int squeeze = 0;
final sb = StringBuffer();
final List<int> buff = [];
await stream.forEach((data) {
sb.clear();
for (final ch in utf8.decode(data).runes) {
buff.clear();
for (final ch in data) {
if (lastLine.lastChar == _lineFeed) {
if (squeezeBlank) {
if (ch == _lineFeed) {
@ -153,52 +152,67 @@ Future<void> _writeStream(
}
if (showLineNumbers || numberNonBlank) {
if (!numberNonBlank || ch != _lineFeed) {
sb
..write('${++lastLine.lineNumber}'.padLeft(6))
..write('\t');
buff.addAll('${++lastLine.lineNumber}'.padLeft(6).codeUnits);
buff.add(tab);
}
}
}
lastLine.lastChar = ch;
if (ch == _lineFeed) {
if (showEnds) {
sb.write('\$');
// $ at EOL
buff.add(36);
}
} else if (ch == tab) {
if (showTabs) {
// TAB
sb.write('^I');
// TAB (^I)
buff
..add(caret)
..add(73);
continue;
}
} else if (showNonPrinting) {
if (ch >= 32) {
if (ch < 127) {
// ASCII
sb.writeCharCode(ch);
buff.add(ch);
continue;
} else if (ch == 127) {
// NULL
sb.write('^?');
// NULL (^?)
buff
..add(caret)
..add(questionMark);
continue;
} else {
// UNICODE
sb
..write('U+')
..write(ch.toRadixString(16).padLeft(4, '0').toUpperCase());
// HIGH BIT (M-)
buff.add(77);
buff.add(45);
if (ch >= 128 + 32) {
if (ch < 128 + 127) {
buff.add(ch - 128);
} else {
buff
..add(caret)
..add(questionMark);
}
} else {
buff.add(caret);
buff.add(ch - 128 + 64);
}
continue;
}
} else {
// CTRL
sb
..write('^')
..writeCharCode(ch + 64);
buff
..add(caret)
..add(ch + 64);
continue;
}
}
sb.writeCharCode(ch);
buff.add(ch);
}
if (sb.isNotEmpty) {
out.write(sb);
if (buff.isNotEmpty) {
out.add(buff);
}
});
}