Merge pull request #2 from kemitix/ignore-extra-tokens

Add support to ignore extra tokens on a line
This commit is contained in:
Paul Campbell 2022-01-15 14:45:06 +00:00 committed by GitHub
commit ca0376a181
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 160 additions and 34 deletions

1
.gitignore vendored
View file

@ -5,3 +5,4 @@ deps.zig
/test.in /test.in
/test.out /test.out
/test.expect /test.expect
/dist

15
Makefile Normal file
View file

@ -0,0 +1,15 @@
dist: inttest
mkdir dist
cp zig-out/bin/skip dist/
inttest: zig-out/bin/skip
./test.sh
zig-out/bin/skip: unittest
zig build
unittest: zigmod src/main.zig
zig build test
zigmod: zig.mod
zigmod ci

View file

@ -42,6 +42,8 @@ line 4
### Skip until a number of matching lines ### Skip until a number of matching lines
The whole line must match.
This example reads the named file. This example reads the named file.
File: `input.txt` File: `input.txt`
@ -67,7 +69,9 @@ gamma
alpha alpha
``` ```
### Skip lines until a number of tokens as seen ### Skip lines until a number of tokens are seen
Looks for a string within a line, counting each occurance.
This example reads the file from stdin. This example reads the file from stdin.
@ -99,3 +103,44 @@ commodo consequat.
It matches the first `dolor` on line 1, It matches the first `dolor` on line 1,
and the second on line 4 as part of the word `dolore`. and the second on line 4 as part of the word `dolore`.
### Skip lines until a lines with tokens are seen
Looks for a string within a line, only counting each matching line once.
This example reads the file from stdin.
File: `input.txt`
```text
Lorem ipsum dolor sit amet,
consectetur adipiscing elit,
sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua.
Ut enim ad minim veniam,
quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea
commodo consequat.
```
```bash
cat input.txt | skip 4 --token m --ignore-extras
```
Will output:
```text
quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea
commodo consequat.
```
Without `--ignore-extras`, it would have found the fourth `m` on line 3, and displayed:
```text
ut labore et dolore magna aliqua.
Ut enim ad minim veniam,
quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea
commodo consequat.
```

View file

@ -11,12 +11,6 @@ const clap = @import("clap");
const version = "0.1.0"; const version = "0.1.0";
// step 1: [x] read in a file from stdin and write out to stdout
// step 2: [x] read in a named file in parameters and write out to stdout
// step 3: [x] skip a number of lines
// step 4: [ ] skip a number of matching lines
// step 5: [ ] skip a number of tokens
const maxLineLength = 4096; const maxLineLength = 4096;
pub fn main() anyerror!void { pub fn main() anyerror!void {
@ -52,6 +46,7 @@ const Config = struct {
file: ?fs.File, file: ?fs.File,
line: ?[]const u8 = null, line: ?[]const u8 = null,
token: ?[]const u8 = null, token: ?[]const u8 = null,
ignoreExtras: bool,
pub fn deinit(self: @This()) void { pub fn deinit(self: @This()) void {
if (self.file) |f| { if (self.file) |f| {
@ -62,17 +57,18 @@ const Config = struct {
fn parseArgs(allocator: mem.Allocator) !Config { fn parseArgs(allocator: mem.Allocator) !Config {
const params = comptime [_]clap.Param(clap.Help) { const params = comptime [_]clap.Param(clap.Help) {
clap.parseParam("<N> The number of lines to skip") catch unreachable, clap.parseParam("<N> The number of lines to skip") catch unreachable,
clap.parseParam("[<FILE>] The file to read or stdin if not given") catch unreachable, clap.parseParam("[<FILE>] The file to read or stdin if not given") catch unreachable,
clap.parseParam("-l, --line <STR> Skip until N lines matching this") catch unreachable, clap.parseParam("-l, --line <STR> Skip until N lines matching this") catch unreachable,
clap.parseParam("-t, --token <STR> Skip lines until N tokens found") catch unreachable, clap.parseParam("-t, --token <STR> Skip lines until N tokens found") catch unreachable,
clap.parseParam("-h, --help Display this help and exit") catch unreachable, clap.parseParam("-i, --ignore-extras Only count the first token on each line") catch unreachable,
clap.parseParam("-v, --version Display the version") catch unreachable, clap.parseParam("-h, --help Display this help and exit") catch unreachable,
clap.parseParam("-v, --version Display the version") catch unreachable,
}; };
var diag = clap.Diagnostic{}; var diag = clap.Diagnostic{};
var args = clap.parse(clap.Help, &params, .{ .diagnostic = &diag }) catch |err| { var args = clap.parse(clap.Help, &params, .{ .diagnostic = &diag }) catch |err| {
diag.report(io.getStdErr().writer(), err) catch {}; diag.report(io.getStdErr().writer(), err) catch {};
return err; return error.BadArgs;
}; };
defer args.deinit(); defer args.deinit();
@ -103,6 +99,15 @@ fn parseArgs(allocator: mem.Allocator) !Config {
if (args.option("--token")) |match| { if (args.option("--token")) |match| {
token = try allocator.dupe(u8, match); token = try allocator.dupe(u8, match);
} }
var ignoreExtras: bool = false;
if (args.flag("--ignore-extras")) {
if (token) |_| {
ignoreExtras = true;
} else {
try io.getStdErr().writer().print("Error: --ignore-extras requires --token\n", .{});
return error.BadArgs;
}
}
var n: u32 = 0; var n: u32 = 0;
var file: ?fs.File = null; var file: ?fs.File = null;
@ -128,6 +133,7 @@ fn parseArgs(allocator: mem.Allocator) !Config {
.file = file, .file = file,
.line = line, .line = line,
.token = token, .token = token,
.ignoreExtras = ignoreExtras,
}; };
} }
@ -138,22 +144,23 @@ fn dumpInput(config: Config, in: fs.File, out: fs.File, allocator: mem.Allocator
var c: usize = 0; var c: usize = 0;
while (c < config.lines) { while (c < config.lines) {
const line = it.next(); const line = it.next();
if (config.line) |match| { if (line) |memory| {
if (line) |memory| { if (config.line) |match| {
if (mem.eql(u8, match, memory)) { if (mem.eql(u8, match, memory)) {
c += 1; c += 1;
} }
}
} else {
if (config.token) |token| {
if (line) |memory| {
c += mem.count(u8, memory, token);
}
} else { } else {
c += 1; if (config.token) |token| {
const occurances = mem.count(u8, memory, token);
if (config.ignoreExtras and occurances > 0) {
c += 1;
} else {
c += occurances;
}
} else {
c += 1;
}
} }
}
if (line) |memory| {
allocator.free(memory); allocator.free(memory);
} else return; } else return;
} }
@ -172,6 +179,7 @@ test "dumpInput skip 1 line" {
const config = Config{ const config = Config{
.lines = 1, .lines = 1,
.file = file, .file = file,
.ignoreExtras = false,
}; };
try dumpInput(config, file, output, testing.allocator); try dumpInput(config, file, output, testing.allocator);
@ -202,6 +210,7 @@ test "dumpInput skip 2 line 'alpha'" {
.lines = 2, .lines = 2,
.file = file, .file = file,
.line = "alpha", .line = "alpha",
.ignoreExtras = false,
}; };
try dumpInput(config, file, output, testing.allocator); try dumpInput(config, file, output, testing.allocator);

74
test.sh
View file

@ -2,6 +2,14 @@
set -e set -e
SKIP="./zig-out/bin/skip"
DIFF="diff -u --color"
if test ! -x $SKIP ; then
echo "File missing: $SKIP - try 'zig build'"
exit 1
fi
echo "> skip a line when reading from stdin" echo "> skip a line when reading from stdin"
INPUT=$(cat<<EOF INPUT=$(cat<<EOF
line 1 line 1
@ -9,8 +17,9 @@ line 2
EOF EOF
) )
echo "line 2" > test.expect echo "line 2" > test.expect
echo "$INPUT" | ./skip 1 > test.out echo "$INPUT" | $SKIP 1 > test.out
diff --brief test.expect test.out $DIFF test.expect test.out
rm test.expect test.out
echo "> skip a line when reading from a file" echo "> skip a line when reading from a file"
cat<<EOF > test.in cat<<EOF > test.in
@ -18,8 +27,9 @@ line 1
line 2 line 2
EOF EOF
echo "line 2" > test.expect echo "line 2" > test.expect
./skip 1 test.in > test.out $SKIP 1 test.in > test.out
diff --brief test.expect test.out $DIFF test.expect test.out
rm test.expect test.out
echo "> skip until 2 matching lines seen" echo "> skip until 2 matching lines seen"
cat<<EOF > test.in cat<<EOF > test.in
@ -35,8 +45,9 @@ alpha
gamma gamma
alpha alpha
EOF EOF
./skip 2 test.in --line alpha > test.out $SKIP 2 test.in --line alpha > test.out
diff --brief test.expect test.out $DIFF test.expect test.out
rm test.in test.expect test.out
echo "> skip lines until 2 tokens seen" echo "> skip lines until 2 tokens seen"
cat<<EOF > test.in cat<<EOF > test.in
@ -55,9 +66,54 @@ quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea laboris nisi ut aliquip ex ea
commodo consequat. commodo consequat.
EOF EOF
./skip 2 test.in --token dolor > test.out $SKIP 2 test.in --token dolor > test.out 2
diff --brief test.expect test.out $DIFF test.expect test.out
rm test.in test.expect test.out
rm test.in test.out test.expect echo "> handle unknown parameter with simple error message"
cat<<EOF > test.expect.err
Invalid argument '--foo'
EOF
cat<<EOF > test.expect
EOF
touch test.out test.err
$SKIP --foo > test.out 2> test.err
$DIFF test.expect test.out
$DIFF test.expect.err test.err
rm test.expect test.out
rm test.expect.err test.err
echo "> handle ignore-extra when token is missing"
cat<<EOF > test.expect.err
Error: --ignore-extras requires --token
EOF
cat<<EOF > test.expect
EOF
touch test.out test.err
$SKIP --ignore-extras > test.out 2> test.err
$DIFF test.expect test.out
$DIFF test.expect.err test.err
rm test.expect test.out
rm test.expect.err test.err
echo "> skip lines until 4 tokens seen - ignored extra tokens on same line"
cat<<EOF > test.in
Lorem ipsum dolor sit amet,
consectetur adipiscing elit,
sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua.
Ut enim ad minim veniam,
quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea
commodo consequat.
EOF
cat<<EOF > test.expect
quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea
commodo consequat.
EOF
$SKIP 4 test.in --token m --ignore-extras > test.out
$DIFF test.expect test.out
rm test.in test.expect test.out
echo done echo done