├── 14-lsr ├── tests │ ├── inputs │ │ ├── .hidden │ │ ├── dir │ │ │ ├── .gitkeep │ │ │ └── spiders.txt │ │ ├── empty.txt │ │ ├── fox.txt │ │ └── bustle.txt │ └── cli.rs ├── src │ ├── main.rs │ └── owner.rs └── Cargo.toml ├── 03-catr ├── tests │ ├── inputs │ │ ├── empty.txt │ │ ├── fox.txt │ │ ├── spiders.txt │ │ └── the-bustle.txt │ ├── expected │ │ ├── empty.txt.b.out │ │ ├── empty.txt.n.out │ │ ├── empty.txt.out │ │ ├── fox.txt.out │ │ ├── fox.txt.b.out │ │ ├── fox.txt.n.out │ │ ├── spiders.txt.out │ │ ├── spiders.txt.b.out │ │ ├── spiders.txt.n.out │ │ ├── the-bustle.txt.out │ │ ├── the-bustle.txt.stdin.out │ │ ├── the-bustle.txt.b.out │ │ ├── the-bustle.txt.b.stdin.out │ │ ├── the-bustle.txt.n.out │ │ ├── the-bustle.txt.n.stdin.out │ │ ├── all.out │ │ ├── all.b.out │ │ └── all.n.out │ └── cli.rs ├── src │ ├── main.rs │ └── lib.rs └── Cargo.toml ├── 04-headr ├── tests │ ├── inputs │ │ ├── empty.txt │ │ ├── one.txt │ │ ├── two.txt │ │ ├── three.txt │ │ └── ten.txt │ └── expected │ │ ├── empty.txt.out │ │ ├── empty.txt.c1.out │ │ ├── empty.txt.c2.out │ │ ├── empty.txt.c4.out │ │ ├── empty.txt.n2.out │ │ ├── empty.txt.n4.out │ │ ├── one.txt.c2.out │ │ ├── one.txt.c4.out │ │ ├── ten.txt.c1.out │ │ ├── ten.txt.c2.out │ │ ├── three.txt.c1.out │ │ ├── three.txt.c2.out │ │ ├── two.txt.c1.out │ │ ├── two.txt.c2.out │ │ ├── two.txt.c4.out │ │ ├── ten.txt.c4.out │ │ ├── three.txt.c4.out │ │ ├── ten.txt.n2.out │ │ ├── one.txt.out │ │ ├── three.txt.n2.out │ │ ├── one.txt.n2.out │ │ ├── one.txt.n4.out │ │ ├── two.txt.out │ │ ├── ten.txt.n4.out │ │ ├── two.txt.n2.out │ │ ├── two.txt.n4.out │ │ ├── three.txt.out │ │ ├── three.txt.n4.out │ │ ├── ten.txt.out │ │ ├── all.c1.out │ │ ├── one.txt.c1.out │ │ ├── all.c2.out │ │ ├── all.c4.out │ │ ├── all.n2.out │ │ ├── all.n4.out │ │ └── all.out ├── src │ ├── main.rs │ └── lib.rs └── Cargo.toml ├── 05-wcr ├── tests │ ├── inputs │ │ ├── empty.txt │ │ ├── fox.txt │ │ └── atlamal.txt │ ├── expected │ │ ├── atlamal.txt.stdin.out │ │ ├── empty.txt.c.out │ │ ├── empty.txt.l.out │ │ ├── empty.txt.m.out │ │ ├── empty.txt.w.out │ │ ├── fox.txt.c.out │ │ ├── fox.txt.l.out │ │ ├── fox.txt.m.out │ │ ├── fox.txt.w.out │ │ ├── atlamal.txt.c.out │ │ ├── atlamal.txt.l.out │ │ ├── atlamal.txt.m.out │ │ ├── atlamal.txt.w.out │ │ ├── fox.txt.cl.out │ │ ├── fox.txt.ml.out │ │ ├── fox.txt.wc.out │ │ ├── fox.txt.wl.out │ │ ├── fox.txt.wm.out │ │ ├── empty.txt.cl.out │ │ ├── empty.txt.ml.out │ │ ├── empty.txt.wc.out │ │ ├── empty.txt.wl.out │ │ ├── empty.txt.wm.out │ │ ├── fox.txt.out │ │ ├── atlamal.txt.cl.out │ │ ├── atlamal.txt.ml.out │ │ ├── atlamal.txt.wc.out │ │ ├── atlamal.txt.wl.out │ │ ├── atlamal.txt.wm.out │ │ ├── empty.txt.out │ │ ├── fox.txt.lwm.out │ │ ├── atlamal.txt.out │ │ ├── empty.txt.lwm.out │ │ ├── atlamal.txt.lwm.out │ │ ├── all.c.out │ │ ├── all.l.out │ │ ├── all.m.out │ │ ├── all.w.out │ │ ├── all.cl.out │ │ ├── all.ml.out │ │ ├── all.wc.out │ │ ├── all.wl.out │ │ ├── all.wm.out │ │ ├── all.out │ │ └── all.lwm.out │ └── cli.rs ├── src │ ├── main.rs │ └── lib.rs └── Cargo.toml ├── 06-uniqr ├── tests │ ├── inputs │ │ ├── empty.txt │ │ ├── one.txt │ │ ├── t2.txt │ │ ├── t3.txt │ │ ├── t1.txt │ │ ├── t4.txt │ │ ├── two.txt │ │ ├── t5.txt │ │ ├── t6.txt │ │ ├── skip.txt │ │ └── three.txt │ └── expected │ │ ├── empty.txt.out │ │ ├── empty.txt.c.out │ │ ├── empty.txt.stdin.out │ │ ├── one.txt.out │ │ ├── t1.txt.out │ │ ├── t2.txt.out │ │ ├── t3.txt.out │ │ ├── t4.txt.out │ │ ├── two.txt.out │ │ ├── empty.txt.stdin.c.out │ │ ├── one.txt.c.out │ │ ├── one.txt.stdin.out │ │ ├── t1.txt.c.out │ │ ├── t1.txt.stdin.out │ │ ├── t2.txt.c.out │ │ ├── t2.txt.stdin.out │ │ ├── t3.txt.stdin.out │ │ ├── t4.txt.stdin.out │ │ ├── t5.txt.out │ │ ├── two.txt.c.out │ │ ├── two.txt.stdin.out │ │ ├── t1.txt.stdin.c.out │ │ ├── t2.txt.stdin.c.out │ │ ├── t3.txt.c.out │ │ ├── t4.txt.c.out │ │ ├── t5.txt.stdin.out │ │ ├── t6.txt.out │ │ ├── one.txt.stdin.c.out │ │ ├── t5.txt.c.out │ │ ├── t6.txt.stdin.out │ │ ├── two.txt.stdin.c.out │ │ ├── skip.txt.out │ │ ├── t3.txt.stdin.c.out │ │ ├── t4.txt.stdin.c.out │ │ ├── skip.txt.stdin.out │ │ ├── t5.txt.stdin.c.out │ │ ├── t6.txt.c.out │ │ ├── three.txt.out │ │ ├── t6.txt.stdin.c.out │ │ ├── skip.txt.c.out │ │ ├── three.txt.stdin.out │ │ ├── skip.txt.stdin.c.out │ │ ├── three.txt.c.out │ │ └── three.txt.stdin.c.out ├── src │ ├── main.rs │ └── lib.rs └── Cargo.toml ├── 07-findr ├── tests │ ├── inputs │ │ ├── g.csv │ │ ├── a │ │ │ ├── a.txt │ │ │ └── b │ │ │ │ ├── b.csv │ │ │ │ └── c │ │ │ │ └── c.mp3 │ │ ├── d │ │ │ ├── b.csv │ │ │ ├── d.tsv │ │ │ ├── d.txt │ │ │ └── e │ │ │ │ └── e.mp3 │ │ └── f │ │ │ └── f.txt │ └── expected │ │ ├── type_l.txt.windows │ │ ├── path_g.txt │ │ ├── type_d_name_a.txt │ │ ├── type_l.txt │ │ ├── path_g.txt.windows │ │ ├── type_d_name_a.txt.windows │ │ ├── type_f_name_a.txt │ │ ├── name_a.txt │ │ ├── type_f_name_a.txt.windows │ │ ├── type_d_path_d.txt │ │ ├── name_a.txt.windows │ │ ├── type_d_path_a_b.txt │ │ ├── type_d_path_d.txt.windows │ │ ├── name_txt_path_a_d.txt │ │ ├── type_d_path_a_b.txt.windows │ │ ├── name_txt_path_a_d.txt.windows │ │ ├── type_f_path_a_b.txt │ │ ├── type_d_path_a.txt │ │ ├── type_f_path_a_b.txt.windows │ │ ├── name_csv.txt │ │ ├── type_d_path_a.txt.windows │ │ ├── type_f_path_d.txt │ │ ├── name_csv.txt.windows │ │ ├── type_f_path_a.txt │ │ ├── type_d_path_a_b_d.txt │ │ ├── type_f_path_a.txt.windows │ │ ├── path_a_b.txt │ │ ├── type_d_path_a_b_d.txt.windows │ │ ├── path_a_b.txt.windows │ │ ├── type_f_path_d.txt.windows │ │ ├── name_csv_mp3.txt │ │ ├── type_d.txt │ │ ├── path_a.txt │ │ ├── path_d.txt │ │ ├── type_f_path_a_b_d.txt │ │ ├── name_csv_mp3.txt.windows │ │ ├── type_d.txt.windows │ │ ├── path_a.txt.windows │ │ ├── path_d.txt.windows │ │ ├── type_f_path_a_b_d.txt.windows │ │ ├── type_f.txt │ │ ├── type_f_l.txt │ │ ├── type_f.txt.windows │ │ ├── type_f_l.txt.windows │ │ ├── path_a_b_d.txt │ │ ├── path_a_b_d.txt.windows │ │ ├── path1.txt │ │ ├── path1.txt.windows │ │ └── unreadable_dir.txt ├── src │ ├── main.rs │ └── lib.rs └── Cargo.toml ├── 09-grepr ├── tests │ ├── expected │ │ ├── empty.foo │ │ ├── foo.empty.txt │ │ ├── nobody.txt │ │ ├── nobody.txt.count │ │ ├── nobody.txt.insensitive.count │ │ ├── bustle.txt.the.capitalized.count │ │ ├── bustle.txt.the.lowercase.count │ │ ├── the.recursive.insensitive.count.stdin │ │ ├── bustle.txt.the.lowercase.insensitive.count │ │ ├── bustle.txt.the.lowercase │ │ ├── empty_regex.fox.txt │ │ ├── nobody.txt.insensitive │ │ ├── dog.recursive │ │ ├── the.recursive.insensitive │ │ ├── the.recursive.insensitive.windows │ │ ├── dog.recursive.windows │ │ ├── bustle.txt.the.capitalized │ │ ├── bustle.txt.the.lowercase.insensistive │ │ ├── bustle.txt.the.lowercase.insensitive │ │ ├── all.the.capitalized.count │ │ ├── the.recursive.insensitive.count │ │ ├── all.the.lowercase.insensitive.count │ │ ├── all.the.capitalized │ │ ├── all.the.lowercase.insensistive │ │ └── all.the.lowercase.insensitive │ └── inputs │ │ ├── empty.txt │ │ ├── fox.txt │ │ ├── bustle.txt │ │ └── nobody.txt ├── src │ ├── main.rs │ └── lib.rs └── Cargo.toml ├── 10-commr ├── tests │ ├── inputs │ │ ├── empty.txt │ │ ├── blank.txt │ │ ├── file2.txt │ │ ├── foo.txt │ │ ├── bar.txt │ │ ├── file1.txt │ │ ├── file3.txt │ │ ├── cities1.txt │ │ ├── cities1_lower.txt │ │ ├── cities2.txt │ │ └── cities2_upper.txt │ └── expected │ │ ├── empty_empty.out │ │ ├── file1_file2.123.out │ │ ├── file1_blank.1.out │ │ ├── file1_file2.12.out │ │ ├── file1_file2.123.i.out │ │ ├── file1_file2.13.i.out │ │ ├── file1_file2.13.out │ │ ├── empty_file2.out │ │ ├── file1_file2.123.delim.out │ │ ├── file1_file2.1.i.out │ │ ├── file1_file2.1.out │ │ ├── file1_file2.12.delim.out │ │ ├── file1_file2.12.i.out │ │ ├── file1_file2.13.delim.out │ │ ├── file1_file2.23.i.out │ │ ├── file1_file2.3.i.out │ │ ├── file1_empty.out │ │ ├── file1_file2.1.delim.out │ │ ├── file1_file2.23.out │ │ ├── file1_blank.2.out │ │ ├── file1_file2.2.out │ │ ├── file1_file2.23.delim.out │ │ ├── file1_file2.3.out │ │ ├── blank_file1.out │ │ ├── file1_blank.3.out │ │ ├── file1_blank.out │ │ ├── file1_file1.out │ │ ├── file1_file2.2.delim.out │ │ ├── file1_file2.2.i.out │ │ ├── file1_file2.3.delim.out │ │ ├── file1_file2.out │ │ └── file1_file2.delim.out ├── src │ ├── main.rs │ └── lib.rs └── Cargo.toml ├── 11-tailr ├── tests │ ├── inputs │ │ ├── empty.txt │ │ ├── one.txt │ │ ├── two.txt │ │ ├── three.txt │ │ └── ten.txt │ └── expected │ │ ├── empty.txt.out │ │ ├── one.txt.n0.out │ │ ├── ten.txt.n0.out │ │ ├── two.txt.n0.out │ │ ├── empty.txt.c+0.out │ │ ├── empty.txt.c+1.out │ │ ├── empty.txt.c+2.out │ │ ├── empty.txt.c12.out │ │ ├── empty.txt.c200.out │ │ ├── empty.txt.c3.out │ │ ├── empty.txt.c8.out │ │ ├── empty.txt.n+0.out │ │ ├── empty.txt.n+1.out │ │ ├── empty.txt.n+2.out │ │ ├── empty.txt.n0.out │ │ ├── empty.txt.n1.out │ │ ├── empty.txt.n200.out │ │ ├── empty.txt.n3.out │ │ ├── empty.txt.n4.out │ │ ├── one.txt.n+2.out │ │ ├── three.txt.n0.out │ │ ├── ten.txt.c3.out │ │ ├── ten.txt.n1.out │ │ ├── three.txt.c3.out │ │ ├── two.txt.c3.out │ │ ├── one.txt.c8.out │ │ ├── three.txt.c8.out │ │ ├── two.txt.c8.out │ │ ├── one.txt.c12.out │ │ ├── ten.txt.c8.out │ │ ├── three.txt.c12.out │ │ ├── three.txt.n1.out │ │ ├── two.txt.c12.out │ │ ├── two.txt.n+2.out │ │ ├── two.txt.n1.out │ │ ├── one.txt.out │ │ ├── ten.txt.c12.out │ │ ├── one.txt.c+0.out │ │ ├── one.txt.c+1.out │ │ ├── one.txt.c200.out │ │ ├── one.txt.n+0.out │ │ ├── one.txt.n+1.out │ │ ├── one.txt.n1.out │ │ ├── one.txt.n200.out │ │ ├── one.txt.n3.out │ │ ├── one.txt.n4.out │ │ ├── ten.txt.n3.out │ │ ├── two.txt.out │ │ ├── three.txt.n+2.out │ │ ├── two.txt.c+0.out │ │ ├── two.txt.c+1.out │ │ ├── two.txt.c+2.out │ │ ├── two.txt.c200.out │ │ ├── two.txt.n+0.out │ │ ├── two.txt.n+1.out │ │ ├── two.txt.n200.out │ │ ├── two.txt.n3.out │ │ ├── two.txt.n4.out │ │ ├── ten.txt.n4.out │ │ ├── three.txt.out │ │ ├── three.txt.c+0.out │ │ ├── three.txt.c+1.out │ │ ├── three.txt.c+2.out │ │ ├── three.txt.c200.out │ │ ├── three.txt.n+0.out │ │ ├── three.txt.n+1.out │ │ ├── three.txt.n200.out │ │ ├── three.txt.n3.out │ │ ├── three.txt.n4.out │ │ ├── all.n1.q.out │ │ ├── ten.txt.n+2.out │ │ ├── all.n+3.q.out │ │ ├── ten.txt.c+2.out │ │ ├── ten.txt.out │ │ ├── ten.txt.c+0.out │ │ ├── ten.txt.c+1.out │ │ ├── ten.txt.c200.out │ │ ├── ten.txt.n+0.out │ │ ├── ten.txt.n+1.out │ │ ├── ten.txt.n200.out │ │ ├── all.c3.out │ │ ├── one.txt.c+2.out │ │ ├── one.txt.c3.out │ │ ├── all.n3.q.out │ │ ├── all.c0.out │ │ ├── all.n0.out │ │ ├── all.c8.out │ │ ├── all.n1.out │ │ ├── all.c12.out │ │ ├── all.n+3.out │ │ ├── all.n3.out │ │ ├── all.c+12.out │ │ ├── all.c+8.out │ │ ├── all.c+3.out │ │ ├── all.out │ │ └── all.n+1.out ├── src │ ├── main.rs │ └── lib.rs └── Cargo.toml ├── 12-fortuner ├── tests │ ├── expected │ │ ├── berra_lower.err │ │ ├── berra_lower.out │ │ ├── twain_lower.err │ │ ├── twain_lower.out │ │ ├── berra_cap.err │ │ ├── berra_lower_i.err │ │ ├── twain_cap.err │ │ ├── twain_lower_i.err │ │ ├── berra_cap.out │ │ ├── berra_lower_i.out │ │ ├── twain_cap.out │ │ └── twain_lower_i.out │ ├── inputs │ │ ├── empty │ │ │ └── .gitkeep │ │ ├── jokes.dat │ │ ├── quotes.dat │ │ ├── ascii-art.dat │ │ ├── literature.dat │ │ ├── literature │ │ ├── jokes │ │ ├── quotes │ │ └── ascii-art │ └── cli.rs ├── src │ ├── main.rs │ └── lib.rs ├── mk-dat.sh └── Cargo.toml ├── 02-echor ├── tests │ ├── expected │ │ ├── hello1.n.txt │ │ ├── hello2.n.txt │ │ ├── hello1.txt │ │ └── hello2.txt │ └── cli.rs ├── mk-outs.sh ├── Cargo.toml └── src │ └── main.rs ├── 08-cutr ├── tests │ ├── expected │ │ ├── movies1.csv.b1.out │ │ ├── movies1.csv.b2.out │ │ ├── movies1.csv.c1.out │ │ ├── movies1.csv.c2.out │ │ ├── movies1.csv.c8.out │ │ ├── movies1.tsv.b1.out │ │ ├── movies1.tsv.b2.out │ │ ├── movies1.tsv.c1.out │ │ ├── movies1.tsv.c2.out │ │ ├── movies1.tsv.c8.out │ │ ├── books.c1,1.out │ │ ├── movies1.csv.b1-2.out │ │ ├── movies1.csv.b2-3.out │ │ ├── movies1.csv.c1-2.out │ │ ├── movies1.csv.c2-3.out │ │ ├── movies1.tsv.b1-2.out │ │ ├── movies1.tsv.b2-3.out │ │ ├── movies1.tsv.c1-2.out │ │ ├── movies1.tsv.c2-3.out │ │ ├── movies1.tsv.f2.out │ │ ├── movies1.csv.f2.dcomma.out │ │ ├── movies1.csv.c1-8.out │ │ ├── movies1.tsv.c1-8.out │ │ ├── movies1.tsv.f3.out │ │ ├── movies1.csv.f3.dcomma.out │ │ ├── movies1.tsv.f1.out │ │ ├── movies1.csv.f1.dcomma.out │ │ ├── movies1.tsv.f2-3.out │ │ ├── movies1.csv.f2-3.dcomma.out │ │ ├── movies1.tsv.f1-2.out │ │ ├── movies1.csv.f1-2.dcomma.out │ │ ├── movies1.tsv.f1-3.out │ │ ├── movies1.csv.f1-3.dcomma.out │ │ ├── movies1.csv.b8.out │ │ ├── movies1.tsv.b8.out │ │ ├── movies1.csv.b1-8.out │ │ └── movies1.tsv.b1-8.out │ └── inputs │ │ ├── movies1.csv │ │ ├── movies1.tsv │ │ ├── movies2.tsv │ │ ├── movies2.csv │ │ ├── books.tsv │ │ ├── books.csv │ │ └── books.txt ├── src │ └── main.rs └── Cargo.toml ├── README.md ├── 03-catr.pdf ├── 05-wcr.pdf ├── 08-cutr.pdf ├── 13-calr.pdf ├── 14-lsr.pdf ├── 02-echor.pdf ├── 04-headr.pdf ├── 06-uniqr.pdf ├── 09-grepr.pdf ├── 10-commr.pdf ├── 11-tailr.pdf ├── 12-fortuner.pdf ├── 13-calr ├── src │ └── main.rs ├── tests │ ├── expected │ │ ├── 2-2020.txt │ │ ├── 4-2020.txt │ │ ├── 5-2020.txt │ │ └── 2020.txt │ └── cli.rs └── Cargo.toml └── .gitignore /14-lsr/tests/inputs/.hidden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /03-catr/tests/inputs/empty.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /04-headr/tests/inputs/empty.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /05-wcr/tests/inputs/empty.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /06-uniqr/tests/inputs/empty.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /07-findr/tests/inputs/g.csv: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/empty.foo: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /09-grepr/tests/inputs/empty.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /10-commr/tests/inputs/empty.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/inputs/empty.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /14-lsr/tests/inputs/dir/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /14-lsr/tests/inputs/empty.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /03-catr/tests/expected/empty.txt.b.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /03-catr/tests/expected/empty.txt.n.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /03-catr/tests/expected/empty.txt.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /04-headr/tests/expected/empty.txt.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/empty.txt.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /06-uniqr/tests/inputs/one.txt: -------------------------------------------------------------------------------- 1 | a 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/inputs/t2.txt: -------------------------------------------------------------------------------- 1 | a 2 | a -------------------------------------------------------------------------------- /06-uniqr/tests/inputs/t3.txt: -------------------------------------------------------------------------------- 1 | a 2 | b -------------------------------------------------------------------------------- /07-findr/tests/inputs/a/a.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /07-findr/tests/inputs/a/b/b.csv: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /07-findr/tests/inputs/d/b.csv: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /07-findr/tests/inputs/d/d.tsv: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /07-findr/tests/inputs/d/d.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /07-findr/tests/inputs/d/e/e.mp3: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /07-findr/tests/inputs/f/f.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/foo.empty.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/nobody.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /10-commr/tests/inputs/blank.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/empty.txt.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/one.txt.n0.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/ten.txt.n0.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/two.txt.n0.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /04-headr/tests/expected/empty.txt.c1.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /04-headr/tests/expected/empty.txt.c2.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /04-headr/tests/expected/empty.txt.c4.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /04-headr/tests/expected/empty.txt.n2.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /04-headr/tests/expected/empty.txt.n4.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /04-headr/tests/expected/one.txt.c2.out: -------------------------------------------------------------------------------- 1 | Ö -------------------------------------------------------------------------------- /04-headr/tests/expected/one.txt.c4.out: -------------------------------------------------------------------------------- 1 | Öne -------------------------------------------------------------------------------- /04-headr/tests/expected/ten.txt.c1.out: -------------------------------------------------------------------------------- 1 | o -------------------------------------------------------------------------------- /04-headr/tests/expected/ten.txt.c2.out: -------------------------------------------------------------------------------- 1 | on -------------------------------------------------------------------------------- /04-headr/tests/expected/three.txt.c1.out: -------------------------------------------------------------------------------- 1 | T -------------------------------------------------------------------------------- /04-headr/tests/expected/three.txt.c2.out: -------------------------------------------------------------------------------- 1 | Th -------------------------------------------------------------------------------- /04-headr/tests/expected/two.txt.c1.out: -------------------------------------------------------------------------------- 1 | T -------------------------------------------------------------------------------- /04-headr/tests/expected/two.txt.c2.out: -------------------------------------------------------------------------------- 1 | Tw -------------------------------------------------------------------------------- /04-headr/tests/expected/two.txt.c4.out: -------------------------------------------------------------------------------- 1 | Two -------------------------------------------------------------------------------- /06-uniqr/tests/expected/empty.txt.c.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/empty.txt.stdin.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/one.txt.out: -------------------------------------------------------------------------------- 1 | a 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t1.txt.out: -------------------------------------------------------------------------------- 1 | a 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t2.txt.out: -------------------------------------------------------------------------------- 1 | a 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t3.txt.out: -------------------------------------------------------------------------------- 1 | a 2 | b -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t4.txt.out: -------------------------------------------------------------------------------- 1 | a 2 | b -------------------------------------------------------------------------------- /06-uniqr/tests/expected/two.txt.out: -------------------------------------------------------------------------------- 1 | a 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/inputs/t1.txt: -------------------------------------------------------------------------------- 1 | a 2 | a 3 | -------------------------------------------------------------------------------- /06-uniqr/tests/inputs/t4.txt: -------------------------------------------------------------------------------- 1 | a 2 | a 3 | b -------------------------------------------------------------------------------- /06-uniqr/tests/inputs/two.txt: -------------------------------------------------------------------------------- 1 | a 2 | a 3 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_l.txt.windows: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /07-findr/tests/inputs/a/b/c/c.mp3: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /10-commr/tests/expected/empty_empty.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.123.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /10-commr/tests/inputs/file2.txt: -------------------------------------------------------------------------------- 1 | B 2 | c 3 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/empty.txt.c+0.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/empty.txt.c+1.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/empty.txt.c+2.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/empty.txt.c12.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/empty.txt.c200.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/empty.txt.c3.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/empty.txt.c8.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/empty.txt.n+0.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/empty.txt.n+1.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/empty.txt.n+2.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/empty.txt.n0.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/empty.txt.n1.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/empty.txt.n200.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/empty.txt.n3.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/empty.txt.n4.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/one.txt.n+2.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/three.txt.n0.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /12-fortuner/tests/expected/berra_lower.err: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /12-fortuner/tests/expected/berra_lower.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /12-fortuner/tests/expected/twain_lower.err: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /12-fortuner/tests/expected/twain_lower.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /12-fortuner/tests/inputs/empty/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /02-echor/tests/expected/hello1.n.txt: -------------------------------------------------------------------------------- 1 | Hello there -------------------------------------------------------------------------------- /02-echor/tests/expected/hello2.n.txt: -------------------------------------------------------------------------------- 1 | Hello there -------------------------------------------------------------------------------- /04-headr/tests/expected/ten.txt.c4.out: -------------------------------------------------------------------------------- 1 | one 2 | -------------------------------------------------------------------------------- /04-headr/tests/expected/three.txt.c4.out: -------------------------------------------------------------------------------- 1 | Thre -------------------------------------------------------------------------------- /06-uniqr/tests/expected/empty.txt.stdin.c.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/one.txt.c.out: -------------------------------------------------------------------------------- 1 | 1 a 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/one.txt.stdin.out: -------------------------------------------------------------------------------- 1 | a 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t1.txt.c.out: -------------------------------------------------------------------------------- 1 | 2 a 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t1.txt.stdin.out: -------------------------------------------------------------------------------- 1 | a 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t2.txt.c.out: -------------------------------------------------------------------------------- 1 | 2 a 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t2.txt.stdin.out: -------------------------------------------------------------------------------- 1 | a 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t3.txt.stdin.out: -------------------------------------------------------------------------------- 1 | a 2 | b -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t4.txt.stdin.out: -------------------------------------------------------------------------------- 1 | a 2 | b -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t5.txt.out: -------------------------------------------------------------------------------- 1 | b 2 | a 3 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/two.txt.c.out: -------------------------------------------------------------------------------- 1 | 2 a 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/two.txt.stdin.out: -------------------------------------------------------------------------------- 1 | a 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/inputs/t5.txt: -------------------------------------------------------------------------------- 1 | b 2 | a 3 | a 4 | -------------------------------------------------------------------------------- /06-uniqr/tests/inputs/t6.txt: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | c 4 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/nobody.txt.count: -------------------------------------------------------------------------------- 1 | 0 2 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_blank.1.out: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.12.out: -------------------------------------------------------------------------------- 1 | c 2 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.123.i.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.13.i.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.13.out: -------------------------------------------------------------------------------- 1 | B 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/ten.txt.c3.out: -------------------------------------------------------------------------------- 1 | en 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/ten.txt.n1.out: -------------------------------------------------------------------------------- 1 | ten 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/three.txt.c3.out: -------------------------------------------------------------------------------- 1 | s. 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/two.txt.c3.out: -------------------------------------------------------------------------------- 1 | s. 2 | -------------------------------------------------------------------------------- /02-echor/tests/expected/hello1.txt: -------------------------------------------------------------------------------- 1 | Hello there 2 | -------------------------------------------------------------------------------- /02-echor/tests/expected/hello2.txt: -------------------------------------------------------------------------------- 1 | Hello there 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t1.txt.stdin.c.out: -------------------------------------------------------------------------------- 1 | 2 a 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t2.txt.stdin.c.out: -------------------------------------------------------------------------------- 1 | 2 a 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t3.txt.c.out: -------------------------------------------------------------------------------- 1 | 1 a 2 | 1 b -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t4.txt.c.out: -------------------------------------------------------------------------------- 1 | 2 a 2 | 1 b -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t5.txt.stdin.out: -------------------------------------------------------------------------------- 1 | b 2 | a 3 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t6.txt.out: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | c 4 | -------------------------------------------------------------------------------- /06-uniqr/tests/inputs/skip.txt: -------------------------------------------------------------------------------- 1 | a 2 | 3 | a 4 | b 5 | -------------------------------------------------------------------------------- /10-commr/tests/expected/empty_file2.out: -------------------------------------------------------------------------------- 1 | B 2 | c 3 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.123.delim.out: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /10-commr/tests/inputs/foo.txt: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/one.txt.c8.out: -------------------------------------------------------------------------------- 1 | wordś. 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/three.txt.c8.out: -------------------------------------------------------------------------------- 1 | words. 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/two.txt.c8.out: -------------------------------------------------------------------------------- 1 | words. 2 | -------------------------------------------------------------------------------- /04-headr/tests/expected/ten.txt.n2.out: -------------------------------------------------------------------------------- 1 | one 2 | two 3 | -------------------------------------------------------------------------------- /04-headr/tests/inputs/one.txt: -------------------------------------------------------------------------------- 1 | Öne line, four words. 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/one.txt.stdin.c.out: -------------------------------------------------------------------------------- 1 | 1 a 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t5.txt.c.out: -------------------------------------------------------------------------------- 1 | 1 b 2 | 2 a 3 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t6.txt.stdin.out: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | c 4 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/two.txt.stdin.c.out: -------------------------------------------------------------------------------- 1 | 2 a 2 | -------------------------------------------------------------------------------- /07-findr/tests/expected/path_g.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/g.csv 2 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/nobody.txt.insensitive.count: -------------------------------------------------------------------------------- 1 | 2 2 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.1.i.out: -------------------------------------------------------------------------------- 1 | b 2 | c 3 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.1.out: -------------------------------------------------------------------------------- 1 | B 2 | c 3 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.12.delim.out: -------------------------------------------------------------------------------- 1 | c 2 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.12.i.out: -------------------------------------------------------------------------------- 1 | b 2 | c 3 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.13.delim.out: -------------------------------------------------------------------------------- 1 | B 2 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.23.i.out: -------------------------------------------------------------------------------- 1 | a 2 | d 3 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.3.i.out: -------------------------------------------------------------------------------- 1 | a 2 | d 3 | -------------------------------------------------------------------------------- /10-commr/tests/inputs/bar.txt: -------------------------------------------------------------------------------- 1 | foo 2 | baz 3 | quux 4 | -------------------------------------------------------------------------------- /10-commr/tests/inputs/file1.txt: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | c 4 | d 5 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/one.txt.c12.out: -------------------------------------------------------------------------------- 1 | our wordś. 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/ten.txt.c8.out: -------------------------------------------------------------------------------- 1 | ine 2 | ten 3 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/three.txt.c12.out: -------------------------------------------------------------------------------- 1 | four words. 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/three.txt.n1.out: -------------------------------------------------------------------------------- 1 | four words. 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/two.txt.c12.out: -------------------------------------------------------------------------------- 1 | Four words. 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/two.txt.n+2.out: -------------------------------------------------------------------------------- 1 | Four words. 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/two.txt.n1.out: -------------------------------------------------------------------------------- 1 | Four words. 2 | -------------------------------------------------------------------------------- /11-tailr/tests/inputs/one.txt: -------------------------------------------------------------------------------- 1 | Öne line, four wordś. 2 | -------------------------------------------------------------------------------- /04-headr/tests/expected/one.txt.out: -------------------------------------------------------------------------------- 1 | Öne line, four words. 2 | -------------------------------------------------------------------------------- /04-headr/tests/expected/three.txt.n2.out: -------------------------------------------------------------------------------- 1 | Three 2 | lines, 3 | -------------------------------------------------------------------------------- /04-headr/tests/inputs/two.txt: -------------------------------------------------------------------------------- 1 | Two lines. 2 | Four words. 3 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/skip.txt.out: -------------------------------------------------------------------------------- 1 | a 2 | 3 | a 4 | b 5 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t3.txt.stdin.c.out: -------------------------------------------------------------------------------- 1 | 1 a 2 | 1 b -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t4.txt.stdin.c.out: -------------------------------------------------------------------------------- 1 | 2 a 2 | 1 b -------------------------------------------------------------------------------- /07-findr/tests/expected/type_d_name_a.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/a 2 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_l.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/d/b.csv 2 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.csv.b1.out: -------------------------------------------------------------------------------- 1 | t 2 | T 3 | L 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.csv.b2.out: -------------------------------------------------------------------------------- 1 | i 2 | h 3 | e 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.csv.c1.out: -------------------------------------------------------------------------------- 1 | t 2 | T 3 | L 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.csv.c2.out: -------------------------------------------------------------------------------- 1 | i 2 | h 3 | e 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.csv.c8.out: -------------------------------------------------------------------------------- 1 | e 2 | e 3 | é 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.tsv.b1.out: -------------------------------------------------------------------------------- 1 | t 2 | T 3 | L 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.tsv.b2.out: -------------------------------------------------------------------------------- 1 | i 2 | h 3 | e 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.tsv.c1.out: -------------------------------------------------------------------------------- 1 | t 2 | T 3 | L 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.tsv.c2.out: -------------------------------------------------------------------------------- 1 | i 2 | h 3 | e 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.tsv.c8.out: -------------------------------------------------------------------------------- 1 | e 2 | e 3 | é 4 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/bustle.txt.the.capitalized.count: -------------------------------------------------------------------------------- 1 | 3 2 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/bustle.txt.the.lowercase.count: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_empty.out: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | c 4 | d 5 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.1.delim.out: -------------------------------------------------------------------------------- 1 | B 2 | :c 3 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.23.out: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | d 4 | -------------------------------------------------------------------------------- /10-commr/tests/inputs/file3.txt: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | b 4 | c 5 | d 6 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/one.txt.out: -------------------------------------------------------------------------------- 1 | Öne line, four wordś. 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/ten.txt.c12.out: -------------------------------------------------------------------------------- 1 | ht 2 | nine 3 | ten 4 | -------------------------------------------------------------------------------- /11-tailr/tests/inputs/two.txt: -------------------------------------------------------------------------------- 1 | Two lines. 2 | Four words. 3 | -------------------------------------------------------------------------------- /12-fortuner/tests/expected/berra_cap.err: -------------------------------------------------------------------------------- 1 | (quotes) 2 | % 3 | -------------------------------------------------------------------------------- /12-fortuner/tests/expected/berra_lower_i.err: -------------------------------------------------------------------------------- 1 | (quotes) 2 | % 3 | -------------------------------------------------------------------------------- /04-headr/tests/expected/one.txt.n2.out: -------------------------------------------------------------------------------- 1 | Öne line, four words. 2 | -------------------------------------------------------------------------------- /04-headr/tests/expected/one.txt.n4.out: -------------------------------------------------------------------------------- 1 | Öne line, four words. 2 | -------------------------------------------------------------------------------- /04-headr/tests/expected/two.txt.out: -------------------------------------------------------------------------------- 1 | Two lines. 2 | Four words. 3 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/skip.txt.stdin.out: -------------------------------------------------------------------------------- 1 | a 2 | 3 | a 4 | b 5 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t5.txt.stdin.c.out: -------------------------------------------------------------------------------- 1 | 1 b 2 | 2 a 3 | -------------------------------------------------------------------------------- /07-findr/tests/expected/path_g.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs/g.csv 2 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_d_name_a.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs\a 2 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_f_name_a.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/a/a.txt 2 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/books.c1,1.out: -------------------------------------------------------------------------------- 1 | AA 2 | ÉÉ 3 | SS 4 | JJ 5 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.csv.b1-2.out: -------------------------------------------------------------------------------- 1 | ti 2 | Th 3 | Le 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.csv.b2-3.out: -------------------------------------------------------------------------------- 1 | it 2 | he 3 | es 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.csv.c1-2.out: -------------------------------------------------------------------------------- 1 | ti 2 | Th 3 | Le 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.csv.c2-3.out: -------------------------------------------------------------------------------- 1 | it 2 | he 3 | es 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.tsv.b1-2.out: -------------------------------------------------------------------------------- 1 | ti 2 | Th 3 | Le 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.tsv.b2-3.out: -------------------------------------------------------------------------------- 1 | it 2 | he 3 | es 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.tsv.c1-2.out: -------------------------------------------------------------------------------- 1 | ti 2 | Th 3 | Le 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.tsv.c2-3.out: -------------------------------------------------------------------------------- 1 | it 2 | he 3 | es 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.tsv.f2.out: -------------------------------------------------------------------------------- 1 | year 2 | 1980 3 | 2019 4 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/the.recursive.insensitive.count.stdin: -------------------------------------------------------------------------------- 1 | 7 2 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_blank.2.out: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | c 4 | d 5 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.2.out: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | c 4 | d 5 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.23.delim.out: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | d 4 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.3.out: -------------------------------------------------------------------------------- 1 | B 2 | a 3 | b 4 | d 5 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/one.txt.c+0.out: -------------------------------------------------------------------------------- 1 | Öne line, four wordś. 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/one.txt.c+1.out: -------------------------------------------------------------------------------- 1 | Öne line, four wordś. 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/one.txt.c200.out: -------------------------------------------------------------------------------- 1 | Öne line, four wordś. 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/one.txt.n+0.out: -------------------------------------------------------------------------------- 1 | Öne line, four wordś. 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/one.txt.n+1.out: -------------------------------------------------------------------------------- 1 | Öne line, four wordś. 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/one.txt.n1.out: -------------------------------------------------------------------------------- 1 | Öne line, four wordś. 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/one.txt.n200.out: -------------------------------------------------------------------------------- 1 | Öne line, four wordś. 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/one.txt.n3.out: -------------------------------------------------------------------------------- 1 | Öne line, four wordś. 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/one.txt.n4.out: -------------------------------------------------------------------------------- 1 | Öne line, four wordś. 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/ten.txt.n3.out: -------------------------------------------------------------------------------- 1 | eight 2 | nine 3 | ten 4 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/two.txt.out: -------------------------------------------------------------------------------- 1 | Two lines. 2 | Four words. 3 | -------------------------------------------------------------------------------- /04-headr/tests/expected/ten.txt.n4.out: -------------------------------------------------------------------------------- 1 | one 2 | two 3 | three 4 | four 5 | -------------------------------------------------------------------------------- /04-headr/tests/expected/two.txt.n2.out: -------------------------------------------------------------------------------- 1 | Two lines. 2 | Four words. 3 | -------------------------------------------------------------------------------- /04-headr/tests/expected/two.txt.n4.out: -------------------------------------------------------------------------------- 1 | Two lines. 2 | Four words. 3 | -------------------------------------------------------------------------------- /04-headr/tests/inputs/three.txt: -------------------------------------------------------------------------------- 1 | Three 2 | lines, 3 | four words. 4 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/atlamal.txt.stdin.out: -------------------------------------------------------------------------------- 1 | 4 29 177 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/empty.txt.c.out: -------------------------------------------------------------------------------- 1 | 0 tests/inputs/empty.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/empty.txt.l.out: -------------------------------------------------------------------------------- 1 | 0 tests/inputs/empty.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/empty.txt.m.out: -------------------------------------------------------------------------------- 1 | 0 tests/inputs/empty.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/empty.txt.w.out: -------------------------------------------------------------------------------- 1 | 0 tests/inputs/empty.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/fox.txt.c.out: -------------------------------------------------------------------------------- 1 | 48 tests/inputs/fox.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/fox.txt.l.out: -------------------------------------------------------------------------------- 1 | 1 tests/inputs/fox.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/fox.txt.m.out: -------------------------------------------------------------------------------- 1 | 48 tests/inputs/fox.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/fox.txt.w.out: -------------------------------------------------------------------------------- 1 | 9 tests/inputs/fox.txt 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t6.txt.c.out: -------------------------------------------------------------------------------- 1 | 1 a 2 | 1 b 3 | 1 c 4 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/three.txt.out: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | a 4 | c 5 | a 6 | d 7 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/bustle.txt.the.lowercase.insensitive.count: -------------------------------------------------------------------------------- 1 | 3 2 | -------------------------------------------------------------------------------- /10-commr/tests/expected/blank_file1.out: -------------------------------------------------------------------------------- 1 | 2 | a 3 | b 4 | c 5 | d 6 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_blank.3.out: -------------------------------------------------------------------------------- 1 | 2 | a 3 | b 4 | c 5 | d 6 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_blank.out: -------------------------------------------------------------------------------- 1 | 2 | a 3 | b 4 | c 5 | d 6 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file1.out: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | c 4 | d 5 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.2.delim.out: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | :c 4 | d 5 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.2.i.out: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | c 4 | d 5 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.3.delim.out: -------------------------------------------------------------------------------- 1 | :B 2 | a 3 | b 4 | d 5 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.out: -------------------------------------------------------------------------------- 1 | B 2 | a 3 | b 4 | c 5 | d 6 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/three.txt.n+2.out: -------------------------------------------------------------------------------- 1 | lines, 2 | four words. 3 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/two.txt.c+0.out: -------------------------------------------------------------------------------- 1 | Two lines. 2 | Four words. 3 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/two.txt.c+1.out: -------------------------------------------------------------------------------- 1 | Two lines. 2 | Four words. 3 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/two.txt.c+2.out: -------------------------------------------------------------------------------- 1 | wo lines. 2 | Four words. 3 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/two.txt.c200.out: -------------------------------------------------------------------------------- 1 | Two lines. 2 | Four words. 3 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/two.txt.n+0.out: -------------------------------------------------------------------------------- 1 | Two lines. 2 | Four words. 3 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/two.txt.n+1.out: -------------------------------------------------------------------------------- 1 | Two lines. 2 | Four words. 3 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/two.txt.n200.out: -------------------------------------------------------------------------------- 1 | Two lines. 2 | Four words. 3 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/two.txt.n3.out: -------------------------------------------------------------------------------- 1 | Two lines. 2 | Four words. 3 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/two.txt.n4.out: -------------------------------------------------------------------------------- 1 | Two lines. 2 | Four words. 3 | -------------------------------------------------------------------------------- /11-tailr/tests/inputs/three.txt: -------------------------------------------------------------------------------- 1 | Three 2 | lines, 3 | four words. 4 | -------------------------------------------------------------------------------- /03-catr/tests/inputs/fox.txt: -------------------------------------------------------------------------------- 1 | The quick brown fox jumps over the lazy dog. 2 | -------------------------------------------------------------------------------- /04-headr/tests/expected/three.txt.out: -------------------------------------------------------------------------------- 1 | Three 2 | lines, 3 | four words. 4 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/atlamal.txt.c.out: -------------------------------------------------------------------------------- 1 | 177 tests/inputs/atlamal.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/atlamal.txt.l.out: -------------------------------------------------------------------------------- 1 | 4 tests/inputs/atlamal.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/atlamal.txt.m.out: -------------------------------------------------------------------------------- 1 | 159 tests/inputs/atlamal.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/atlamal.txt.w.out: -------------------------------------------------------------------------------- 1 | 29 tests/inputs/atlamal.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/fox.txt.cl.out: -------------------------------------------------------------------------------- 1 | 1 48 tests/inputs/fox.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/fox.txt.ml.out: -------------------------------------------------------------------------------- 1 | 1 48 tests/inputs/fox.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/fox.txt.wc.out: -------------------------------------------------------------------------------- 1 | 9 48 tests/inputs/fox.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/fox.txt.wl.out: -------------------------------------------------------------------------------- 1 | 1 9 tests/inputs/fox.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/fox.txt.wm.out: -------------------------------------------------------------------------------- 1 | 9 48 tests/inputs/fox.txt 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/t6.txt.stdin.c.out: -------------------------------------------------------------------------------- 1 | 1 a 2 | 1 b 3 | 1 c 4 | -------------------------------------------------------------------------------- /07-findr/tests/expected/name_a.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/a 2 | tests/inputs/a/a.txt 3 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_f_name_a.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs\a\a.txt 2 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.csv.f2.dcomma.out: -------------------------------------------------------------------------------- 1 | year 2 | 1980 3 | 2012 4 | -------------------------------------------------------------------------------- /09-grepr/tests/inputs/fox.txt: -------------------------------------------------------------------------------- 1 | The quick brown fox jumps over the lazy dog. 2 | -------------------------------------------------------------------------------- /10-commr/tests/expected/file1_file2.delim.out: -------------------------------------------------------------------------------- 1 | :B 2 | a 3 | b 4 | ::c 5 | d 6 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/ten.txt.n4.out: -------------------------------------------------------------------------------- 1 | seven 2 | eight 3 | nine 4 | ten 5 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/three.txt.out: -------------------------------------------------------------------------------- 1 | Three 2 | lines, 3 | four words. 4 | -------------------------------------------------------------------------------- /14-lsr/tests/inputs/fox.txt: -------------------------------------------------------------------------------- 1 | The quick brown fox jumps over the lazy dog. 2 | -------------------------------------------------------------------------------- /03-catr/tests/expected/fox.txt.out: -------------------------------------------------------------------------------- 1 | The quick brown fox jumps over the lazy dog. 2 | -------------------------------------------------------------------------------- /04-headr/tests/expected/three.txt.n4.out: -------------------------------------------------------------------------------- 1 | Three 2 | lines, 3 | four words. 4 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/empty.txt.cl.out: -------------------------------------------------------------------------------- 1 | 0 0 tests/inputs/empty.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/empty.txt.ml.out: -------------------------------------------------------------------------------- 1 | 0 0 tests/inputs/empty.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/empty.txt.wc.out: -------------------------------------------------------------------------------- 1 | 0 0 tests/inputs/empty.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/empty.txt.wl.out: -------------------------------------------------------------------------------- 1 | 0 0 tests/inputs/empty.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/empty.txt.wm.out: -------------------------------------------------------------------------------- 1 | 0 0 tests/inputs/empty.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/fox.txt.out: -------------------------------------------------------------------------------- 1 | 1 9 48 tests/inputs/fox.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/inputs/fox.txt: -------------------------------------------------------------------------------- 1 | The quick brown fox jumps over the lazy dog. 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/skip.txt.c.out: -------------------------------------------------------------------------------- 1 | 1 a 2 | 1 3 | 1 a 4 | 1 b 5 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/three.txt.stdin.out: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | a 4 | c 5 | a 6 | d 7 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_d_path_d.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/d 2 | tests/inputs/d/e 3 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.csv.c1-8.out: -------------------------------------------------------------------------------- 1 | title,ye 2 | The Blue 3 | Les Misé 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.tsv.c1-8.out: -------------------------------------------------------------------------------- 1 | title ye 2 | The Blue 3 | Les Misé 4 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/bustle.txt.the.lowercase: -------------------------------------------------------------------------------- 1 | The sweeping up the heart, 2 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/three.txt.c+0.out: -------------------------------------------------------------------------------- 1 | Three 2 | lines, 3 | four words. 4 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/three.txt.c+1.out: -------------------------------------------------------------------------------- 1 | Three 2 | lines, 3 | four words. 4 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/three.txt.c+2.out: -------------------------------------------------------------------------------- 1 | hree 2 | lines, 3 | four words. 4 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/three.txt.c200.out: -------------------------------------------------------------------------------- 1 | Three 2 | lines, 3 | four words. 4 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/three.txt.n+0.out: -------------------------------------------------------------------------------- 1 | Three 2 | lines, 3 | four words. 4 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/three.txt.n+1.out: -------------------------------------------------------------------------------- 1 | Three 2 | lines, 3 | four words. 4 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/three.txt.n200.out: -------------------------------------------------------------------------------- 1 | Three 2 | lines, 3 | four words. 4 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/three.txt.n3.out: -------------------------------------------------------------------------------- 1 | Three 2 | lines, 3 | four words. 4 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/three.txt.n4.out: -------------------------------------------------------------------------------- 1 | Three 2 | lines, 3 | four words. 4 | -------------------------------------------------------------------------------- /12-fortuner/tests/expected/twain_cap.err: -------------------------------------------------------------------------------- 1 | (literature) 2 | % 3 | (quotes) 4 | % 5 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/atlamal.txt.cl.out: -------------------------------------------------------------------------------- 1 | 4 177 tests/inputs/atlamal.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/atlamal.txt.ml.out: -------------------------------------------------------------------------------- 1 | 4 159 tests/inputs/atlamal.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/atlamal.txt.wc.out: -------------------------------------------------------------------------------- 1 | 29 177 tests/inputs/atlamal.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/atlamal.txt.wl.out: -------------------------------------------------------------------------------- 1 | 4 29 tests/inputs/atlamal.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/atlamal.txt.wm.out: -------------------------------------------------------------------------------- 1 | 29 159 tests/inputs/atlamal.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/empty.txt.out: -------------------------------------------------------------------------------- 1 | 0 0 0 tests/inputs/empty.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/fox.txt.lwm.out: -------------------------------------------------------------------------------- 1 | 1 9 48 tests/inputs/fox.txt 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/expected/skip.txt.stdin.c.out: -------------------------------------------------------------------------------- 1 | 1 a 2 | 1 3 | 1 a 4 | 1 b 5 | -------------------------------------------------------------------------------- /07-findr/tests/expected/name_a.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs\a 2 | tests/inputs\a\a.txt 3 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_d_path_a_b.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/a/b 2 | tests/inputs/a/b/c 3 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.tsv.f3.out: -------------------------------------------------------------------------------- 1 | director 2 | John Landis 3 | Tom Hooper 4 | -------------------------------------------------------------------------------- /12-fortuner/tests/expected/twain_lower_i.err: -------------------------------------------------------------------------------- 1 | (literature) 2 | % 3 | (quotes) 4 | % 5 | -------------------------------------------------------------------------------- /03-catr/tests/expected/fox.txt.b.out: -------------------------------------------------------------------------------- 1 | 1 The quick brown fox jumps over the lazy dog. 2 | -------------------------------------------------------------------------------- /03-catr/tests/expected/fox.txt.n.out: -------------------------------------------------------------------------------- 1 | 1 The quick brown fox jumps over the lazy dog. 2 | -------------------------------------------------------------------------------- /03-catr/tests/inputs/spiders.txt: -------------------------------------------------------------------------------- 1 | Don't worry, spiders, 2 | I keep house 3 | casually. 4 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/atlamal.txt.out: -------------------------------------------------------------------------------- 1 | 4 29 177 tests/inputs/atlamal.txt 2 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/empty.txt.lwm.out: -------------------------------------------------------------------------------- 1 | 0 0 0 tests/inputs/empty.txt 2 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_d_path_d.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs/d 2 | tests/inputs/d\e 3 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.csv.f3.dcomma.out: -------------------------------------------------------------------------------- 1 | director 2 | John Landis 3 | Tom Hooper 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.tsv.f1.out: -------------------------------------------------------------------------------- 1 | title 2 | The Blues Brothers 3 | Les Misérables 4 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/empty_regex.fox.txt: -------------------------------------------------------------------------------- 1 | The quick brown fox jumps over the lazy dog. 2 | -------------------------------------------------------------------------------- /14-lsr/tests/inputs/dir/spiders.txt: -------------------------------------------------------------------------------- 1 | Don't worry, spiders, 2 | I keep house 3 | casually. 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # learn_system_programming_in_rust 2 | 《Command-Line Rust》学习笔记,pdf为每章的学习笔记,代码见各目录 -------------------------------------------------------------------------------- /03-catr/tests/expected/spiders.txt.out: -------------------------------------------------------------------------------- 1 | Don't worry, spiders, 2 | I keep house 3 | casually. 4 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/atlamal.txt.lwm.out: -------------------------------------------------------------------------------- 1 | 4 29 159 tests/inputs/atlamal.txt 2 | -------------------------------------------------------------------------------- /07-findr/tests/expected/name_txt_path_a_d.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/a/a.txt 2 | tests/inputs/d/d.txt 3 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_d_path_a_b.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs/a/b 2 | tests/inputs/a/b\c 3 | -------------------------------------------------------------------------------- /03-catr.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/03-catr.pdf -------------------------------------------------------------------------------- /05-wcr.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/05-wcr.pdf -------------------------------------------------------------------------------- /07-findr/tests/expected/name_txt_path_a_d.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs/a\a.txt 2 | tests/inputs/d\d.txt 3 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_f_path_a_b.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/a/b/b.csv 2 | tests/inputs/a/b/c/c.mp3 3 | -------------------------------------------------------------------------------- /08-cutr.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/08-cutr.pdf -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.csv.f1.dcomma.out: -------------------------------------------------------------------------------- 1 | title 2 | The Blues Brothers 3 | Les Misérables 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.tsv.f2-3.out: -------------------------------------------------------------------------------- 1 | year director 2 | 1980 John Landis 3 | 2019 Tom Hooper 4 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/nobody.txt.insensitive: -------------------------------------------------------------------------------- 1 | I'm Nobody! Who are you? 2 | Are you—Nobody—too? 3 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/all.n1.q.out: -------------------------------------------------------------------------------- 1 | ten 2 | Öne line, four wordś. 3 | four words. 4 | Four words. 5 | -------------------------------------------------------------------------------- /13-calr.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/13-calr.pdf -------------------------------------------------------------------------------- /14-lsr.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/14-lsr.pdf -------------------------------------------------------------------------------- /02-echor.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/02-echor.pdf -------------------------------------------------------------------------------- /04-headr.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/04-headr.pdf -------------------------------------------------------------------------------- /06-uniqr.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/06-uniqr.pdf -------------------------------------------------------------------------------- /06-uniqr/tests/expected/three.txt.c.out: -------------------------------------------------------------------------------- 1 | 2 a 2 | 2 b 3 | 1 a 4 | 3 c 5 | 1 a 6 | 4 d 7 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_d_path_a.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/a 2 | tests/inputs/a/b 3 | tests/inputs/a/b/c 4 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_f_path_a_b.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs/a/b\b.csv 2 | tests/inputs/a/b\c\c.mp3 3 | -------------------------------------------------------------------------------- /09-grepr.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/09-grepr.pdf -------------------------------------------------------------------------------- /09-grepr/tests/expected/dog.recursive: -------------------------------------------------------------------------------- 1 | tests/inputs/fox.txt:The quick brown fox jumps over the lazy dog. 2 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/the.recursive.insensitive: -------------------------------------------------------------------------------- 1 | tests/inputs/nobody.txt:Then there's a pair of us! 2 | -------------------------------------------------------------------------------- /10-commr.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/10-commr.pdf -------------------------------------------------------------------------------- /10-commr/tests/inputs/cities1.txt: -------------------------------------------------------------------------------- 1 | Jackson 2 | Denton 3 | Cincinnati 4 | Boston 5 | Santa Fe 6 | Tucson 7 | -------------------------------------------------------------------------------- /11-tailr.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/11-tailr.pdf -------------------------------------------------------------------------------- /06-uniqr/tests/expected/three.txt.stdin.c.out: -------------------------------------------------------------------------------- 1 | 2 a 2 | 2 b 3 | 1 a 4 | 3 c 5 | 1 a 6 | 4 d 7 | -------------------------------------------------------------------------------- /07-findr/tests/expected/name_csv.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/a/b/b.csv 2 | tests/inputs/d/b.csv 3 | tests/inputs/g.csv 4 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_d_path_a.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs/a 2 | tests/inputs/a\b 3 | tests/inputs/a\b\c 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.csv.f2-3.dcomma.out: -------------------------------------------------------------------------------- 1 | year,director 2 | 1980,John Landis 3 | 2012,Tom Hooper 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.tsv.f1-2.out: -------------------------------------------------------------------------------- 1 | title year 2 | The Blues Brothers 1980 3 | Les Misérables 2019 4 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/the.recursive.insensitive.windows: -------------------------------------------------------------------------------- 1 | tests/inputs\nobody.txt:Then there's a pair of us! 2 | -------------------------------------------------------------------------------- /10-commr/tests/inputs/cities1_lower.txt: -------------------------------------------------------------------------------- 1 | jackson 2 | denton 3 | cincinnati 4 | boston 5 | santa fe 6 | tucson 7 | -------------------------------------------------------------------------------- /10-commr/tests/inputs/cities2.txt: -------------------------------------------------------------------------------- 1 | San Francisco 2 | Denver 3 | Ypsilanti 4 | Denton 5 | Cincinnati 6 | Boston 7 | -------------------------------------------------------------------------------- /12-fortuner.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/12-fortuner.pdf -------------------------------------------------------------------------------- /03-catr/tests/expected/spiders.txt.b.out: -------------------------------------------------------------------------------- 1 | 1 Don't worry, spiders, 2 | 2 I keep house 3 | 3 casually. 4 | -------------------------------------------------------------------------------- /03-catr/tests/expected/spiders.txt.n.out: -------------------------------------------------------------------------------- 1 | 1 Don't worry, spiders, 2 | 2 I keep house 3 | 3 casually. 4 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_f_path_d.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/d/d.tsv 2 | tests/inputs/d/d.txt 3 | tests/inputs/d/e/e.mp3 4 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.csv.f1-2.dcomma.out: -------------------------------------------------------------------------------- 1 | title,year 2 | The Blues Brothers,1980 3 | Les Misérables,2012 4 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/dog.recursive.windows: -------------------------------------------------------------------------------- 1 | tests/inputs\fox.txt:The quick brown fox jumps over the lazy dog. 2 | -------------------------------------------------------------------------------- /06-uniqr/tests/inputs/three.txt: -------------------------------------------------------------------------------- 1 | a 2 | a 3 | b 4 | b 5 | a 6 | c 7 | c 8 | c 9 | a 10 | d 11 | d 12 | d 13 | d 14 | -------------------------------------------------------------------------------- /07-findr/tests/expected/name_csv.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs\a\b\b.csv 2 | tests/inputs\d\b.csv 3 | tests/inputs\g.csv 4 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_f_path_a.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/a/a.txt 2 | tests/inputs/a/b/b.csv 3 | tests/inputs/a/b/c/c.mp3 4 | -------------------------------------------------------------------------------- /10-commr/tests/inputs/cities2_upper.txt: -------------------------------------------------------------------------------- 1 | SAN FRANCISCO 2 | DENVER 3 | YPSILANTI 4 | DENTON 5 | CINCINNATI 6 | BOSTON 7 | -------------------------------------------------------------------------------- /04-headr/tests/inputs/ten.txt: -------------------------------------------------------------------------------- 1 | one 2 | two 3 | three 4 | four 5 | five 6 | six 7 | seven 8 | eight 9 | nine 10 | ten 11 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_d_path_a_b_d.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/a/b 2 | tests/inputs/a/b/c 3 | tests/inputs/d 4 | tests/inputs/d/e 5 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_f_path_a.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs/a\a.txt 2 | tests/inputs/a\b\b.csv 3 | tests/inputs/a\b\c\c.mp3 4 | -------------------------------------------------------------------------------- /08-cutr/tests/inputs/movies1.csv: -------------------------------------------------------------------------------- 1 | title,year,director 2 | The Blues Brothers,1980,John Landis 3 | Les Misérables,2012,Tom Hooper 4 | -------------------------------------------------------------------------------- /08-cutr/tests/inputs/movies1.tsv: -------------------------------------------------------------------------------- 1 | title year director 2 | The Blues Brothers 1980 John Landis 3 | Les Misérables 2019 Tom Hooper 4 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/ten.txt.n+2.out: -------------------------------------------------------------------------------- 1 | two 2 | three 3 | four 4 | five 5 | six 6 | seven 7 | eight 8 | nine 9 | ten 10 | -------------------------------------------------------------------------------- /11-tailr/tests/inputs/ten.txt: -------------------------------------------------------------------------------- 1 | one 2 | two 3 | three 4 | four 5 | five 6 | six 7 | seven 8 | eight 9 | nine 10 | ten 11 | -------------------------------------------------------------------------------- /04-headr/tests/expected/ten.txt.out: -------------------------------------------------------------------------------- 1 | one 2 | two 3 | three 4 | four 5 | five 6 | six 7 | seven 8 | eight 9 | nine 10 | ten 11 | -------------------------------------------------------------------------------- /07-findr/tests/expected/path_a_b.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/a/b 2 | tests/inputs/a/b/b.csv 3 | tests/inputs/a/b/c 4 | tests/inputs/a/b/c/c.mp3 5 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_d_path_a_b_d.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs/a/b 2 | tests/inputs/a/b\c 3 | tests/inputs/d 4 | tests/inputs/d\e 5 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/bustle.txt.the.capitalized: -------------------------------------------------------------------------------- 1 | The bustle in a house 2 | The morning after death 3 | The sweeping up the heart, 4 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/all.n+3.q.out: -------------------------------------------------------------------------------- 1 | three 2 | four 3 | five 4 | six 5 | seven 6 | eight 7 | nine 8 | ten 9 | four words. 10 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/ten.txt.c+2.out: -------------------------------------------------------------------------------- 1 | ne 2 | two 3 | three 4 | four 5 | five 6 | six 7 | seven 8 | eight 9 | nine 10 | ten 11 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/ten.txt.out: -------------------------------------------------------------------------------- 1 | one 2 | two 3 | three 4 | four 5 | five 6 | six 7 | seven 8 | eight 9 | nine 10 | ten 11 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.tsv.f1-3.out: -------------------------------------------------------------------------------- 1 | title year director 2 | The Blues Brothers 1980 John Landis 3 | Les Misérables 2019 Tom Hooper 4 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/ten.txt.c+0.out: -------------------------------------------------------------------------------- 1 | one 2 | two 3 | three 4 | four 5 | five 6 | six 7 | seven 8 | eight 9 | nine 10 | ten 11 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/ten.txt.c+1.out: -------------------------------------------------------------------------------- 1 | one 2 | two 3 | three 4 | four 5 | five 6 | six 7 | seven 8 | eight 9 | nine 10 | ten 11 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/ten.txt.c200.out: -------------------------------------------------------------------------------- 1 | one 2 | two 3 | three 4 | four 5 | five 6 | six 7 | seven 8 | eight 9 | nine 10 | ten 11 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/ten.txt.n+0.out: -------------------------------------------------------------------------------- 1 | one 2 | two 3 | three 4 | four 5 | five 6 | six 7 | seven 8 | eight 9 | nine 10 | ten 11 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/ten.txt.n+1.out: -------------------------------------------------------------------------------- 1 | one 2 | two 3 | three 4 | four 5 | five 6 | six 7 | seven 8 | eight 9 | nine 10 | ten 11 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/ten.txt.n200.out: -------------------------------------------------------------------------------- 1 | one 2 | two 3 | three 4 | four 5 | five 6 | six 7 | seven 8 | eight 9 | nine 10 | ten 11 | -------------------------------------------------------------------------------- /04-headr/tests/expected/all.c1.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/04-headr/tests/expected/all.c1.out -------------------------------------------------------------------------------- /07-findr/tests/expected/path_a_b.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs/a/b 2 | tests/inputs/a/b\b.csv 3 | tests/inputs/a/b\c 4 | tests/inputs/a/b\c\c.mp3 5 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/bustle.txt.the.lowercase.insensistive: -------------------------------------------------------------------------------- 1 | The bustle in a house 2 | The morning after death 3 | The sweeping up the heart, 4 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/bustle.txt.the.lowercase.insensitive: -------------------------------------------------------------------------------- 1 | The bustle in a house 2 | The morning after death 3 | The sweeping up the heart, 4 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/all.c3.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/11-tailr/tests/expected/all.c3.out -------------------------------------------------------------------------------- /12-fortuner/tests/inputs/jokes.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/12-fortuner/tests/inputs/jokes.dat -------------------------------------------------------------------------------- /07-findr/tests/expected/type_f_path_d.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs/d\b.csv 2 | tests/inputs/d\d.tsv 3 | tests/inputs/d\d.txt 4 | tests/inputs/d\e\e.mp3 5 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.csv.f1-3.dcomma.out: -------------------------------------------------------------------------------- 1 | title,year,director 2 | The Blues Brothers,1980,John Landis 3 | Les Misérables,2012,Tom Hooper 4 | -------------------------------------------------------------------------------- /12-fortuner/tests/inputs/quotes.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/12-fortuner/tests/inputs/quotes.dat -------------------------------------------------------------------------------- /04-headr/tests/expected/one.txt.c1.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/04-headr/tests/expected/one.txt.c1.out -------------------------------------------------------------------------------- /05-wcr/tests/expected/all.c.out: -------------------------------------------------------------------------------- 1 | 0 tests/inputs/empty.txt 2 | 48 tests/inputs/fox.txt 3 | 177 tests/inputs/atlamal.txt 4 | 225 total 5 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/all.l.out: -------------------------------------------------------------------------------- 1 | 0 tests/inputs/empty.txt 2 | 1 tests/inputs/fox.txt 3 | 4 tests/inputs/atlamal.txt 4 | 5 total 5 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/all.m.out: -------------------------------------------------------------------------------- 1 | 0 tests/inputs/empty.txt 2 | 48 tests/inputs/fox.txt 3 | 159 tests/inputs/atlamal.txt 4 | 207 total 5 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/all.w.out: -------------------------------------------------------------------------------- 1 | 0 tests/inputs/empty.txt 2 | 9 tests/inputs/fox.txt 3 | 29 tests/inputs/atlamal.txt 4 | 38 total 5 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/one.txt.c+2.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/11-tailr/tests/expected/one.txt.c+2.out -------------------------------------------------------------------------------- /11-tailr/tests/expected/one.txt.c3.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/11-tailr/tests/expected/one.txt.c3.out -------------------------------------------------------------------------------- /12-fortuner/tests/inputs/ascii-art.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/12-fortuner/tests/inputs/ascii-art.dat -------------------------------------------------------------------------------- /12-fortuner/tests/inputs/literature.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/12-fortuner/tests/inputs/literature.dat -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.csv.b8.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/08-cutr/tests/expected/movies1.csv.b8.out -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.tsv.b8.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/08-cutr/tests/expected/movies1.tsv.b8.out -------------------------------------------------------------------------------- /08-cutr/tests/inputs/movies2.tsv: -------------------------------------------------------------------------------- 1 | title year 2 | The Blues Brothers 1980 John Landis 3 | Les Misérables 2019 Tom Hooper 4 | To Sir, with Love 1967 James Clavell 5 | -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.csv.b1-8.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/08-cutr/tests/expected/movies1.csv.b1-8.out -------------------------------------------------------------------------------- /08-cutr/tests/expected/movies1.tsv.b1-8.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liu-jianhao/learn_system_programming_in_rust/HEAD/08-cutr/tests/expected/movies1.tsv.b1-8.out -------------------------------------------------------------------------------- /09-grepr/tests/expected/all.the.capitalized.count: -------------------------------------------------------------------------------- 1 | tests/inputs/bustle.txt:3 2 | tests/inputs/empty.txt:0 3 | tests/inputs/fox.txt:1 4 | tests/inputs/nobody.txt:1 5 | -------------------------------------------------------------------------------- /07-findr/tests/expected/name_csv_mp3.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/a/b/b.csv 2 | tests/inputs/a/b/c/c.mp3 3 | tests/inputs/d/b.csv 4 | tests/inputs/d/e/e.mp3 5 | tests/inputs/g.csv 6 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_d.txt: -------------------------------------------------------------------------------- 1 | tests/inputs 2 | tests/inputs/a 3 | tests/inputs/a/b 4 | tests/inputs/a/b/c 5 | tests/inputs/d 6 | tests/inputs/d/e 7 | tests/inputs/f 8 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/the.recursive.insensitive.count: -------------------------------------------------------------------------------- 1 | tests/inputs/empty.txt:0 2 | tests/inputs/fox.txt:1 3 | tests/inputs/bustle.txt:3 4 | tests/inputs/nobody.txt:3 5 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/all.n3.q.out: -------------------------------------------------------------------------------- 1 | eight 2 | nine 3 | ten 4 | Öne line, four wordś. 5 | Three 6 | lines, 7 | four words. 8 | Two lines. 9 | Four words. 10 | -------------------------------------------------------------------------------- /12-fortuner/tests/expected/berra_cap.out: -------------------------------------------------------------------------------- 1 | It's like deja vu all over again. 2 | -- Yogi Berra 3 | % 4 | You can observe a lot just by watching. 5 | -- Yogi Berra 6 | % 7 | -------------------------------------------------------------------------------- /05-wcr/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if let Err(e) = wcr::get_args().and_then(wcr::run) { 3 | eprintln!("{}", e); 4 | std::process::exit(1); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /07-findr/tests/expected/path_a.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/a 2 | tests/inputs/a/a.txt 3 | tests/inputs/a/b 4 | tests/inputs/a/b/b.csv 5 | tests/inputs/a/b/c 6 | tests/inputs/a/b/c/c.mp3 7 | -------------------------------------------------------------------------------- /07-findr/tests/expected/path_d.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/d 2 | tests/inputs/d/b.csv 3 | tests/inputs/d/d.tsv 4 | tests/inputs/d/d.txt 5 | tests/inputs/d/e 6 | tests/inputs/d/e/e.mp3 7 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_f_path_a_b_d.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/a/b/b.csv 2 | tests/inputs/a/b/c/c.mp3 3 | tests/inputs/d/d.tsv 4 | tests/inputs/d/d.txt 5 | tests/inputs/d/e/e.mp3 6 | -------------------------------------------------------------------------------- /08-cutr/tests/inputs/movies2.csv: -------------------------------------------------------------------------------- 1 | title,year,director 2 | The Blues Brothers,1980,John Landis 3 | Les Misérables,2012,Tom Hooper 4 | "To Sir, with Love",1967,James Clavell 5 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/all.the.lowercase.insensitive.count: -------------------------------------------------------------------------------- 1 | tests/inputs/bustle.txt:3 2 | tests/inputs/empty.txt:0 3 | tests/inputs/fox.txt:1 4 | tests/inputs/nobody.txt:3 5 | -------------------------------------------------------------------------------- /12-fortuner/tests/expected/berra_lower_i.out: -------------------------------------------------------------------------------- 1 | It's like deja vu all over again. 2 | -- Yogi Berra 3 | % 4 | You can observe a lot just by watching. 5 | -- Yogi Berra 6 | % 7 | -------------------------------------------------------------------------------- /14-lsr/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if let Err(e) = lsr::get_args().and_then(lsr::run) { 3 | eprintln!("{}", e); 4 | std::process::exit(1); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /03-catr/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if let Err(e) = catr::get_args().and_then(catr::run) { 3 | eprintln!("{}", e); 4 | std::process::exit(1); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /07-findr/tests/expected/name_csv_mp3.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs\a\b\b.csv 2 | tests/inputs\a\b\c\c.mp3 3 | tests/inputs\d\b.csv 4 | tests/inputs\d\e\e.mp3 5 | tests/inputs\g.csv 6 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_d.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs 2 | tests/inputs\a 3 | tests/inputs\a\b 4 | tests/inputs\a\b\c 5 | tests/inputs\d 6 | tests/inputs\d\e 7 | tests/inputs\f 8 | -------------------------------------------------------------------------------- /08-cutr/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if let Err(e) = cutr::get_args().and_then(cutr::run) { 3 | eprintln!("{}", e); 4 | std::process::exit(1); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /13-calr/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if let Err(e) = calr::get_args().and_then(calr::run) { 3 | eprintln!("{}", e); 4 | std::process::exit(1); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /04-headr/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if let Err(e) = headr::get_args().and_then(headr::run) { 3 | eprintln!("{}", e); 4 | std::process::exit(1); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /07-findr/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if let Err(e) = findr::get_args().and_then(findr::run) { 3 | eprintln!("{}", e); 4 | std::process::exit(1); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /07-findr/tests/expected/path_a.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs/a 2 | tests/inputs/a\a.txt 3 | tests/inputs/a\b 4 | tests/inputs/a\b\b.csv 5 | tests/inputs/a\b\c 6 | tests/inputs/a\b\c\c.mp3 7 | -------------------------------------------------------------------------------- /07-findr/tests/expected/path_d.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs/d 2 | tests/inputs/d\b.csv 3 | tests/inputs/d\d.tsv 4 | tests/inputs/d\d.txt 5 | tests/inputs/d\e 6 | tests/inputs/d\e\e.mp3 7 | -------------------------------------------------------------------------------- /08-cutr/tests/inputs/books.tsv: -------------------------------------------------------------------------------- 1 | Author Year Title 2 | Émile Zola 1865 La Confession de Claude 3 | Samuel Beckett 1952 Waiting for Godot 4 | Jules Verne 1870 20,000 Leagues Under the Sea 5 | -------------------------------------------------------------------------------- /09-grepr/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if let Err(e) = grepr::get_args().and_then(grepr::run) { 3 | eprintln!("{}", e); 4 | std::process::exit(1); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /10-commr/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if let Err(e) = commr::get_args().and_then(commr::run) { 3 | eprintln!("{}", e); 4 | std::process::exit(1); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /11-tailr/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if let Err(e) = tailr::get_args().and_then(tailr::run) { 3 | eprintln!("{}", e); 4 | std::process::exit(1); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/all.cl.out: -------------------------------------------------------------------------------- 1 | 0 0 tests/inputs/empty.txt 2 | 1 48 tests/inputs/fox.txt 3 | 4 177 tests/inputs/atlamal.txt 4 | 5 225 total 5 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/all.ml.out: -------------------------------------------------------------------------------- 1 | 0 0 tests/inputs/empty.txt 2 | 1 48 tests/inputs/fox.txt 3 | 4 159 tests/inputs/atlamal.txt 4 | 5 207 total 5 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/all.wc.out: -------------------------------------------------------------------------------- 1 | 0 0 tests/inputs/empty.txt 2 | 9 48 tests/inputs/fox.txt 3 | 29 177 tests/inputs/atlamal.txt 4 | 38 225 total 5 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/all.wl.out: -------------------------------------------------------------------------------- 1 | 0 0 tests/inputs/empty.txt 2 | 1 9 tests/inputs/fox.txt 3 | 4 29 tests/inputs/atlamal.txt 4 | 5 38 total 5 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/all.wm.out: -------------------------------------------------------------------------------- 1 | 0 0 tests/inputs/empty.txt 2 | 9 48 tests/inputs/fox.txt 3 | 29 159 tests/inputs/atlamal.txt 4 | 38 207 total 5 | -------------------------------------------------------------------------------- /08-cutr/tests/inputs/books.csv: -------------------------------------------------------------------------------- 1 | Author,Year,Title 2 | Émile Zola,1865,La Confession de Claude 3 | Samuel Beckett,1952,Waiting for Godot 4 | Jules Verne,1870,"20,000 Leagues Under the Sea" 5 | -------------------------------------------------------------------------------- /12-fortuner/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if let Err(e) = fortuner::get_args().and_then(fortuner::run) { 3 | eprintln!("{}", e); 4 | std::process::exit(1); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /06-uniqr/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if let Err(e) = uniqr::get_args().and_then(uniqr::run) { 3 | eprintln!("{}", e); 4 | std::process::exit(1); 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /05-wcr/tests/inputs/atlamal.txt: -------------------------------------------------------------------------------- 1 | Frétt hefir öld óvu, þá er endr of gerðu 2 | seggir samkundu, sú var nýt fæstum, 3 | æxtu einmæli, yggr var þeim síðan 4 | ok it sama sonum Gjúka, er váru sannráðnir. 5 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_f_path_a_b_d.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs/a/b\b.csv 2 | tests/inputs/a/b\c\c.mp3 3 | tests/inputs/d\b.csv 4 | tests/inputs/d\d.tsv 5 | tests/inputs/d\d.txt 6 | tests/inputs/d\e\e.mp3 7 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/all.out: -------------------------------------------------------------------------------- 1 | 0 0 0 tests/inputs/empty.txt 2 | 1 9 48 tests/inputs/fox.txt 3 | 4 29 177 tests/inputs/atlamal.txt 4 | 5 38 225 total 5 | -------------------------------------------------------------------------------- /05-wcr/tests/expected/all.lwm.out: -------------------------------------------------------------------------------- 1 | 0 0 0 tests/inputs/empty.txt 2 | 1 9 48 tests/inputs/fox.txt 3 | 4 29 159 tests/inputs/atlamal.txt 4 | 5 38 207 total 5 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/all.c0.out: -------------------------------------------------------------------------------- 1 | ==> tests/inputs/ten.txt <== 2 | 3 | ==> tests/inputs/empty.txt <== 4 | 5 | ==> tests/inputs/one.txt <== 6 | 7 | ==> tests/inputs/three.txt <== 8 | 9 | ==> tests/inputs/two.txt <== 10 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/all.n0.out: -------------------------------------------------------------------------------- 1 | ==> tests/inputs/ten.txt <== 2 | 3 | ==> tests/inputs/empty.txt <== 4 | 5 | ==> tests/inputs/one.txt <== 6 | 7 | ==> tests/inputs/three.txt <== 8 | 9 | ==> tests/inputs/two.txt <== 10 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_f.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/a/a.txt 2 | tests/inputs/a/b/b.csv 3 | tests/inputs/a/b/c/c.mp3 4 | tests/inputs/d/d.tsv 5 | tests/inputs/d/d.txt 6 | tests/inputs/d/e/e.mp3 7 | tests/inputs/f/f.txt 8 | tests/inputs/g.csv 9 | -------------------------------------------------------------------------------- /04-headr/tests/expected/all.c2.out: -------------------------------------------------------------------------------- 1 | ==> ./tests/inputs/empty.txt <== 2 | 3 | ==> ./tests/inputs/one.txt <== 4 | Ö 5 | ==> ./tests/inputs/two.txt <== 6 | Tw 7 | ==> ./tests/inputs/three.txt <== 8 | Th 9 | ==> ./tests/inputs/ten.txt <== 10 | on -------------------------------------------------------------------------------- /13-calr/tests/expected/2-2020.txt: -------------------------------------------------------------------------------- 1 | February 2020 2 | Su Mo Tu We Th Fr Sa 3 | 1 4 | 2 3 4 5 6 7 8 5 | 9 10 11 12 13 14 15 6 | 16 17 18 19 20 21 22 7 | 23 24 25 26 27 28 29 8 | 9 | -------------------------------------------------------------------------------- /13-calr/tests/expected/4-2020.txt: -------------------------------------------------------------------------------- 1 | April 2020 2 | Su Mo Tu We Th Fr Sa 3 | 1 2 3 4 4 | 5 6 7 8 9 10 11 5 | 12 13 14 15 16 17 18 6 | 19 20 21 22 23 24 25 7 | 26 27 28 29 30 8 | 9 | -------------------------------------------------------------------------------- /13-calr/tests/expected/5-2020.txt: -------------------------------------------------------------------------------- 1 | May 2020 2 | Su Mo Tu We Th Fr Sa 3 | 1 2 4 | 3 4 5 6 7 8 9 5 | 10 11 12 13 14 15 16 6 | 17 18 19 20 21 22 23 7 | 24 25 26 27 28 29 30 8 | 31 9 | -------------------------------------------------------------------------------- /04-headr/tests/expected/all.c4.out: -------------------------------------------------------------------------------- 1 | ==> ./tests/inputs/empty.txt <== 2 | 3 | ==> ./tests/inputs/one.txt <== 4 | Öne 5 | ==> ./tests/inputs/two.txt <== 6 | Two 7 | ==> ./tests/inputs/three.txt <== 8 | Thre 9 | ==> ./tests/inputs/ten.txt <== 10 | one 11 | -------------------------------------------------------------------------------- /14-lsr/tests/inputs/bustle.txt: -------------------------------------------------------------------------------- 1 | The bustle in a house 2 | The morning after death 3 | Is solemnest of industries 4 | Enacted upon earth,— 5 | 6 | The sweeping up the heart, 7 | And putting love away 8 | We shall not want to use again 9 | Until eternity. 10 | -------------------------------------------------------------------------------- /03-catr/tests/inputs/the-bustle.txt: -------------------------------------------------------------------------------- 1 | The bustle in a house 2 | The morning after death 3 | Is solemnest of industries 4 | Enacted upon earth,— 5 | 6 | The sweeping up the heart, 7 | And putting love away 8 | We shall not want to use again 9 | Until eternity. 10 | -------------------------------------------------------------------------------- /08-cutr/tests/inputs/books.txt: -------------------------------------------------------------------------------- 1 | Author Year Title 2 | Émile Zola 1865 La Confession de Claude 3 | Samuel Beckett 1952 Waiting for Godot 4 | Jules Verne 1870 20,000 Leagues Under the Sea 5 | -------------------------------------------------------------------------------- /09-grepr/tests/inputs/bustle.txt: -------------------------------------------------------------------------------- 1 | The bustle in a house 2 | The morning after death 3 | Is solemnest of industries 4 | Enacted upon earth,— 5 | 6 | The sweeping up the heart, 7 | And putting love away 8 | We shall not want to use again 9 | Until eternity. 10 | -------------------------------------------------------------------------------- /03-catr/tests/expected/the-bustle.txt.out: -------------------------------------------------------------------------------- 1 | The bustle in a house 2 | The morning after death 3 | Is solemnest of industries 4 | Enacted upon earth,— 5 | 6 | The sweeping up the heart, 7 | And putting love away 8 | We shall not want to use again 9 | Until eternity. 10 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_f_l.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/a/a.txt 2 | tests/inputs/a/b/b.csv 3 | tests/inputs/a/b/c/c.mp3 4 | tests/inputs/d/b.csv 5 | tests/inputs/d/d.tsv 6 | tests/inputs/d/d.txt 7 | tests/inputs/d/e/e.mp3 8 | tests/inputs/f/f.txt 9 | tests/inputs/g.csv 10 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_f.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs\a\a.txt 2 | tests/inputs\a\b\b.csv 3 | tests/inputs\a\b\c\c.mp3 4 | tests/inputs\d\b.csv 5 | tests/inputs\d\d.tsv 6 | tests/inputs\d\d.txt 7 | tests/inputs\d\e\e.mp3 8 | tests/inputs\f\f.txt 9 | tests/inputs\g.csv 10 | -------------------------------------------------------------------------------- /03-catr/tests/expected/the-bustle.txt.stdin.out: -------------------------------------------------------------------------------- 1 | The bustle in a house 2 | The morning after death 3 | Is solemnest of industries 4 | Enacted upon earth,— 5 | 6 | The sweeping up the heart, 7 | And putting love away 8 | We shall not want to use again 9 | Until eternity. 10 | -------------------------------------------------------------------------------- /07-findr/tests/expected/type_f_l.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs\a\a.txt 2 | tests/inputs\a\b\b.csv 3 | tests/inputs\a\b\c\c.mp3 4 | tests/inputs\d\b.csv 5 | tests/inputs\d\d.tsv 6 | tests/inputs\d\d.txt 7 | tests/inputs\d\e\e.mp3 8 | tests/inputs\f\f.txt 9 | tests/inputs\g.csv 10 | -------------------------------------------------------------------------------- /07-findr/tests/expected/path_a_b_d.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/a/b 2 | tests/inputs/a/b/b.csv 3 | tests/inputs/a/b/c 4 | tests/inputs/a/b/c/c.mp3 5 | tests/inputs/d 6 | tests/inputs/d/b.csv 7 | tests/inputs/d/d.tsv 8 | tests/inputs/d/d.txt 9 | tests/inputs/d/e 10 | tests/inputs/d/e/e.mp3 11 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/all.c8.out: -------------------------------------------------------------------------------- 1 | ==> tests/inputs/ten.txt <== 2 | ine 3 | ten 4 | 5 | ==> tests/inputs/empty.txt <== 6 | 7 | ==> tests/inputs/one.txt <== 8 | wordś. 9 | 10 | ==> tests/inputs/three.txt <== 11 | words. 12 | 13 | ==> tests/inputs/two.txt <== 14 | words. 15 | -------------------------------------------------------------------------------- /12-fortuner/mk-dat.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | DIR="./tests/inputs" 4 | cd $DIR 5 | rm -f *.dat 6 | 7 | for FILE in *; do 8 | if [[ -f $FILE ]]; then 9 | echo $FILE 10 | strfile -c % $FILE $FILE.dat > /dev/null 11 | fi 12 | done 13 | 14 | echo "Done." 15 | -------------------------------------------------------------------------------- /07-findr/tests/expected/path_a_b_d.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs/a/b 2 | tests/inputs/a/b\b.csv 3 | tests/inputs/a/b\c 4 | tests/inputs/a/b\c\c.mp3 5 | tests/inputs/d 6 | tests/inputs/d\b.csv 7 | tests/inputs/d\d.tsv 8 | tests/inputs/d\d.txt 9 | tests/inputs/d\e 10 | tests/inputs/d\e\e.mp3 11 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/all.n1.out: -------------------------------------------------------------------------------- 1 | ==> tests/inputs/ten.txt <== 2 | ten 3 | 4 | ==> tests/inputs/empty.txt <== 5 | 6 | ==> tests/inputs/one.txt <== 7 | Öne line, four wordś. 8 | 9 | ==> tests/inputs/three.txt <== 10 | four words. 11 | 12 | ==> tests/inputs/two.txt <== 13 | Four words. 14 | -------------------------------------------------------------------------------- /09-grepr/tests/inputs/nobody.txt: -------------------------------------------------------------------------------- 1 | I'm Nobody! Who are you? 2 | Are you—Nobody—too? 3 | Then there's a pair of us! 4 | Don't tell! they'd advertise—you know! 5 | 6 | How dreary—to be—Somebody! 7 | How public—like a Frog— 8 | To tell one's name—the livelong June— 9 | To an admiring Bog! 10 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/all.c12.out: -------------------------------------------------------------------------------- 1 | ==> tests/inputs/ten.txt <== 2 | ht 3 | nine 4 | ten 5 | 6 | ==> tests/inputs/empty.txt <== 7 | 8 | ==> tests/inputs/one.txt <== 9 | our wordś. 10 | 11 | ==> tests/inputs/three.txt <== 12 | four words. 13 | 14 | ==> tests/inputs/two.txt <== 15 | Four words. 16 | -------------------------------------------------------------------------------- /02-echor/mk-outs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bin/env bash 2 | 3 | OUTDIR="tests/expected" 4 | [[ ! -d "$OUTDIR" ]] && mkdir -p "$OUTDIR" 5 | 6 | echo "Hello there" > $OUTDIR/hello1.txt 7 | echo "Hello" "there" > $OUTDIR/hello2.txt 8 | echo -n "Hello there" > $OUTDIR/hello1.n.txt 9 | echo -n "Hello" "there" > $OUTDIR/hello2.n.txt -------------------------------------------------------------------------------- /09-grepr/tests/expected/all.the.capitalized: -------------------------------------------------------------------------------- 1 | tests/inputs/bustle.txt:The bustle in a house 2 | tests/inputs/bustle.txt:The morning after death 3 | tests/inputs/bustle.txt:The sweeping up the heart, 4 | tests/inputs/fox.txt:The quick brown fox jumps over the lazy dog. 5 | tests/inputs/nobody.txt:Then there's a pair of us! 6 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/all.n+3.out: -------------------------------------------------------------------------------- 1 | ==> tests/inputs/ten.txt <== 2 | three 3 | four 4 | five 5 | six 6 | seven 7 | eight 8 | nine 9 | ten 10 | 11 | ==> tests/inputs/empty.txt <== 12 | 13 | ==> tests/inputs/one.txt <== 14 | 15 | ==> tests/inputs/three.txt <== 16 | four words. 17 | 18 | ==> tests/inputs/two.txt <== 19 | -------------------------------------------------------------------------------- /03-catr/tests/expected/the-bustle.txt.b.out: -------------------------------------------------------------------------------- 1 | 1 The bustle in a house 2 | 2 The morning after death 3 | 3 Is solemnest of industries 4 | 4 Enacted upon earth,— 5 | 6 | 5 The sweeping up the heart, 7 | 6 And putting love away 8 | 7 We shall not want to use again 9 | 8 Until eternity. 10 | -------------------------------------------------------------------------------- /03-catr/tests/expected/the-bustle.txt.b.stdin.out: -------------------------------------------------------------------------------- 1 | 1 The bustle in a house 2 | 2 The morning after death 3 | 3 Is solemnest of industries 4 | 4 Enacted upon earth,— 5 | 6 | 5 The sweeping up the heart, 7 | 6 And putting love away 8 | 7 We shall not want to use again 9 | 8 Until eternity. 10 | -------------------------------------------------------------------------------- /03-catr/tests/expected/the-bustle.txt.n.out: -------------------------------------------------------------------------------- 1 | 1 The bustle in a house 2 | 2 The morning after death 3 | 3 Is solemnest of industries 4 | 4 Enacted upon earth,— 5 | 5 6 | 6 The sweeping up the heart, 7 | 7 And putting love away 8 | 8 We shall not want to use again 9 | 9 Until eternity. 10 | -------------------------------------------------------------------------------- /05-wcr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wcr" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | clap = "2.33" 10 | 11 | [dev-dependencies] 12 | assert_cmd = "2" 13 | predicates = "2" 14 | rand = "0.8" 15 | -------------------------------------------------------------------------------- /04-headr/tests/expected/all.n2.out: -------------------------------------------------------------------------------- 1 | ==> ./tests/inputs/empty.txt <== 2 | 3 | ==> ./tests/inputs/one.txt <== 4 | Öne line, four words. 5 | 6 | ==> ./tests/inputs/two.txt <== 7 | Two lines. 8 | Four words. 9 | 10 | ==> ./tests/inputs/three.txt <== 11 | Three 12 | lines, 13 | 14 | ==> ./tests/inputs/ten.txt <== 15 | one 16 | two 17 | -------------------------------------------------------------------------------- /10-commr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "commr" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | clap = "2.33" 10 | 11 | [dev-dependencies] 12 | assert_cmd = "2" 13 | predicates = "2" 14 | rand = "0.8" 15 | -------------------------------------------------------------------------------- /03-catr/tests/expected/the-bustle.txt.n.stdin.out: -------------------------------------------------------------------------------- 1 | 1 The bustle in a house 2 | 2 The morning after death 3 | 3 Is solemnest of industries 4 | 4 Enacted upon earth,— 5 | 5 6 | 6 The sweeping up the heart, 7 | 7 And putting love away 8 | 8 We shall not want to use again 9 | 9 Until eternity. 10 | -------------------------------------------------------------------------------- /06-uniqr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "uniqr" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | clap = "2.33" 10 | 11 | [dev-dependencies] 12 | assert_cmd = "2" 13 | predicates = "2" 14 | tempfile = "3" 15 | rand = "0.8" -------------------------------------------------------------------------------- /11-tailr/tests/expected/all.n3.out: -------------------------------------------------------------------------------- 1 | ==> tests/inputs/ten.txt <== 2 | eight 3 | nine 4 | ten 5 | 6 | ==> tests/inputs/empty.txt <== 7 | 8 | ==> tests/inputs/one.txt <== 9 | Öne line, four wordś. 10 | 11 | ==> tests/inputs/three.txt <== 12 | Three 13 | lines, 14 | four words. 15 | 16 | ==> tests/inputs/two.txt <== 17 | Two lines. 18 | Four words. 19 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/all.c+12.out: -------------------------------------------------------------------------------- 1 | ==> tests/inputs/ten.txt <== 2 | ee 3 | four 4 | five 5 | six 6 | seven 7 | eight 8 | nine 9 | ten 10 | 11 | ==> tests/inputs/empty.txt <== 12 | 13 | ==> tests/inputs/one.txt <== 14 | four wordś. 15 | 16 | ==> tests/inputs/three.txt <== 17 | s, 18 | four words. 19 | 20 | ==> tests/inputs/two.txt <== 21 | Four words. 22 | -------------------------------------------------------------------------------- /03-catr/tests/expected/all.out: -------------------------------------------------------------------------------- 1 | The quick brown fox jumps over the lazy dog. 2 | Don't worry, spiders, 3 | I keep house 4 | casually. 5 | The bustle in a house 6 | The morning after death 7 | Is solemnest of industries 8 | Enacted upon earth,— 9 | 10 | The sweeping up the heart, 11 | And putting love away 12 | We shall not want to use again 13 | Until eternity. 14 | -------------------------------------------------------------------------------- /08-cutr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cutr" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | clap = "2.33" 10 | csv = "1" 11 | regex = "1" 12 | 13 | [dev-dependencies] 14 | assert_cmd = "2" 15 | predicates = "2" 16 | rand = "0.8" 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | **/target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | -------------------------------------------------------------------------------- /07-findr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "findr" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | clap = "2.33" 10 | walkdir = "2" 11 | regex = "1" 12 | 13 | [dev-dependencies] 14 | assert_cmd = "2" 15 | predicates = "2" 16 | rand = "0.8" 17 | -------------------------------------------------------------------------------- /12-fortuner/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fortuner" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | clap = "2.33" 10 | rand = "0.8" 11 | walkdir = "2" 12 | regex = "1" 13 | 14 | [dev-dependencies] 15 | assert_cmd = "2" 16 | predicates = "2" -------------------------------------------------------------------------------- /02-echor/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "echor" 3 | version = "0.1.0" 4 | authors = ["liujianhao "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dev-dependencies] 10 | assert_cmd = "1" 11 | predicates = "1" 12 | 13 | [dependencies] 14 | clap = "2.33" 15 | -------------------------------------------------------------------------------- /04-headr/tests/expected/all.n4.out: -------------------------------------------------------------------------------- 1 | ==> ./tests/inputs/empty.txt <== 2 | 3 | ==> ./tests/inputs/one.txt <== 4 | Öne line, four words. 5 | 6 | ==> ./tests/inputs/two.txt <== 7 | Two lines. 8 | Four words. 9 | 10 | ==> ./tests/inputs/three.txt <== 11 | Three 12 | lines, 13 | four words. 14 | 15 | ==> ./tests/inputs/ten.txt <== 16 | one 17 | two 18 | three 19 | four 20 | -------------------------------------------------------------------------------- /13-calr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "calr" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | clap = "2" 10 | chrono = "0.4" 11 | itertools = "0.10" 12 | ansi_term = "0.12" 13 | 14 | [dev-dependencies] 15 | assert_cmd = "2" 16 | predicates = "2" 17 | -------------------------------------------------------------------------------- /09-grepr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "grepr" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | clap = "2.33" 10 | regex = "1" 11 | walkdir = "2" 12 | 13 | [dev-dependencies] 14 | assert_cmd = "2" 15 | predicates = "2" 16 | rand = "0.8" 17 | sys-info = "0.9" -------------------------------------------------------------------------------- /11-tailr/tests/expected/all.c+8.out: -------------------------------------------------------------------------------- 1 | ==> tests/inputs/ten.txt <== 2 | 3 | three 4 | four 5 | five 6 | six 7 | seven 8 | eight 9 | nine 10 | ten 11 | 12 | ==> tests/inputs/empty.txt <== 13 | 14 | ==> tests/inputs/one.txt <== 15 | ne, four wordś. 16 | 17 | ==> tests/inputs/three.txt <== 18 | lines, 19 | four words. 20 | 21 | ==> tests/inputs/two.txt <== 22 | es. 23 | Four words. 24 | -------------------------------------------------------------------------------- /03-catr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "catr" 3 | version = "0.1.0" 4 | authors = ["liujianhao "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | clap = "2.23" 11 | 12 | [dev-dependencies] 13 | assert_cmd = "1" 14 | predicates = "1" 15 | rand = "0.8" 16 | -------------------------------------------------------------------------------- /04-headr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "headr" 3 | version = "0.1.0" 4 | authors = ["liujianhao "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | clap = "2.33" 11 | 12 | [dev-dependencies] 13 | assert_cmd = "1" 14 | predicates = "1" 15 | rand = "0.8" 16 | -------------------------------------------------------------------------------- /11-tailr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tailr" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | clap = "2.33" 10 | num = "0.4" 11 | regex = "1" 12 | once_cell = "1" 13 | 14 | [dev-dependencies] 15 | assert_cmd = "2" 16 | predicates = "2" 17 | rand = "0.8" 18 | -------------------------------------------------------------------------------- /14-lsr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lsr" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | chrono = "0.4" 10 | clap = "2.33" 11 | users = "0.11" 12 | tabular = "0.1.4" 13 | 14 | [dev-dependencies] 15 | assert_cmd = "2" 16 | predicates = "2" 17 | rand = "0.8" 18 | 19 | -------------------------------------------------------------------------------- /14-lsr/src/owner.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone, Copy)] 2 | pub enum Owner { 3 | User, 4 | Group, 5 | Other, 6 | } 7 | 8 | impl Owner { 9 | pub fn masks(self) -> [u32; 3] { 10 | match self { 11 | Self::User => [0o400, 0o200, 0o100], 12 | Self::Group => [0o040, 0o020, 0o010], 13 | Self::Other => [0o004, 0o002, 0o001], 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /07-findr/tests/expected/path1.txt: -------------------------------------------------------------------------------- 1 | tests/inputs 2 | tests/inputs/a 3 | tests/inputs/a/a.txt 4 | tests/inputs/a/b 5 | tests/inputs/a/b/b.csv 6 | tests/inputs/a/b/c 7 | tests/inputs/a/b/c/c.mp3 8 | tests/inputs/d 9 | tests/inputs/d/b.csv 10 | tests/inputs/d/d.tsv 11 | tests/inputs/d/d.txt 12 | tests/inputs/d/e 13 | tests/inputs/d/e/e.mp3 14 | tests/inputs/f 15 | tests/inputs/f/f.txt 16 | tests/inputs/g.csv 17 | -------------------------------------------------------------------------------- /07-findr/tests/expected/path1.txt.windows: -------------------------------------------------------------------------------- 1 | tests/inputs 2 | tests/inputs\a 3 | tests/inputs\a\a.txt 4 | tests/inputs\a\b 5 | tests/inputs\a\b\b.csv 6 | tests/inputs\a\b\c 7 | tests/inputs\a\b\c\c.mp3 8 | tests/inputs\d 9 | tests/inputs\d\b.csv 10 | tests/inputs\d\d.tsv 11 | tests/inputs\d\d.txt 12 | tests/inputs\d\e 13 | tests/inputs\d\e\e.mp3 14 | tests/inputs\f 15 | tests/inputs\f\f.txt 16 | tests/inputs\g.csv 17 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/all.c+3.out: -------------------------------------------------------------------------------- 1 | ==> tests/inputs/ten.txt <== 2 | e 3 | two 4 | three 5 | four 6 | five 7 | six 8 | seven 9 | eight 10 | nine 11 | ten 12 | 13 | ==> tests/inputs/empty.txt <== 14 | 15 | ==> tests/inputs/one.txt <== 16 | ne line, four wordś. 17 | 18 | ==> tests/inputs/three.txt <== 19 | ree 20 | lines, 21 | four words. 22 | 23 | ==> tests/inputs/two.txt <== 24 | o lines. 25 | Four words. 26 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/all.out: -------------------------------------------------------------------------------- 1 | ==> tests/inputs/ten.txt <== 2 | one 3 | two 4 | three 5 | four 6 | five 7 | six 8 | seven 9 | eight 10 | nine 11 | ten 12 | 13 | ==> tests/inputs/empty.txt <== 14 | 15 | ==> tests/inputs/one.txt <== 16 | Öne line, four wordś. 17 | 18 | ==> tests/inputs/three.txt <== 19 | Three 20 | lines, 21 | four words. 22 | 23 | ==> tests/inputs/two.txt <== 24 | Two lines. 25 | Four words. 26 | -------------------------------------------------------------------------------- /11-tailr/tests/expected/all.n+1.out: -------------------------------------------------------------------------------- 1 | ==> tests/inputs/ten.txt <== 2 | one 3 | two 4 | three 5 | four 6 | five 7 | six 8 | seven 9 | eight 10 | nine 11 | ten 12 | 13 | ==> tests/inputs/empty.txt <== 14 | 15 | ==> tests/inputs/one.txt <== 16 | Öne line, four wordś. 17 | 18 | ==> tests/inputs/three.txt <== 19 | Three 20 | lines, 21 | four words. 22 | 23 | ==> tests/inputs/two.txt <== 24 | Two lines. 25 | Four words. 26 | -------------------------------------------------------------------------------- /04-headr/tests/expected/all.out: -------------------------------------------------------------------------------- 1 | ==> ./tests/inputs/empty.txt <== 2 | 3 | ==> ./tests/inputs/one.txt <== 4 | Öne line, four words. 5 | 6 | ==> ./tests/inputs/two.txt <== 7 | Two lines. 8 | Four words. 9 | 10 | ==> ./tests/inputs/three.txt <== 11 | Three 12 | lines, 13 | four words. 14 | 15 | ==> ./tests/inputs/ten.txt <== 16 | one 17 | two 18 | three 19 | four 20 | five 21 | six 22 | seven 23 | eight 24 | nine 25 | ten 26 | -------------------------------------------------------------------------------- /03-catr/tests/expected/all.b.out: -------------------------------------------------------------------------------- 1 | 1 The quick brown fox jumps over the lazy dog. 2 | 1 Don't worry, spiders, 3 | 2 I keep house 4 | 3 casually. 5 | 1 The bustle in a house 6 | 2 The morning after death 7 | 3 Is solemnest of industries 8 | 4 Enacted upon earth,— 9 | 10 | 5 The sweeping up the heart, 11 | 6 And putting love away 12 | 7 We shall not want to use again 13 | 8 Until eternity. 14 | -------------------------------------------------------------------------------- /07-findr/tests/expected/unreadable_dir.txt: -------------------------------------------------------------------------------- 1 | tests/inputs/ 2 | tests/inputs/g.csv 3 | tests/inputs/a 4 | tests/inputs/a/a.txt 5 | tests/inputs/a/b 6 | tests/inputs/a/b/b.csv 7 | tests/inputs/a/b/c 8 | tests/inputs/a/b/c/c.mp3 9 | tests/inputs/f 10 | tests/inputs/f/f.txt 11 | tests/inputs/cant-touch-this 12 | tests/inputs/d 13 | tests/inputs/d/b.csv 14 | tests/inputs/d/d.txt 15 | tests/inputs/d/d.tsv 16 | tests/inputs/d/e 17 | tests/inputs/d/e/e.mp3 18 | -------------------------------------------------------------------------------- /03-catr/tests/expected/all.n.out: -------------------------------------------------------------------------------- 1 | 1 The quick brown fox jumps over the lazy dog. 2 | 1 Don't worry, spiders, 3 | 2 I keep house 4 | 3 casually. 5 | 1 The bustle in a house 6 | 2 The morning after death 7 | 3 Is solemnest of industries 8 | 4 Enacted upon earth,— 9 | 5 10 | 6 The sweeping up the heart, 11 | 7 And putting love away 12 | 8 We shall not want to use again 13 | 9 Until eternity. 14 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/all.the.lowercase.insensistive: -------------------------------------------------------------------------------- 1 | tests/inputs/bustle.txt:The bustle in a house 2 | tests/inputs/bustle.txt:The morning after death 3 | tests/inputs/bustle.txt:The sweeping up the heart, 4 | tests/inputs/fox.txt:The quick brown fox jumps over the lazy dog. 5 | tests/inputs/nobody.txt:Then there's a pair of us! 6 | tests/inputs/nobody.txt:Don't tell! they'd advertise—you know! 7 | tests/inputs/nobody.txt:To tell one's name—the livelong June— 8 | -------------------------------------------------------------------------------- /09-grepr/tests/expected/all.the.lowercase.insensitive: -------------------------------------------------------------------------------- 1 | tests/inputs/bustle.txt:The bustle in a house 2 | tests/inputs/bustle.txt:The morning after death 3 | tests/inputs/bustle.txt:The sweeping up the heart, 4 | tests/inputs/fox.txt:The quick brown fox jumps over the lazy dog. 5 | tests/inputs/nobody.txt:Then there's a pair of us! 6 | tests/inputs/nobody.txt:Don't tell! they'd advertise—you know! 7 | tests/inputs/nobody.txt:To tell one's name—the livelong June— 8 | -------------------------------------------------------------------------------- /12-fortuner/tests/inputs/literature: -------------------------------------------------------------------------------- 1 | A banker is a fellow who lends you his umbrella when the sun is shining 2 | and wants it back the minute it begins to rain. 3 | -- Mark Twain 4 | % 5 | A classic is something that everyone wants to have read 6 | and nobody wants to read. 7 | -- Mark Twain, "The Disappearance of Literature" 8 | % 9 | A horse! A horse! My kingdom for a horse! 10 | -- Wm. Shakespeare, "Henry VI" 11 | % 12 | A is for Apple. 13 | -- Hester Pryne 14 | % 15 | -------------------------------------------------------------------------------- /12-fortuner/tests/inputs/jokes: -------------------------------------------------------------------------------- 1 | Q. What do you call a head of lettuce in a shirt and tie? 2 | A. Collared greens. 3 | % 4 | Q: Why did the gardener quit his job? 5 | A: His celery wasn't high enough. 6 | % 7 | Q. Why did the honeydew couple get married in a church? 8 | A. Their parents told them they cantaloupe. 9 | % 10 | Q: Why did the fungus and the alga marry? 11 | A: Because they took a lichen to each other! 12 | % 13 | Q: What happens when frogs park illegally? 14 | A: They get toad. 15 | % 16 | Q: What do you call a deer wearing an eye patch? 17 | A: A bad idea (bad-eye deer). 18 | % 19 | % 20 | -------------------------------------------------------------------------------- /12-fortuner/tests/inputs/quotes: -------------------------------------------------------------------------------- 1 | Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails. Explore. Dream. Discover. 2 | -- Mark Twain 3 | % 4 | I can live for two months on a good compliment. 5 | -- Mark Twain 6 | % 7 | Keep away from people who try to belittle your ambitions. Small people always do that, but the really great make you feel that you, too, can become great. 8 | -- Mark Twain 9 | % 10 | It's like deja vu all over again. 11 | -- Yogi Berra 12 | % 13 | You can observe a lot just by watching. 14 | -- Yogi Berra 15 | % 16 | -------------------------------------------------------------------------------- /12-fortuner/tests/expected/twain_cap.out: -------------------------------------------------------------------------------- 1 | A banker is a fellow who lends you his umbrella when the sun is shining 2 | and wants it back the minute it begins to rain. 3 | -- Mark Twain 4 | % 5 | A classic is something that everyone wants to have read 6 | and nobody wants to read. 7 | -- Mark Twain, "The Disappearance of Literature" 8 | % 9 | Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails. Explore. Dream. Discover. 10 | -- Mark Twain 11 | % 12 | I can live for two months on a good compliment. 13 | -- Mark Twain 14 | % 15 | Keep away from people who try to belittle your ambitions. Small people always do that, but the really great make you feel that you, too, can become great. 16 | -- Mark Twain 17 | % 18 | -------------------------------------------------------------------------------- /12-fortuner/tests/expected/twain_lower_i.out: -------------------------------------------------------------------------------- 1 | A banker is a fellow who lends you his umbrella when the sun is shining 2 | and wants it back the minute it begins to rain. 3 | -- Mark Twain 4 | % 5 | A classic is something that everyone wants to have read 6 | and nobody wants to read. 7 | -- Mark Twain, "The Disappearance of Literature" 8 | % 9 | Twenty years from now you will be more disappointed by the things that you didn't do than by the ones you did do. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails. Explore. Dream. Discover. 10 | -- Mark Twain 11 | % 12 | I can live for two months on a good compliment. 13 | -- Mark Twain 14 | % 15 | Keep away from people who try to belittle your ambitions. Small people always do that, but the really great make you feel that you, too, can become great. 16 | -- Mark Twain 17 | % 18 | -------------------------------------------------------------------------------- /02-echor/src/main.rs: -------------------------------------------------------------------------------- 1 | use clap::{App, Arg}; 2 | 3 | fn main() { 4 | let matches = App::new("echor") 5 | .version("0.1.0") 6 | .author("liujianhao") 7 | .about("Rust echo") 8 | .arg( 9 | Arg::with_name("text") 10 | .value_name("TEXT") 11 | .help("Input text") 12 | .required(true) 13 | .min_values(1), 14 | ) 15 | .arg( 16 | Arg::with_name("omit_newline") 17 | .help("Do not print newline") 18 | .takes_value(false) 19 | .short("n"), 20 | ) 21 | .get_matches(); 22 | 23 | let text = matches.values_of_lossy("text").unwrap(); 24 | let omit_newline = matches.is_present("omit_newline"); 25 | let ending = if omit_newline { "" } else { "\n" }; 26 | print!("{}{}", text.join(" "), ending); 27 | 28 | // println!("{:#?}", matches); 29 | } 30 | -------------------------------------------------------------------------------- /02-echor/tests/cli.rs: -------------------------------------------------------------------------------- 1 | use assert_cmd::Command; 2 | use predicates::prelude::*; 3 | use std::fs; 4 | 5 | type TestResult = Result<(), Box>; 6 | 7 | #[test] 8 | fn dies_no_args() ->TestResult { 9 | let mut cmd = Command::cargo_bin("echor")?; 10 | cmd.assert() 11 | .failure() 12 | .stderr(predicate::str::contains("USAGE")); 13 | 14 | Ok(()) 15 | } 16 | 17 | #[test] 18 | fn runs() { 19 | let mut cmd = Command::cargo_bin("echor").unwrap(); 20 | cmd.arg("hello").assert().success(); 21 | } 22 | 23 | fn run(args: &[&str], expected_file: &str) -> TestResult { 24 | let expected = fs::read_to_string(expected_file)?; 25 | Command::cargo_bin("echor")? 26 | .args(args) 27 | .assert() 28 | .success() 29 | .stdout(expected); 30 | 31 | Ok(()) 32 | } 33 | 34 | #[test] 35 | fn hello1() ->TestResult { 36 | run(&["Hello there"], "tests/expected/hello1.txt") 37 | } 38 | 39 | #[test] 40 | fn hello2() -> TestResult { 41 | run(&["Hello", "there"], "tests/expected/hello2.txt") 42 | } 43 | 44 | #[test] 45 | fn hello3() ->TestResult { 46 | run(&["Hello there", "-n"], "tests/expected/hello1.n.txt") 47 | } 48 | 49 | #[test] 50 | fn hello4() ->TestResult { 51 | run(&["-n", "Hello", "there"], "tests/expected/hello2.n.txt") 52 | } 53 | -------------------------------------------------------------------------------- /13-calr/tests/expected/2020.txt: -------------------------------------------------------------------------------- 1 | 2020 2 | January February March 3 | Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa 4 | 1 2 3 4 1 1 2 3 4 5 6 7 5 | 5 6 7 8 9 10 11 2 3 4 5 6 7 8 8 9 10 11 12 13 14 6 | 12 13 14 15 16 17 18 9 10 11 12 13 14 15 15 16 17 18 19 20 21 7 | 19 20 21 22 23 24 25 16 17 18 19 20 21 22 22 23 24 25 26 27 28 8 | 26 27 28 29 30 31 23 24 25 26 27 28 29 29 30 31 9 | 10 | 11 | April May June 12 | Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa 13 | 1 2 3 4 1 2 1 2 3 4 5 6 14 | 5 6 7 8 9 10 11 3 4 5 6 7 8 9 7 8 9 10 11 12 13 15 | 12 13 14 15 16 17 18 10 11 12 13 14 15 16 14 15 16 17 18 19 20 16 | 19 20 21 22 23 24 25 17 18 19 20 21 22 23 21 22 23 24 25 26 27 17 | 26 27 28 29 30 24 25 26 27 28 29 30 28 29 30 18 | 31 19 | 20 | July August September 21 | Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa 22 | 1 2 3 4 1 1 2 3 4 5 23 | 5 6 7 8 9 10 11 2 3 4 5 6 7 8 6 7 8 9 10 11 12 24 | 12 13 14 15 16 17 18 9 10 11 12 13 14 15 13 14 15 16 17 18 19 25 | 19 20 21 22 23 24 25 16 17 18 19 20 21 22 20 21 22 23 24 25 26 26 | 26 27 28 29 30 31 23 24 25 26 27 28 29 27 28 29 30 27 | 30 31 28 | 29 | October November December 30 | Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa 31 | 1 2 3 1 2 3 4 5 6 7 1 2 3 4 5 32 | 4 5 6 7 8 9 10 8 9 10 11 12 13 14 6 7 8 9 10 11 12 33 | 11 12 13 14 15 16 17 15 16 17 18 19 20 21 13 14 15 16 17 18 19 34 | 18 19 20 21 22 23 24 22 23 24 25 26 27 28 20 21 22 23 24 25 26 35 | 25 26 27 28 29 30 31 29 30 27 28 29 30 31 36 | 37 | -------------------------------------------------------------------------------- /06-uniqr/src/lib.rs: -------------------------------------------------------------------------------- 1 | use clap::{App, Arg}; 2 | use std::error::Error; 3 | use std::fs::File; 4 | use std::io::{self, BufRead, BufReader, Write}; 5 | 6 | type MyResult = Result>; 7 | 8 | pub fn run(config: Config) -> MyResult<()> { 9 | let mut file = open(&config.in_file).map_err(|e| format!("{}: {}", config.in_file, e))?; 10 | 11 | let mut out_file: Box = match &config.out_file { 12 | Some(out_name) => Box::new(File::create(out_name)?), 13 | _ => Box::new(io::stdout()), 14 | }; 15 | 16 | let mut print = |count: u64, text: &str| -> MyResult<()> { 17 | if count > 0 { 18 | if config.count { 19 | write!(out_file, "{:>4} {}", count, text)?; 20 | } else { 21 | write!(out_file, "{}", text)?; 22 | } 23 | }; 24 | Ok(()) 25 | }; 26 | 27 | 28 | let mut line = String::new(); 29 | let mut previous = String::new(); 30 | let mut count: u64 = 0; 31 | loop { 32 | let bytes = file.read_line(&mut line)?; 33 | if bytes == 0 { 34 | break; 35 | } 36 | if line.trim_end() != previous.trim_end() { 37 | print(count, &previous)?; 38 | previous = line.clone(); 39 | count = 0; 40 | } 41 | count += 1; 42 | line.clear(); 43 | } 44 | print(count, &previous)?; 45 | Ok(()) 46 | } 47 | 48 | pub fn get_args() -> MyResult { 49 | let matches = App::new("uniqr") 50 | .version("0.1.0") 51 | .author("liujianhao") 52 | .about("Rust uniq") 53 | .arg( 54 | Arg::with_name("in_file") 55 | .value_name("IN_FILE") 56 | .help("Input file") 57 | .default_value("-"), 58 | ) 59 | .arg( 60 | Arg::with_name("out_file") 61 | .value_name("OUT_FILE") 62 | .help("Output file"), 63 | ) 64 | .arg( 65 | Arg::with_name("count") 66 | .short("c") 67 | .long("count") 68 | .help("Show counts") 69 | .takes_value(false), 70 | ) 71 | .get_matches(); 72 | 73 | Ok(Config { 74 | in_file: matches.value_of_lossy("in_file").map(Into::into).unwrap(), 75 | out_file: matches.value_of("out_file").map(|v| v.to_string()), 76 | count: matches.is_present("count"), 77 | }) 78 | } 79 | 80 | #[derive(Debug)] 81 | pub struct Config { 82 | in_file: String, 83 | out_file: Option, 84 | count: bool, 85 | } 86 | 87 | fn open(filename: &str) -> MyResult> { 88 | match filename { 89 | "-" => Ok(Box::new(BufReader::new(io::stdin()))), 90 | _ => Ok(Box::new(BufReader::new(File::open(filename)?))), 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /03-catr/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use clap::{App, Arg}; 3 | use std::fs::File; 4 | use std::io::{self, BufRead, BufReader}; 5 | 6 | type MyResult = Result>; 7 | 8 | pub fn run(config: Config) -> MyResult<()> { 9 | for filename in config.files { 10 | match open(&filename) { 11 | Err(err) => eprintln!("Failed to open {}: {}", filename, err), 12 | Ok(file) => { 13 | let mut last_num = 0; 14 | for (line_num, line_result) in file.lines().enumerate() { 15 | let line = line_result?; 16 | 17 | if config.number_lines { 18 | println!("{:>6}\t{}", line_num+1, line); 19 | } else if config.number_nonblank_lines { 20 | if !line.is_empty() { 21 | last_num += 1; 22 | println!("{:>6}\t{}", last_num, line); 23 | } else { 24 | println!(); 25 | } 26 | } else { 27 | println!("{}", line); 28 | } 29 | } 30 | }, 31 | } 32 | } 33 | Ok(()) 34 | } 35 | 36 | #[derive(Debug)] 37 | pub struct Config { 38 | files: Vec, 39 | number_lines: bool, 40 | number_nonblank_lines: bool, 41 | } 42 | 43 | pub fn get_args() -> MyResult { 44 | let matches = App::new("catr") 45 | .version("0.1.0") 46 | .author("liujianhao") 47 | .about("Rust cat") 48 | .arg( 49 | Arg::with_name("files") 50 | .value_name("FILE") 51 | .help("input file(s)") 52 | .multiple(true) 53 | .default_value("-"), 54 | ) 55 | .arg( 56 | Arg::with_name("number") 57 | .short("n") 58 | .long("number") 59 | .help("Number lines") 60 | .takes_value(false) 61 | .conflicts_with("number_nonblank"), 62 | ) 63 | .arg( 64 | Arg::with_name("number_nonblank") 65 | .short("b") 66 | .long("number-nonblank") 67 | .help("Number non-blank lines") 68 | .takes_value(false), 69 | ) 70 | .get_matches(); 71 | 72 | Ok(Config { 73 | files: matches.values_of_lossy("files").unwrap(), 74 | number_lines: matches.is_present("number"), 75 | number_nonblank_lines: matches.is_present("number_nonblank") 76 | }) 77 | } 78 | 79 | // 注意这里用到了Box来创建一个指向堆内存的文件句柄 80 | // 如果不用Box的话会报错 81 | fn open(filename: &str) -> MyResult> { 82 | match filename { 83 | "-" => Ok(Box::new(BufReader::new(io::stdin()))), 84 | _ => Ok(Box::new(BufReader::new(File::open(filename)?))), 85 | } 86 | } -------------------------------------------------------------------------------- /12-fortuner/tests/inputs/ascii-art: -------------------------------------------------------------------------------- 1 | .--._.--. 2 | ( O O ) 3 | / . . \ 4 | .`._______.'. 5 | /( )\ 6 | _/ \ \ / / \_ 7 | .~ ` \ \ / / ' ~. 8 | { -. \ V / .- } 9 | _ _`. \ | | | / .'_ _ 10 | >_ _} | | | {_ _< 11 | /. - ~ ,_-' .^. `-_, ~ - .\ 12 | '-'|/ \|`-` 13 | % 14 | ( /\__________/\ ) 15 | \(^ @___..___@ ^)/ 16 | /\ (\/\/\/\/) /\ 17 | / \(/\/\/\/\)/ \ 18 | -( """""""""" ) 19 | \ _____ / 20 | ( /( )\ ) 21 | _) (_V) (V_) (_ 22 | (V)(V)(V) (V)(V)(V) 23 | % 24 | ___ ______ 25 | /__/\ ___/_____/\ 26 | \ \ \ / /\\ 27 | \ \ \_/__ / \ 28 | _\ \ \ /\_____/___ \ 29 | // \__\/ / \ /\ \ 30 | _______//_______/ \ / _\/______ 31 | / / \ \ / / / /\ 32 | __/ / \ \ / / / / _\__ 33 | / / / \_______\/ / / / / /\ 34 | /_/______/___________________/ /________/ /___/ \ 35 | \ \ \ ___________ \ \ \ \ \ / 36 | \_\ \ / /\ \ \ \ \___\/ 37 | \ \/ / \ \ \ \ / 38 | \_____/ / \ \ \________\/ 39 | /__________/ \ \ / 40 | \ _____ \ /_____\/ 41 | \ / /\ \ / \ \ \ 42 | /____/ \ \ / \ \ \ 43 | \ \ /___\/ \ \ \ 44 | \____\/ \__\/ 45 | % 46 | .s$$$Ss. 47 | .8, $$$. _. . ..sS$$$$$" ...,.; 48 | o. ,@.. 88 =.$"$' ' ..sS$$$$$$$$$$$$s. _;"' 49 | @@@.@@@. .88. ` ` ""l. .sS$$.._.sS$$$$$$$$$$$$S'"' 50 | .@@@q@@.8888o. .s$$$$$$$$$$$$$$$$$$$$$' 51 | .:`@@@@33333. .>$$$$$$$$$$$$$$$$$$$$' 52 | .: `@@@@333' ..>$$$$$$$$$$$$$$$$$$$' 53 | : `@@333. `., s$$$$$$$$$$$$$$$$$' 54 | : `@33 $$ S.s$$$$$$$$$$$$$$$$$' 55 | .S `Y ..` ,"$' `$$$$$$$$$$$$$$ 56 | $s . ..S$s, . .`$$$$$$$$$$$$. 57 | $s ., ,s ,$$$$,,sS$s.$$$$$$$$$$$$$. 58 | / /$$SsS.s. ..s$$$$$$$$$$$$$$$$$$$$$$$$$. 59 | /`.`$$$$$dN.ssS$$'`$$$$$$$$$$$$$$$$$$$$$$$. 60 | /// `$$$$$$$$$' `$$$$$$$$$$$$$$$$$$$$$$. 61 | ///| `S$$S$' `$$$$$$$$$$$$$$$$$$$$$$. 62 | / / $$$$$$$$$$$$$$$$$$$$$. 63 | `$$$$$$$$$$$$$$$$$$$$$s. 64 | $$$"' .?T$$$$$$$ 65 | .$' ... ?$$#\ 66 | ! -=S$$$$$s 67 | .! -=s$$' `$=-_ : 68 | , .$$$' `$, .| 69 | , .$$$' . , 70 | , ..$$$' 71 | .s$$$' `s . 72 | . .s$$$$' $s. ..$s 73 | . .s$$$$' `$s=s$$$ 74 | .$$$$' , $$s 75 | ` " .$$' $$$ 76 | , s$$' . $$$s 77 | ` .s..s$' .s ,$$ 78 | .s$$$' "s$$$, 79 | - $$$' .$$$$. 80 | ." .s$$s .$',',$. 81 | $s.s$$$$S.............. ................ $$....s$s...... 82 | `""' ` ```""""""""""""""" `"" `` 83 | % 84 | -------------------------------------------------------------------------------- /07-findr/src/lib.rs: -------------------------------------------------------------------------------- 1 | use crate::EntryType::*; 2 | use clap::{App, Arg}; 3 | use regex::Regex; 4 | use std::error::Error; 5 | use walkdir::{DirEntry, WalkDir}; 6 | 7 | type MyResult = Result>; 8 | 9 | #[derive(Debug, Eq, PartialEq)] 10 | enum EntryType { 11 | Dir, 12 | File, 13 | Link, 14 | } 15 | 16 | #[derive(Debug)] 17 | pub struct Config { 18 | paths: Vec, 19 | names: Vec, 20 | entry_types: Vec, 21 | } 22 | 23 | pub fn run(config: Config) -> MyResult<()> { 24 | let type_filter = |entry: &DirEntry| { 25 | config.entry_types.is_empty() 26 | || config 27 | .entry_types 28 | .iter() 29 | .any(|entry_type| match entry_type { 30 | Link => entry.file_type().is_symlink(), 31 | Dir => entry.file_type().is_dir(), 32 | File => entry.file_type().is_file(), 33 | }) 34 | }; 35 | let name_filter = |entry: &DirEntry| { 36 | config.names.is_empty() 37 | || config 38 | .names 39 | .iter() 40 | .any(|re| 41 | re.is_match(&entry.file_name().to_string_lossy())) 42 | }; 43 | for path in config.paths { 44 | let entries = WalkDir::new(path) 45 | .into_iter() 46 | .filter_map(|e| match e { 47 | Err(e) => { 48 | eprintln!("{}", e); 49 | None 50 | } 51 | Ok(entry) => Some(entry), 52 | }) 53 | .filter(type_filter) 54 | .filter(name_filter) 55 | .map(|entry| 56 | entry.path().display().to_string()) 57 | .collect::>(); 58 | 59 | println!("{}", entries.join("\n")); 60 | } 61 | Ok(()) 62 | } 63 | 64 | pub fn get_args() -> MyResult { 65 | let matches = App::new("findr") 66 | .version("0.1.0") 67 | .author("liujianhao") 68 | .about("Rust find") 69 | .arg( 70 | Arg::with_name("paths") 71 | .value_name("PATH") 72 | .help("Search paths") 73 | .default_value(".") 74 | .multiple(true), 75 | ) 76 | .arg( 77 | Arg::with_name("names") 78 | .value_name("NAME") 79 | .short("n") 80 | .long("name") 81 | .help("Name") 82 | .takes_value(true) 83 | .multiple(true), 84 | ) 85 | .arg( 86 | Arg::with_name("types") 87 | .value_name("TYPE") 88 | .short("t") 89 | .long("type") 90 | .help("Entry type") 91 | .possible_values(&["f", "d", "l"]) 92 | .multiple(true) 93 | .takes_value(true), 94 | ) 95 | .get_matches(); 96 | 97 | let names = matches 98 | .values_of_lossy("names") 99 | .map(|vals| { 100 | vals.into_iter() 101 | .map(|name| { 102 | Regex::new(&name).map_err(|_| format!("Invalid --name \"{}\"", name)) 103 | }) 104 | .collect::, _>>() 105 | }) 106 | .transpose()? 107 | .unwrap_or_default(); 108 | 109 | let entry_types = matches 110 | .values_of_lossy("types") 111 | .map(|vals| { 112 | vals.iter() 113 | .map(|val| match val.as_str() { 114 | "d" => Dir, 115 | "f" => File, 116 | "l" => Link, 117 | _ => unreachable!("Invalid type"), 118 | }) 119 | .collect() 120 | }) 121 | .unwrap_or_default(); 122 | 123 | Ok(Config { 124 | paths: matches.values_of_lossy("paths").unwrap(), 125 | names, 126 | entry_types, 127 | }) 128 | } -------------------------------------------------------------------------------- /04-headr/src/lib.rs: -------------------------------------------------------------------------------- 1 | use clap::{App, Arg}; 2 | use std::error::Error; 3 | use std::fs::File; 4 | use std::io::{self, BufRead, BufReader, Read}; 5 | 6 | type MyResult = Result>; 7 | 8 | #[derive(Debug)] 9 | pub struct Config { 10 | files: Vec, 11 | lines: usize, 12 | bytes: Option, 13 | } 14 | 15 | // -------------------------------------------------- 16 | pub fn get_args() -> MyResult { 17 | let matches = App::new("headr") 18 | .version("0.1.0") 19 | .author("Ken Youens-Clark ") 20 | .about("Rust head") 21 | .arg( 22 | Arg::with_name("lines") 23 | .short("n") 24 | .long("lines") 25 | .value_name("LINES") 26 | .help("Number of lines") 27 | .default_value("10"), 28 | ) 29 | .arg( 30 | Arg::with_name("bytes") 31 | .short("c") 32 | .long("bytes") 33 | .value_name("BYTES") 34 | .takes_value(true) 35 | .conflicts_with("lines") 36 | .help("Number of bytes"), 37 | ) 38 | .arg( 39 | Arg::with_name("files") 40 | .value_name("FILE") 41 | .help("Input file(s)") 42 | .multiple(true) 43 | .default_value("-"), 44 | ) 45 | .get_matches(); 46 | 47 | let lines = matches 48 | .value_of("lines") 49 | .map(parse_positive_int) 50 | .transpose() 51 | .map_err(|e| format!("illegal line count -- {}", e))?; 52 | 53 | let bytes = matches 54 | .value_of("bytes") 55 | .map(parse_positive_int) 56 | .transpose() 57 | .map_err(|e| format!("illegal byte count -- {}", e))?; 58 | 59 | Ok(Config { 60 | files: matches.values_of_lossy("files").unwrap(), 61 | lines: lines.unwrap(), 62 | bytes, 63 | }) 64 | } 65 | 66 | // -------------------------------------------------- 67 | pub fn run(config: Config) -> MyResult<()> { 68 | let num_files = config.files.len(); 69 | 70 | for (file_num, filename) in config.files.iter().enumerate() { 71 | match open(filename) { 72 | Err(err) => eprintln!("{}: {}", filename, err), 73 | Ok(mut file) => { 74 | if num_files > 1 { 75 | println!( 76 | "{}==> {} <==", 77 | if file_num > 0 { "\n" } else { "" }, 78 | &filename 79 | ); 80 | } 81 | 82 | if let Some(num_bytes) = config.bytes { 83 | let mut handle = file.take(num_bytes as u64); 84 | let mut buffer = vec![0; num_bytes]; 85 | let bytes_read = handle.read(&mut buffer)?; 86 | print!( 87 | "{}", 88 | String::from_utf8_lossy(&buffer[..bytes_read]) 89 | ); 90 | } else { 91 | let mut line = String::new(); 92 | for _ in 0..config.lines { 93 | let bytes = file.read_line(&mut line)?; 94 | if bytes == 0 { 95 | break; 96 | } 97 | print!("{}", line); 98 | line.clear(); 99 | } 100 | } 101 | } 102 | } 103 | } 104 | Ok(()) 105 | } 106 | 107 | // -------------------------------------------------- 108 | fn open(filename: &str) -> MyResult> { 109 | match filename { 110 | "-" => Ok(Box::new(BufReader::new(io::stdin()))), 111 | _ => Ok(Box::new(BufReader::new(File::open(filename)?))), 112 | } 113 | } 114 | 115 | // -------------------------------------------------- 116 | fn parse_positive_int(val: &str) -> MyResult { 117 | match val.parse() { 118 | Ok(n) if n > 0 => Ok(n), 119 | _ => Err(From::from(val)), 120 | } 121 | } 122 | 123 | // -------------------------------------------------- 124 | #[test] 125 | fn test_parse_positive_int() { 126 | // 3 is an OK integer 127 | let res = parse_positive_int("3"); 128 | assert!(res.is_ok()); 129 | assert_eq!(res.unwrap(), 3); 130 | 131 | // Any string is an error 132 | let res = parse_positive_int("foo"); 133 | assert!(res.is_err()); 134 | assert_eq!(res.unwrap_err().to_string(), "foo".to_string()); 135 | 136 | // A zero is an error 137 | let res = parse_positive_int("0"); 138 | assert!(res.is_err()); 139 | assert_eq!(res.unwrap_err().to_string(), "0".to_string()); 140 | } 141 | -------------------------------------------------------------------------------- /12-fortuner/tests/cli.rs: -------------------------------------------------------------------------------- 1 | use assert_cmd::Command; 2 | use predicates::prelude::*; 3 | use rand::{distributions::Alphanumeric, Rng}; 4 | use std::fs; 5 | 6 | type TestResult = Result<(), Box>; 7 | 8 | const PRG: &str = "fortuner"; 9 | const FORTUNE_DIR: &str = "./tests/inputs"; 10 | const EMPTY_DIR: &str = "./tests/inputs/empty"; 11 | const JOKES: &str = "./tests/inputs/jokes"; 12 | const LITERATURE: &str = "./tests/inputs/literature"; 13 | const QUOTES: &str = "./tests/inputs/quotes"; 14 | 15 | // -------------------------------------------------- 16 | fn random_string() -> String { 17 | rand::thread_rng() 18 | .sample_iter(&Alphanumeric) 19 | .take(7) 20 | .map(char::from) 21 | .collect() 22 | } 23 | 24 | // -------------------------------------------------- 25 | fn gen_bad_file() -> String { 26 | loop { 27 | let filename = random_string(); 28 | if fs::metadata(&filename).is_err() { 29 | return filename; 30 | } 31 | } 32 | } 33 | 34 | // -------------------------------------------------- 35 | #[test] 36 | fn dies_bad_file() -> TestResult { 37 | let bad = gen_bad_file(); 38 | let expected = format!("{}: .* [(]os error 2[)]", bad); 39 | Command::cargo_bin(PRG)? 40 | .args(&[LITERATURE, &bad]) 41 | .assert() 42 | .failure() 43 | .stderr(predicate::str::is_match(expected)?); 44 | Ok(()) 45 | } 46 | 47 | // -------------------------------------------------- 48 | #[test] 49 | fn dies_bad_seed() -> TestResult { 50 | let bad = random_string(); 51 | let expected = format!("\"{}\" not a valid integer", &bad); 52 | Command::cargo_bin(PRG)? 53 | .args(&[LITERATURE, "--seed", &bad]) 54 | .assert() 55 | .failure() 56 | .stderr(predicate::str::contains(expected)); 57 | Ok(()) 58 | } 59 | 60 | // -------------------------------------------------- 61 | fn run(args: &[&str], expected: &'static str) -> TestResult { 62 | Command::cargo_bin(PRG)? 63 | .args(args) 64 | .assert() 65 | .success() 66 | .stdout(expected); 67 | Ok(()) 68 | } 69 | 70 | // -------------------------------------------------- 71 | #[test] 72 | fn no_fortunes_found() -> TestResult { 73 | run(&[EMPTY_DIR], "No fortunes found\n") 74 | } 75 | 76 | // -------------------------------------------------- 77 | #[test] 78 | fn quotes_seed_1() -> TestResult { 79 | run( 80 | &[QUOTES, "-s", "1"], 81 | "You can observe a lot just by watching.\n-- Yogi Berra\n", 82 | ) 83 | } 84 | 85 | // -------------------------------------------------- 86 | #[test] 87 | fn jokes_seed_1() -> TestResult { 88 | run( 89 | &[JOKES, "-s", "1"], 90 | "Q: What happens when frogs park illegally?\nA: They get toad.\n", 91 | ) 92 | } 93 | 94 | // -------------------------------------------------- 95 | #[test] 96 | fn dir_seed_10() -> TestResult { 97 | run( 98 | &[FORTUNE_DIR, "-s", "10"], 99 | "Q: Why did the fungus and the alga marry?\n\ 100 | A: Because they took a lichen to each other!\n", 101 | ) 102 | } 103 | 104 | // -------------------------------------------------- 105 | fn run_outfiles(args: &[&str], out_file: &str, err_file: &str) -> TestResult { 106 | let out = fs::read_to_string(out_file)?; 107 | let err = fs::read_to_string(err_file)?; 108 | Command::cargo_bin(PRG)? 109 | .args(args) 110 | .assert() 111 | .success() 112 | .stderr(err) 113 | .stdout(out); 114 | Ok(()) 115 | } 116 | 117 | // -------------------------------------------------- 118 | #[test] 119 | fn yogi_berra_cap() -> TestResult { 120 | run_outfiles( 121 | &["--pattern", "Yogi Berra", FORTUNE_DIR], 122 | "tests/expected/berra_cap.out", 123 | "tests/expected/berra_cap.err", 124 | ) 125 | } 126 | 127 | // -------------------------------------------------- 128 | #[test] 129 | fn mark_twain_cap() -> TestResult { 130 | run_outfiles( 131 | &["-m", "Mark Twain", FORTUNE_DIR], 132 | "tests/expected/twain_cap.out", 133 | "tests/expected/twain_cap.err", 134 | ) 135 | } 136 | 137 | // -------------------------------------------------- 138 | #[test] 139 | fn yogi_berra_lower() -> TestResult { 140 | run_outfiles( 141 | &["--pattern", "yogi berra", FORTUNE_DIR], 142 | "tests/expected/berra_lower.out", 143 | "tests/expected/berra_lower.err", 144 | ) 145 | } 146 | 147 | // -------------------------------------------------- 148 | #[test] 149 | fn mark_twain_lower() -> TestResult { 150 | run_outfiles( 151 | &["-m", "will twain", FORTUNE_DIR], 152 | "tests/expected/twain_lower.out", 153 | "tests/expected/twain_lower.err", 154 | ) 155 | } 156 | 157 | // -------------------------------------------------- 158 | #[test] 159 | fn yogi_berra_lower_i() -> TestResult { 160 | run_outfiles( 161 | &["--insensitive", "--pattern", "yogi berra", FORTUNE_DIR], 162 | "tests/expected/berra_lower_i.out", 163 | "tests/expected/berra_lower_i.err", 164 | ) 165 | } 166 | 167 | // -------------------------------------------------- 168 | #[test] 169 | fn mark_twain_lower_i() -> TestResult { 170 | run_outfiles( 171 | &["-i", "-m", "mark twain", FORTUNE_DIR], 172 | "tests/expected/twain_lower_i.out", 173 | "tests/expected/twain_lower_i.err", 174 | ) 175 | } 176 | -------------------------------------------------------------------------------- /12-fortuner/src/lib.rs: -------------------------------------------------------------------------------- 1 | use clap::{App, Arg}; 2 | use rand::prelude::SliceRandom; 3 | use rand::{rngs::StdRng, SeedableRng}; 4 | use regex::{Regex, RegexBuilder}; 5 | use std::{ 6 | error::Error, 7 | ffi::OsStr, 8 | fs::{self, File}, 9 | io::{BufRead, BufReader}, 10 | path::PathBuf, 11 | }; 12 | use walkdir::WalkDir; 13 | 14 | type MyResult = Result>; 15 | 16 | #[derive(Debug)] 17 | pub struct Config { 18 | sources: Vec, 19 | pattern: Option, 20 | seed: Option, 21 | } 22 | 23 | #[derive(Debug)] 24 | struct Fortune { 25 | source: String, 26 | text: String, 27 | } 28 | 29 | pub fn get_args() -> MyResult { 30 | let matches = App::new("fortuner") 31 | .version("0.1.0") 32 | .author("Ken Youens-Clark ") 33 | .about("Rust fortune") 34 | .arg( 35 | Arg::with_name("sources") 36 | .value_name("FILE") 37 | .multiple(true) 38 | .required(true) 39 | .help("Input files or directories"), 40 | ) 41 | .arg( 42 | Arg::with_name("pattern") 43 | .value_name("PATTERN") 44 | .short("m") 45 | .long("pattern") 46 | .help("Pattern"), 47 | ) 48 | .arg( 49 | Arg::with_name("insensitive") 50 | .short("i") 51 | .long("insensitive") 52 | .help("Case-insensitive pattern matching") 53 | .takes_value(false), 54 | ) 55 | .arg( 56 | Arg::with_name("seed") 57 | .value_name("SEED") 58 | .short("s") 59 | .long("seed") 60 | .help("Random seed"), 61 | ) 62 | .get_matches(); 63 | 64 | let pattern = matches 65 | .value_of("pattern") 66 | .map(|val| { 67 | RegexBuilder::new(val) 68 | .case_insensitive(matches.is_present("insensitive")) 69 | .build() 70 | .map_err(|_| format!("Invalid --pattern \"{}\"", val)) 71 | }) 72 | .transpose()?; 73 | 74 | Ok(Config { 75 | sources: matches.values_of_lossy("sources").unwrap(), 76 | seed: matches.value_of("seed").map(parse_u64).transpose()?, 77 | pattern, 78 | }) 79 | } 80 | 81 | pub fn run(config: Config) -> MyResult<()> { 82 | let files = find_files(&config.sources)?; 83 | let fortunes = read_fortunes(&files)?; 84 | 85 | if let Some(pattern) = config.pattern { 86 | let mut prev_source = None; 87 | for fortune in fortunes 88 | .iter() 89 | .filter(|fortune| pattern.is_match(&fortune.text)) 90 | { 91 | if prev_source.as_ref().map_or(true, |s| s != &fortune.source) { 92 | eprintln!("({})\n%", fortune.source); 93 | prev_source = Some(fortune.source.clone()); 94 | } 95 | println!("{}\n%", fortune.text); 96 | } 97 | } else { 98 | println!( 99 | "{}", 100 | pick_fortune(&fortunes, config.seed) 101 | .or_else(|| Some("No fortunes found".to_string())) 102 | .unwrap() 103 | ); 104 | } 105 | 106 | Ok(()) 107 | } 108 | 109 | fn parse_u64(val: &str) -> MyResult { 110 | val.parse() 111 | .map_err(|_| format!("\"{}\" not a valid integer", val).into()) 112 | } 113 | 114 | fn find_files(paths: &[String]) -> MyResult> { 115 | let dat = OsStr::new("dat"); 116 | let mut files = vec![]; 117 | 118 | for path in paths { 119 | match fs::metadata(path) { 120 | Err(e) => return Err(format!("{}: {}", path, e).into()), 121 | Ok(_) => files.extend( 122 | WalkDir::new(path) 123 | .into_iter() 124 | .filter_map(Result::ok) 125 | .filter(|e| { 126 | e.file_type().is_file() 127 | && e.path().extension() != Some(dat) 128 | }) 129 | .map(|e| e.path().into()), 130 | ), 131 | } 132 | } 133 | 134 | files.sort(); 135 | files.dedup(); 136 | Ok(files) 137 | } 138 | 139 | fn read_fortunes(paths: &[PathBuf]) -> MyResult> { 140 | let mut fortunes = vec![]; 141 | let mut buffer = vec![]; 142 | 143 | for path in paths { 144 | let basename = 145 | path.file_name().unwrap().to_string_lossy().into_owned(); 146 | let file = File::open(path).map_err(|e| { 147 | format!("{}: {}", path.to_string_lossy().into_owned(), e) 148 | })?; 149 | 150 | for line in BufReader::new(file).lines().filter_map(Result::ok) { 151 | if line == "%" { 152 | if !buffer.is_empty() { 153 | fortunes.push(Fortune { 154 | source: basename.clone(), 155 | text: buffer.join("\n"), 156 | }); 157 | buffer.clear(); 158 | } 159 | } else { 160 | buffer.push(line.to_string()); 161 | } 162 | } 163 | } 164 | 165 | Ok(fortunes) 166 | } 167 | 168 | fn pick_fortune(fortunes: &[Fortune], seed: Option) -> Option { 169 | if let Some(val) = seed { 170 | let mut rng = StdRng::seed_from_u64(val); 171 | fortunes.choose(&mut rng).map(|f| f.text.to_string()) 172 | } else { 173 | let mut rng = rand::thread_rng(); 174 | fortunes.choose(&mut rng).map(|f| f.text.to_string()) 175 | } 176 | } -------------------------------------------------------------------------------- /03-catr/tests/cli.rs: -------------------------------------------------------------------------------- 1 | use assert_cmd::Command; 2 | use predicates::prelude::*; 3 | use rand::{distributions::Alphanumeric, Rng}; 4 | use std::error::Error; 5 | use std::fs; 6 | 7 | type TestResult = Result<(), Box>; 8 | 9 | const PRG: &str = "catr"; 10 | const EMPTY: &str = "tests/inputs/empty.txt"; 11 | const FOX: &str = "tests/inputs/fox.txt"; 12 | const SPIDERS: &str = "tests/inputs/spiders.txt"; 13 | const BUSTLE: &str = "tests/inputs/the-bustle.txt"; 14 | 15 | // -------------------------------------------------- 16 | #[test] 17 | fn usage() -> TestResult { 18 | for flag in &["-h", "--help"] { 19 | Command::cargo_bin(PRG)? 20 | .arg(flag) 21 | .assert() 22 | .stdout(predicate::str::contains("USAGE")); 23 | } 24 | Ok(()) 25 | } 26 | 27 | // -------------------------------------------------- 28 | fn gen_bad_file() -> String { 29 | loop { 30 | let filename: String = rand::thread_rng() 31 | .sample_iter(&Alphanumeric) 32 | .take(7) 33 | .map(char::from) 34 | .collect(); 35 | 36 | if fs::metadata(&filename).is_err() { 37 | return filename; 38 | } 39 | } 40 | } 41 | 42 | // -------------------------------------------------- 43 | #[test] 44 | fn skips_bad_file() -> TestResult { 45 | let bad = gen_bad_file(); 46 | let expected = format!("{}: .* [(]os error 2[)]", bad); 47 | Command::cargo_bin(PRG)? 48 | .arg(&bad) 49 | .assert() 50 | .success() 51 | .stderr(predicate::str::is_match(expected)?); 52 | Ok(()) 53 | } 54 | 55 | // -------------------------------------------------- 56 | fn run(args: &[&str], expected_file: &str) -> TestResult { 57 | let expected = fs::read_to_string(expected_file)?; 58 | Command::cargo_bin(PRG)? 59 | .args(args) 60 | .assert() 61 | .success() 62 | .stdout(expected); 63 | Ok(()) 64 | } 65 | 66 | // -------------------------------------------------- 67 | fn run_stdin( 68 | input_file: &str, 69 | args: &[&str], 70 | expected_file: &str, 71 | ) -> TestResult { 72 | let input = fs::read_to_string(input_file)?; 73 | let expected = fs::read_to_string(expected_file)?; 74 | Command::cargo_bin(PRG)? 75 | .args(args) 76 | .write_stdin(input) 77 | .assert() 78 | .success() 79 | .stdout(expected); 80 | Ok(()) 81 | } 82 | 83 | // -------------------------------------------------- 84 | #[test] 85 | fn bustle_stdin() -> TestResult { 86 | run_stdin(BUSTLE, &["-"], "tests/expected/the-bustle.txt.stdin.out") 87 | } 88 | 89 | // -------------------------------------------------- 90 | #[test] 91 | fn bustle_stdin_n() -> TestResult { 92 | run_stdin( 93 | BUSTLE, 94 | &["-n", "-"], 95 | "tests/expected/the-bustle.txt.n.stdin.out", 96 | ) 97 | } 98 | 99 | // -------------------------------------------------- 100 | #[test] 101 | fn bustle_stdin_b() -> TestResult { 102 | run_stdin( 103 | BUSTLE, 104 | &["-b", "-"], 105 | "tests/expected/the-bustle.txt.b.stdin.out", 106 | ) 107 | } 108 | 109 | // -------------------------------------------------- 110 | #[test] 111 | fn empty() -> TestResult { 112 | run(&[EMPTY], "tests/expected/empty.txt.out") 113 | } 114 | 115 | // -------------------------------------------------- 116 | #[test] 117 | fn empty_n() -> TestResult { 118 | run(&["-n", EMPTY], "tests/expected/empty.txt.n.out") 119 | } 120 | 121 | // -------------------------------------------------- 122 | #[test] 123 | fn empty_b() -> TestResult { 124 | run(&["-b", EMPTY], "tests/expected/empty.txt.b.out") 125 | } 126 | 127 | // -------------------------------------------------- 128 | #[test] 129 | fn fox() -> TestResult { 130 | run(&[FOX], "tests/expected/fox.txt.out") 131 | } 132 | 133 | // -------------------------------------------------- 134 | #[test] 135 | fn fox_n() -> TestResult { 136 | run(&["-n", FOX], "tests/expected/fox.txt.n.out") 137 | } 138 | 139 | // -------------------------------------------------- 140 | #[test] 141 | fn fox_b() -> TestResult { 142 | run(&["-b", FOX], "tests/expected/fox.txt.b.out") 143 | } 144 | 145 | // -------------------------------------------------- 146 | #[test] 147 | fn spiders() -> TestResult { 148 | run(&[SPIDERS], "tests/expected/spiders.txt.out") 149 | } 150 | 151 | // -------------------------------------------------- 152 | #[test] 153 | fn spiders_n() -> TestResult { 154 | run(&["--number", SPIDERS], "tests/expected/spiders.txt.n.out") 155 | } 156 | 157 | // -------------------------------------------------- 158 | #[test] 159 | fn spiders_b() -> TestResult { 160 | run( 161 | &["--number-nonblank", SPIDERS], 162 | "tests/expected/spiders.txt.b.out", 163 | ) 164 | } 165 | 166 | // -------------------------------------------------- 167 | #[test] 168 | fn bustle() -> TestResult { 169 | run(&[BUSTLE], "tests/expected/the-bustle.txt.out") 170 | } 171 | 172 | // -------------------------------------------------- 173 | #[test] 174 | fn bustle_n() -> TestResult { 175 | run(&["-n", BUSTLE], "tests/expected/the-bustle.txt.n.out") 176 | } 177 | 178 | // -------------------------------------------------- 179 | #[test] 180 | fn bustle_b() -> TestResult { 181 | run(&["-b", BUSTLE], "tests/expected/the-bustle.txt.b.out") 182 | } 183 | 184 | // -------------------------------------------------- 185 | #[test] 186 | fn all() -> TestResult { 187 | run(&[FOX, SPIDERS, BUSTLE], "tests/expected/all.out") 188 | } 189 | 190 | // -------------------------------------------------- 191 | #[test] 192 | fn all_n() -> TestResult { 193 | run(&[FOX, SPIDERS, BUSTLE, "-n"], "tests/expected/all.n.out") 194 | } 195 | 196 | // -------------------------------------------------- 197 | #[test] 198 | fn all_b() -> TestResult { 199 | run(&[FOX, SPIDERS, BUSTLE, "-b"], "tests/expected/all.b.out") 200 | } 201 | -------------------------------------------------------------------------------- /10-commr/src/lib.rs: -------------------------------------------------------------------------------- 1 | use crate::Column::*; 2 | use clap::{App, Arg}; 3 | use std::{ 4 | cmp::Ordering::*, 5 | error::Error, 6 | fs::File, 7 | io::{self, BufRead, BufReader}, 8 | }; 9 | 10 | type MyResult = Result>; 11 | 12 | #[derive(Debug)] 13 | enum Column<'a> { 14 | Col1(&'a str), 15 | Col2(&'a str), 16 | Col3(&'a str), 17 | } 18 | 19 | #[derive(Debug)] 20 | pub struct Config { 21 | file1: String, 22 | file2: String, 23 | show_col1: bool, 24 | show_col2: bool, 25 | show_col3: bool, 26 | insensitive: bool, 27 | delimiter: String, 28 | } 29 | 30 | pub fn get_args() -> MyResult { 31 | let matches = App::new("commr") 32 | .version("0.1.0") 33 | .author("Ken Youens-Clark ") 34 | .about("Rust comm") 35 | .arg( 36 | Arg::with_name("file1") 37 | .value_name("FILE1") 38 | .help("Input file 1") 39 | .takes_value(true) 40 | .required(true), 41 | ) 42 | .arg( 43 | Arg::with_name("file2") 44 | .value_name("FILE2") 45 | .help("Input file 2") 46 | .takes_value(true) 47 | .required(true), 48 | ) 49 | .arg( 50 | Arg::with_name("suppress_col1") 51 | .short("1") 52 | .takes_value(false) 53 | .help("Suppress printing of column 1"), 54 | ) 55 | .arg( 56 | Arg::with_name("suppress_col2") 57 | .short("2") 58 | .takes_value(false) 59 | .help("Suppress printing of column 2"), 60 | ) 61 | .arg( 62 | Arg::with_name("suppress_col3") 63 | .short("3") 64 | .takes_value(false) 65 | .help("Suppress printing of column 3"), 66 | ) 67 | .arg( 68 | Arg::with_name("insensitive") 69 | .short("i") 70 | .takes_value(false) 71 | .help("Case-insensitive comparison of lines"), 72 | ) 73 | .arg( 74 | Arg::with_name("delimiter") 75 | .short("d") 76 | .long("output-delimiter") 77 | .value_name("DELIM") 78 | .help("Output delimiter") 79 | .default_value("\t") 80 | .takes_value(true), 81 | ) 82 | .get_matches(); 83 | 84 | Ok(Config { 85 | file1: matches.value_of("file1").unwrap().to_string(), 86 | file2: matches.value_of("file2").unwrap().to_string(), 87 | show_col1: !matches.is_present("suppress_col1"), 88 | show_col2: !matches.is_present("suppress_col2"), 89 | show_col3: !matches.is_present("suppress_col3"), 90 | insensitive: matches.is_present("insensitive"), 91 | delimiter: matches.value_of("delimiter").unwrap().to_string(), 92 | }) 93 | } 94 | 95 | pub fn run(config: Config) -> MyResult<()> { 96 | let file1 = &config.file1; 97 | let file2 = &config.file2; 98 | 99 | if file1 == "-" && file2 == "-" { 100 | return Err(From::from("Both input files cannot be STDIN (\"-\")")); 101 | } 102 | 103 | let case = |line: String| { 104 | if config.insensitive { 105 | line.to_lowercase() 106 | } else { 107 | line 108 | } 109 | }; 110 | 111 | let mut lines1 = open(file1)?.lines().filter_map(Result::ok).map(case); 112 | let mut lines2 = open(file2)?.lines().filter_map(Result::ok).map(case); 113 | 114 | let print = |col: Column| { 115 | let mut columns = vec![]; 116 | match col { 117 | Col1(val) => { 118 | if config.show_col1 { 119 | columns.push(val); 120 | } 121 | } 122 | Col2(val) => { 123 | if config.show_col2 { 124 | if config.show_col1 { 125 | columns.push(""); 126 | } 127 | columns.push(val); 128 | } 129 | } 130 | Col3(val) => { 131 | if config.show_col3 { 132 | if config.show_col1 { 133 | columns.push(""); 134 | } 135 | if config.show_col2 { 136 | columns.push(""); 137 | } 138 | columns.push(val); 139 | } 140 | } 141 | }; 142 | 143 | if !columns.is_empty() { 144 | println!("{}", columns.join(&config.delimiter)); 145 | } 146 | }; 147 | 148 | let mut line1 = lines1.next(); 149 | let mut line2 = lines2.next(); 150 | 151 | while line1.is_some() || line2.is_some() { 152 | match (&line1, &line2) { 153 | (Some(val1), Some(val2)) => match val1.cmp(val2) { 154 | Equal => { 155 | print(Col3(val1)); 156 | line1 = lines1.next(); 157 | line2 = lines2.next(); 158 | } 159 | Less => { 160 | print(Col1(val1)); 161 | line1 = lines1.next(); 162 | } 163 | Greater => { 164 | print(Col2(val2)); 165 | line2 = lines2.next(); 166 | } 167 | }, 168 | (Some(val1), None) => { 169 | print(Col1(val1)); 170 | line1 = lines1.next(); 171 | } 172 | (None, Some(val2)) => { 173 | print(Col2(val2)); 174 | line2 = lines2.next(); 175 | } 176 | _ => (), 177 | } 178 | } 179 | 180 | Ok(()) 181 | } 182 | 183 | fn open(filename: &str) -> MyResult> { 184 | match filename { 185 | "-" => Ok(Box::new(BufReader::new(io::stdin()))), 186 | _ => Ok(Box::new(BufReader::new( 187 | File::open(filename) 188 | .map_err(|e| format!("{}: {}", filename, e))?, 189 | ))), 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /05-wcr/src/lib.rs: -------------------------------------------------------------------------------- 1 | use clap::{App, Arg}; 2 | use std::error::Error; 3 | use std::fs::File; 4 | use std::io::{self, BufRead, BufReader}; 5 | 6 | type MyResult = Result>; 7 | 8 | pub fn run(config: Config) -> MyResult<()> { 9 | let mut total_lines = 0; 10 | let mut total_words = 0; 11 | let mut total_bytes = 0; 12 | let mut total_chars = 0; 13 | 14 | for filename in &config.files { 15 | match open(filename) { 16 | Err(err) => eprintln!("{}: {}", filename, err), 17 | Ok(file) => { 18 | if let Ok(info) = count(file) { 19 | println!( 20 | "{}{}{}{}{}", 21 | format_field(info.num_lines, config.lines), 22 | format_field(info.num_words, config.words), 23 | format_field(info.num_bytes, config.bytes), 24 | format_field(info.num_chars, config.chars), 25 | if filename == "-" { 26 | "".to_string() 27 | } else { 28 | format!(" {}", &filename) 29 | }, 30 | ); 31 | 32 | total_lines += info.num_lines; 33 | total_words += info.num_words; 34 | total_bytes += info.num_bytes; 35 | total_chars += info.num_chars; 36 | } 37 | } 38 | } 39 | } 40 | 41 | if config.files.len() > 1 { 42 | println!( 43 | "{}{}{}{} total", 44 | format_field(total_lines, config.lines), 45 | format_field(total_words, config.words), 46 | format_field(total_bytes, config.bytes), 47 | format_field(total_chars, config.chars) 48 | ); 49 | } 50 | Ok(()) 51 | } 52 | 53 | fn format_field(value: usize, show: bool) -> String { 54 | if show { 55 | format!("{:>8}", value) 56 | } else { 57 | "".to_string() 58 | } 59 | } 60 | 61 | pub fn count(mut file: impl BufRead) -> MyResult { 62 | let mut num_lines = 0; 63 | let mut num_words = 0; 64 | let mut num_bytes = 0; 65 | let mut num_chars = 0; 66 | let mut line = String::new(); 67 | 68 | loop { 69 | let line_bytes = file.read_line(&mut line)?; 70 | if line_bytes == 0 { 71 | break; 72 | } 73 | num_bytes += line_bytes; 74 | num_lines += 1; 75 | num_words += line.split_whitespace().count(); 76 | num_chars += line.chars().count(); 77 | line.clear(); 78 | } 79 | 80 | Ok(FileInfo { 81 | num_lines, 82 | num_words, 83 | num_bytes, 84 | num_chars, 85 | }) 86 | } 87 | 88 | #[derive(Debug)] 89 | pub struct Config { 90 | files: Vec, 91 | lines: bool, 92 | words: bool, 93 | bytes: bool, 94 | chars: bool, 95 | } 96 | 97 | #[derive(Debug, PartialEq)] 98 | pub struct FileInfo { 99 | num_lines: usize, 100 | num_words: usize, 101 | num_bytes: usize, 102 | num_chars: usize, 103 | } 104 | 105 | pub fn get_args() -> MyResult { 106 | let matches = App::new("wcr") 107 | .version("0.1.0") 108 | .author("liujianhao") 109 | .about("Rust wc") 110 | .arg( 111 | Arg::with_name("files") 112 | .value_name("FILE") 113 | .help("Input file(s)") 114 | .default_value("-") 115 | .multiple(true), 116 | ) 117 | .arg( 118 | Arg::with_name("words") 119 | .short("w") 120 | .long("words") 121 | .help("Show word count") 122 | .takes_value(false), 123 | ) 124 | .arg( 125 | Arg::with_name("bytes") 126 | .short("c") 127 | .long("bytes") 128 | .help("Show byte count") 129 | .takes_value(false), 130 | ) 131 | .arg( 132 | Arg::with_name("chars") 133 | .short("m") 134 | .long("chars") 135 | .help("Show character count") 136 | .takes_value(false) 137 | .conflicts_with("bytes"), 138 | ) 139 | .arg( 140 | Arg::with_name("lines") 141 | .short("l") 142 | .long("lines") 143 | .help("Show line count") 144 | .takes_value(false), 145 | ) 146 | .get_matches(); 147 | 148 | let mut lines = matches.is_present("lines"); 149 | let mut words = matches.is_present("words"); 150 | let mut bytes = matches.is_present("bytes"); 151 | let chars = matches.is_present("chars"); 152 | 153 | if [words, bytes, chars, lines].iter().all(|v| v == &false) { 154 | lines = true; 155 | words = true; 156 | bytes = true; 157 | } 158 | 159 | Ok(Config { 160 | files: matches.values_of_lossy("files").unwrap(), 161 | lines, 162 | words, 163 | bytes, 164 | chars, 165 | }) 166 | } 167 | 168 | fn open(filename: &str) -> MyResult> { 169 | match filename { 170 | "-" => Ok(Box::new(BufReader::new(io::stdin()))), 171 | _ => Ok(Box::new(BufReader::new(File::open(filename)?))), 172 | } 173 | } 174 | 175 | // -------------------------------------------------- 176 | #[cfg(test)] 177 | mod tests { 178 | use super::{count, format_field, FileInfo}; 179 | use std::io::Cursor; 180 | 181 | #[test] 182 | fn test_count() { 183 | let text = "I don't want the world. I just want your half.\r\n"; 184 | let info = count(Cursor::new(text)); 185 | assert!(info.is_ok()); 186 | let expected = FileInfo { 187 | num_lines: 1, 188 | num_words: 10, 189 | num_chars: 48, 190 | num_bytes: 48, 191 | }; 192 | assert_eq!(info.unwrap(), expected); 193 | } 194 | 195 | #[test] 196 | fn test_format_field() { 197 | assert_eq!(format_field(1, false), ""); 198 | assert_eq!(format_field(3, true), " 3"); 199 | assert_eq!(format_field(10, true), " 10"); 200 | } 201 | } -------------------------------------------------------------------------------- /13-calr/tests/cli.rs: -------------------------------------------------------------------------------- 1 | use assert_cmd::Command; 2 | use predicates::prelude::*; 3 | use std::{error::Error, fs}; 4 | 5 | type TestResult = Result<(), Box>; 6 | 7 | const PRG: &str = "calr"; 8 | 9 | // -------------------------------------------------- 10 | #[test] 11 | fn dies_year_0() -> TestResult { 12 | Command::cargo_bin(PRG)? 13 | .arg("0") 14 | .assert() 15 | .failure() 16 | .stderr("year \"0\" not in the range 1 through 9999\n"); 17 | Ok(()) 18 | } 19 | 20 | // -------------------------------------------------- 21 | #[test] 22 | fn dies_year_13() -> TestResult { 23 | Command::cargo_bin(PRG)? 24 | .arg("10000") 25 | .assert() 26 | .failure() 27 | .stderr("year \"10000\" not in the range 1 through 9999\n"); 28 | Ok(()) 29 | } 30 | 31 | // -------------------------------------------------- 32 | #[test] 33 | fn dies_invalid_year() -> TestResult { 34 | Command::cargo_bin(PRG)? 35 | .arg("foo") 36 | .assert() 37 | .failure() 38 | .stderr("Invalid integer \"foo\"\n"); 39 | Ok(()) 40 | } 41 | 42 | // -------------------------------------------------- 43 | #[test] 44 | fn dies_month_0() -> TestResult { 45 | Command::cargo_bin(PRG)? 46 | .args(&["-m", "0"]) 47 | .assert() 48 | .failure() 49 | .stderr("month \"0\" not in the range 1 through 12\n"); 50 | Ok(()) 51 | } 52 | 53 | // -------------------------------------------------- 54 | #[test] 55 | fn dies_month_13() -> TestResult { 56 | Command::cargo_bin(PRG)? 57 | .args(&["-m", "13"]) 58 | .assert() 59 | .failure() 60 | .stderr("month \"13\" not in the range 1 through 12\n"); 61 | Ok(()) 62 | } 63 | 64 | // -------------------------------------------------- 65 | #[test] 66 | fn dies_invalid_month() -> TestResult { 67 | Command::cargo_bin(PRG)? 68 | .args(&["-m", "foo"]) 69 | .assert() 70 | .failure() 71 | .stderr("Invalid month \"foo\"\n"); 72 | Ok(()) 73 | } 74 | 75 | // -------------------------------------------------- 76 | #[test] 77 | fn dies_y_and_month() -> TestResult { 78 | let expected = "The argument '-m ' cannot be used with '--year'"; 79 | Command::cargo_bin(PRG)? 80 | .args(&["-m", "1", "-y"]) 81 | .assert() 82 | .failure() 83 | .stderr(predicate::str::contains(expected)); 84 | Ok(()) 85 | } 86 | 87 | // -------------------------------------------------- 88 | #[test] 89 | fn dies_y_and_year() -> TestResult { 90 | let expected = "The argument '' cannot be used with '--year'"; 91 | Command::cargo_bin(PRG)? 92 | .args(&["-y", "2000"]) 93 | .assert() 94 | .failure() 95 | .stderr(predicate::str::contains(expected)); 96 | Ok(()) 97 | } 98 | 99 | // -------------------------------------------------- 100 | #[test] 101 | fn month_num() -> TestResult { 102 | let expected = &[ 103 | ("1", "January"), 104 | ("2", "February"), 105 | ("3", "March"), 106 | ("4", "April"), 107 | ("5", "May"), 108 | ("6", "June"), 109 | ("7", "July"), 110 | ("8", "August"), 111 | ("9", "September"), 112 | ("10", "October"), 113 | ("11", "November"), 114 | ("12", "December"), 115 | ]; 116 | 117 | for (num, month) in expected { 118 | Command::cargo_bin(PRG)? 119 | .args(&["-m", num]) 120 | .assert() 121 | .success() 122 | .stdout(predicates::str::contains(month.to_string())); 123 | } 124 | Ok(()) 125 | } 126 | 127 | // -------------------------------------------------- 128 | #[test] 129 | fn partial_month() -> TestResult { 130 | let expected = &[ 131 | ("ja", "January"), 132 | ("f", "February"), 133 | ("mar", "March"), 134 | ("ap", "April"), 135 | ("may", "May"), 136 | ("jun", "June"), 137 | ("jul", "July"), 138 | ("au", "August"), 139 | ("s", "September"), 140 | ("n", "November"), 141 | ("d", "December"), 142 | ]; 143 | 144 | for (arg, month) in expected { 145 | Command::cargo_bin(PRG)? 146 | .args(&["-m", arg]) 147 | .assert() 148 | .success() 149 | .stdout(predicates::str::contains(month.to_string())); 150 | } 151 | Ok(()) 152 | } 153 | 154 | // -------------------------------------------------- 155 | fn run(args: &[&str], expected_file: &str) -> TestResult { 156 | let expected = fs::read_to_string(expected_file)?; 157 | Command::cargo_bin(PRG)? 158 | .args(args) 159 | .assert() 160 | .success() 161 | .stdout(expected); 162 | Ok(()) 163 | } 164 | 165 | // -------------------------------------------------- 166 | #[test] 167 | fn default_one_month() -> TestResult { 168 | let cmd = Command::cargo_bin(PRG)?.assert().success(); 169 | let out = cmd.get_output(); 170 | let stdout = String::from_utf8(out.stdout.clone())?; 171 | let lines: Vec<_> = stdout.split("\n").collect(); 172 | assert_eq!(lines.len(), 9); 173 | assert_eq!(lines[0].len(), 22); 174 | Ok(()) 175 | } 176 | 177 | // -------------------------------------------------- 178 | #[test] 179 | fn test_2_2020_leap_year() -> TestResult { 180 | run(&["-m", "2", "2020"], "tests/expected/2-2020.txt") 181 | } 182 | 183 | // -------------------------------------------------- 184 | #[test] 185 | fn test_4_2020() -> TestResult { 186 | run(&["-m", "4", "2020"], "tests/expected/4-2020.txt") 187 | } 188 | 189 | // -------------------------------------------------- 190 | #[test] 191 | fn test_april_2020() -> TestResult { 192 | run(&["2020", "-m", "april"], "tests/expected/4-2020.txt") 193 | } 194 | 195 | // -------------------------------------------------- 196 | #[test] 197 | fn test_2020() -> TestResult { 198 | run(&["2020"], "tests/expected/2020.txt") 199 | } 200 | 201 | // -------------------------------------------------- 202 | #[test] 203 | fn year() -> TestResult { 204 | let cmd = Command::cargo_bin(PRG)?.arg("-y").assert().success(); 205 | let stdout = String::from_utf8(cmd.get_output().stdout.clone())?; 206 | let lines: Vec<&str> = stdout.split("\n").collect(); 207 | assert_eq!(lines.len(), 37); 208 | Ok(()) 209 | } 210 | -------------------------------------------------------------------------------- /09-grepr/src/lib.rs: -------------------------------------------------------------------------------- 1 | use clap::{App, Arg}; 2 | use regex::{Regex, RegexBuilder}; 3 | use std::{ 4 | error::Error, 5 | fs::{self, File}, 6 | io::{self, BufRead, BufReader}, 7 | mem, 8 | }; 9 | use walkdir::WalkDir; 10 | 11 | type MyResult = Result>; 12 | 13 | #[derive(Debug)] 14 | pub struct Config { 15 | pattern: Regex, 16 | files: Vec, 17 | recursive: bool, 18 | count: bool, 19 | invert_match: bool, 20 | } 21 | 22 | pub fn get_args() -> MyResult { 23 | let matches = App::new("grepr") 24 | .version("0.1.0") 25 | .author("Ken Youens-Clark ") 26 | .about("Rust grep") 27 | .arg( 28 | Arg::with_name("pattern") 29 | .value_name("PATTERN") 30 | .help("Search pattern") 31 | .required(true), 32 | ) 33 | .arg( 34 | Arg::with_name("files") 35 | .value_name("FILE") 36 | .help("Input file(s)") 37 | .multiple(true) 38 | .default_value("-"), 39 | ) 40 | .arg( 41 | Arg::with_name("insensitive") 42 | .short("i") 43 | .long("insensitive") 44 | .help("Case-insensitive") 45 | .takes_value(false), 46 | ) 47 | .arg( 48 | Arg::with_name("recursive") 49 | .short("r") 50 | .long("recursive") 51 | .help("Recursive search") 52 | .takes_value(false), 53 | ) 54 | .arg( 55 | Arg::with_name("count") 56 | .short("c") 57 | .long("count") 58 | .help("Count occurrences") 59 | .takes_value(false), 60 | ) 61 | .arg( 62 | Arg::with_name("invert") 63 | .short("v") 64 | .long("invert-match") 65 | .help("Invert match") 66 | .takes_value(false), 67 | ) 68 | .get_matches(); 69 | 70 | let pattern = matches.value_of("pattern").unwrap(); 71 | let pattern = RegexBuilder::new(pattern) 72 | .case_insensitive(matches.is_present("insensitive")) 73 | .build() 74 | .map_err(|_| format!("Invalid pattern \"{}\"", pattern))?; 75 | 76 | Ok(Config { 77 | pattern, 78 | files: matches.values_of_lossy("files").unwrap(), 79 | recursive: matches.is_present("recursive"), 80 | count: matches.is_present("count"), 81 | invert_match: matches.is_present("invert"), 82 | }) 83 | } 84 | 85 | pub fn run(config: Config) -> MyResult<()> { 86 | // println!("{:#?}", config); 87 | 88 | let entries = find_files(&config.files, config.recursive); 89 | let num_files = entries.len(); 90 | let print = |fname: &str, val: &str| { 91 | if num_files > 1 { 92 | print!("{}:{}", fname, val); 93 | } else { 94 | print!("{}", val); 95 | } 96 | }; 97 | 98 | for entry in entries { 99 | match entry { 100 | Err(e) => eprintln!("{}", e), 101 | Ok(filename) => match open(&filename) { 102 | Err(e) => eprintln!("{}: {}", filename, e), 103 | Ok(file) => { 104 | match find_lines( 105 | file, 106 | &config.pattern, 107 | config.invert_match, 108 | ) { 109 | Err(e) => eprintln!("{}", e), 110 | Ok(matches) => { 111 | if config.count { 112 | print( 113 | &filename, 114 | &format!("{}\n", matches.len()), 115 | ); 116 | } else { 117 | for line in &matches { 118 | print(&filename, line); 119 | } 120 | } 121 | } 122 | } 123 | } 124 | }, 125 | } 126 | } 127 | Ok(()) 128 | } 129 | 130 | fn open(filename: &str) -> MyResult> { 131 | match filename { 132 | "-" => Ok(Box::new(BufReader::new(io::stdin()))), 133 | _ => Ok(Box::new(BufReader::new(File::open(filename)?))), 134 | } 135 | } 136 | 137 | fn find_files(paths: &[String], recursive: bool) -> Vec> { 138 | let mut results = vec![]; 139 | 140 | for path in paths { 141 | match path.as_str() { 142 | "-" => results.push(Ok(path.to_string())), 143 | _ => match fs::metadata(path) { 144 | Ok(metadata) => { 145 | if metadata.is_dir() { 146 | if recursive { 147 | for entry in WalkDir::new(path) 148 | .into_iter() 149 | .flatten() 150 | .filter(|e| e.file_type().is_file()) 151 | { 152 | results.push(Ok(entry 153 | .path() 154 | .display() 155 | .to_string())); 156 | } 157 | } else { 158 | results.push(Err(From::from(format!( 159 | "{} is a directory", 160 | path 161 | )))); 162 | } 163 | } else if metadata.is_file() { 164 | results.push(Ok(path.to_string())); 165 | } 166 | } 167 | Err(e) => { 168 | results.push(Err(From::from(format!("{}: {}", path, e)))) 169 | } 170 | }, 171 | } 172 | } 173 | 174 | results 175 | } 176 | 177 | fn find_lines( 178 | mut file: T, 179 | pattern: &Regex, 180 | invert_match: bool, 181 | ) -> MyResult> { 182 | let mut matches = vec![]; 183 | let mut line = String::new(); 184 | 185 | loop { 186 | let bytes = file.read_line(&mut line)?; 187 | if bytes == 0 { 188 | break; 189 | } 190 | if pattern.is_match(&line) ^ invert_match { 191 | matches.push(mem::take(&mut line)); 192 | } 193 | line.clear(); 194 | } 195 | 196 | Ok(matches) 197 | } -------------------------------------------------------------------------------- /05-wcr/tests/cli.rs: -------------------------------------------------------------------------------- 1 | use assert_cmd::Command; 2 | use predicates::prelude::*; 3 | use rand::{distributions::Alphanumeric, Rng}; 4 | use std::fs; 5 | 6 | type TestResult = Result<(), Box>; 7 | 8 | const PRG: &str = "wcr"; 9 | const EMPTY: &str = "tests/inputs/empty.txt"; 10 | const FOX: &str = "tests/inputs/fox.txt"; 11 | const ATLAMAL: &str = "tests/inputs/atlamal.txt"; 12 | 13 | // -------------------------------------------------- 14 | fn gen_bad_file() -> String { 15 | loop { 16 | let filename = rand::thread_rng() 17 | .sample_iter(&Alphanumeric) 18 | .take(7) 19 | .map(char::from) 20 | .collect(); 21 | 22 | if fs::metadata(&filename).is_err() { 23 | return filename; 24 | } 25 | } 26 | } 27 | 28 | // -------------------------------------------------- 29 | #[test] 30 | fn dies_chars_and_bytes() -> TestResult { 31 | Command::cargo_bin(PRG)? 32 | .args(&["-m", "-c"]) 33 | .assert() 34 | .failure() 35 | .stderr(predicate::str::contains( 36 | "The argument '--bytes' cannot be used with '--chars'", 37 | )); 38 | Ok(()) 39 | } 40 | 41 | // -------------------------------------------------- 42 | fn run(args: &[&str], expected_file: &str) -> TestResult { 43 | let expected = fs::read_to_string(expected_file)?; 44 | Command::cargo_bin(PRG)? 45 | .args(args) 46 | .assert() 47 | .success() 48 | .stdout(expected); 49 | Ok(()) 50 | } 51 | 52 | // -------------------------------------------------- 53 | #[test] 54 | fn skips_bad_file() -> TestResult { 55 | let bad = gen_bad_file(); 56 | let expected = format!("{}: .* [(]os error 2[)]", bad); 57 | Command::cargo_bin(PRG)? 58 | .arg(bad) 59 | .assert() 60 | .success() 61 | .stderr(predicate::str::is_match(expected)?); 62 | Ok(()) 63 | } 64 | 65 | // -------------------------------------------------- 66 | #[test] 67 | fn empty() -> TestResult { 68 | run(&[EMPTY], "tests/expected/empty.txt.out") 69 | } 70 | 71 | // -------------------------------------------------- 72 | #[test] 73 | fn fox() -> TestResult { 74 | run(&[FOX], "tests/expected/fox.txt.out") 75 | } 76 | 77 | // -------------------------------------------------- 78 | #[test] 79 | fn fox_bytes() -> TestResult { 80 | run(&["--bytes", FOX], "tests/expected/fox.txt.c.out") 81 | } 82 | 83 | // -------------------------------------------------- 84 | #[test] 85 | fn fox_chars() -> TestResult { 86 | run(&["--chars", FOX], "tests/expected/fox.txt.m.out") 87 | } 88 | 89 | // -------------------------------------------------- 90 | #[test] 91 | fn fox_words() -> TestResult { 92 | run(&["--words", FOX], "tests/expected/fox.txt.w.out") 93 | } 94 | 95 | // -------------------------------------------------- 96 | #[test] 97 | fn fox_lines() -> TestResult { 98 | run(&["--lines", FOX], "tests/expected/fox.txt.l.out") 99 | } 100 | 101 | // -------------------------------------------------- 102 | #[test] 103 | fn fox_words_bytes() -> TestResult { 104 | run(&["-w", "-c", FOX], "tests/expected/fox.txt.wc.out") 105 | } 106 | 107 | // -------------------------------------------------- 108 | #[test] 109 | fn fox_words_lines() -> TestResult { 110 | run(&["-w", "-l", FOX], "tests/expected/fox.txt.wl.out") 111 | } 112 | 113 | // -------------------------------------------------- 114 | #[test] 115 | fn fox_bytes_lines() -> TestResult { 116 | run(&["-l", "-c", FOX], "tests/expected/fox.txt.cl.out") 117 | } 118 | 119 | // -------------------------------------------------- 120 | #[test] 121 | fn atlamal() -> TestResult { 122 | run(&[ATLAMAL], "tests/expected/atlamal.txt.out") 123 | } 124 | 125 | // -------------------------------------------------- 126 | #[test] 127 | fn atlamal_bytes() -> TestResult { 128 | run(&["-c", ATLAMAL], "tests/expected/atlamal.txt.c.out") 129 | } 130 | 131 | // -------------------------------------------------- 132 | #[test] 133 | fn atlamal_words() -> TestResult { 134 | run(&["-w", ATLAMAL], "tests/expected/atlamal.txt.w.out") 135 | } 136 | 137 | // -------------------------------------------------- 138 | #[test] 139 | fn atlamal_lines() -> TestResult { 140 | run(&["-l", ATLAMAL], "tests/expected/atlamal.txt.l.out") 141 | } 142 | 143 | // -------------------------------------------------- 144 | #[test] 145 | fn atlamal_words_bytes() -> TestResult { 146 | run(&["-w", "-c", ATLAMAL], "tests/expected/atlamal.txt.wc.out") 147 | } 148 | 149 | // -------------------------------------------------- 150 | #[test] 151 | fn atlamal_words_lines() -> TestResult { 152 | run(&["-w", "-l", ATLAMAL], "tests/expected/atlamal.txt.wl.out") 153 | } 154 | 155 | // -------------------------------------------------- 156 | #[test] 157 | fn atlamal_bytes_lines() -> TestResult { 158 | run(&["-l", "-c", ATLAMAL], "tests/expected/atlamal.txt.cl.out") 159 | } 160 | 161 | // -------------------------------------------------- 162 | #[test] 163 | fn atlamal_stdin() -> TestResult { 164 | let input = fs::read_to_string(ATLAMAL)?; 165 | let expected = 166 | fs::read_to_string("tests/expected/atlamal.txt.stdin.out")?; 167 | Command::cargo_bin(PRG)? 168 | .write_stdin(input) 169 | .assert() 170 | .stdout(expected); 171 | Ok(()) 172 | } 173 | 174 | // -------------------------------------------------- 175 | #[test] 176 | fn test_all() -> TestResult { 177 | run(&[EMPTY, FOX, ATLAMAL], "tests/expected/all.out") 178 | } 179 | 180 | // -------------------------------------------------- 181 | #[test] 182 | fn test_all_lines() -> TestResult { 183 | run(&["-l", EMPTY, FOX, ATLAMAL], "tests/expected/all.l.out") 184 | } 185 | 186 | // -------------------------------------------------- 187 | #[test] 188 | fn test_all_words() -> TestResult { 189 | run(&["-w", EMPTY, FOX, ATLAMAL], "tests/expected/all.w.out") 190 | } 191 | 192 | // -------------------------------------------------- 193 | #[test] 194 | fn test_all_bytes() -> TestResult { 195 | run(&["-c", EMPTY, FOX, ATLAMAL], "tests/expected/all.c.out") 196 | } 197 | 198 | // -------------------------------------------------- 199 | #[test] 200 | fn test_all_words_bytes() -> TestResult { 201 | run(&["-cw", EMPTY, FOX, ATLAMAL], "tests/expected/all.wc.out") 202 | } 203 | 204 | // -------------------------------------------------- 205 | #[test] 206 | fn test_all_words_lines() -> TestResult { 207 | run(&["-wl", EMPTY, FOX, ATLAMAL], "tests/expected/all.wl.out") 208 | } 209 | 210 | // -------------------------------------------------- 211 | #[test] 212 | fn test_all_bytes_lines() -> TestResult { 213 | run(&["-cl", EMPTY, FOX, ATLAMAL], "tests/expected/all.cl.out") 214 | } 215 | -------------------------------------------------------------------------------- /14-lsr/tests/cli.rs: -------------------------------------------------------------------------------- 1 | use assert_cmd::Command; 2 | use predicates::prelude::*; 3 | use rand::{distributions::Alphanumeric, Rng}; 4 | use std::{error::Error, fs}; 5 | 6 | type TestResult = Result<(), Box>; 7 | 8 | const PRG: &str = "lsr"; 9 | const HIDDEN: &str = "tests/inputs/.hidden"; 10 | const EMPTY: &str = "tests/inputs/empty.txt"; 11 | const BUSTLE: &str = "tests/inputs/bustle.txt"; 12 | const FOX: &str = "tests/inputs/fox.txt"; 13 | 14 | // -------------------------------------------------- 15 | fn gen_bad_file() -> String { 16 | loop { 17 | let filename: String = rand::thread_rng() 18 | .sample_iter(&Alphanumeric) 19 | .take(7) 20 | .map(char::from) 21 | .collect(); 22 | 23 | if fs::metadata(&filename).is_err() { 24 | return filename; 25 | } 26 | } 27 | } 28 | 29 | // -------------------------------------------------- 30 | #[test] 31 | fn bad_file() -> TestResult { 32 | let bad = gen_bad_file(); 33 | let expected = 34 | format!("{}: No such file or directory (os error 2)", &bad); 35 | Command::cargo_bin(PRG)? 36 | .arg(&bad) 37 | .assert() 38 | .success() 39 | .stderr(predicate::str::contains(expected)); 40 | Ok(()) 41 | } 42 | 43 | // -------------------------------------------------- 44 | #[test] 45 | fn no_args() -> TestResult { 46 | // Uses current directory by default 47 | Command::cargo_bin(PRG)? 48 | .assert() 49 | .success() 50 | .stdout(predicate::str::contains("Cargo.toml")); 51 | Ok(()) 52 | } 53 | 54 | // -------------------------------------------------- 55 | fn run_short(arg: &str) -> TestResult { 56 | Command::cargo_bin(PRG)? 57 | .arg(arg) 58 | .assert() 59 | .success() 60 | .stdout(format!("{}\n", arg)); 61 | Ok(()) 62 | } 63 | 64 | // -------------------------------------------------- 65 | fn run_long(filename: &str, permissions: &str, size: &str) -> TestResult { 66 | let cmd = Command::cargo_bin(PRG)? 67 | .args(&["--long", filename]) 68 | .assert() 69 | .success(); 70 | let stdout = String::from_utf8(cmd.get_output().stdout.clone())?; 71 | let parts: Vec<_> = stdout.split_whitespace().collect(); 72 | assert_eq!(parts.get(0).unwrap(), &permissions); 73 | assert_eq!(parts.get(4).unwrap(), &size); 74 | assert_eq!(parts.last().unwrap(), &filename); 75 | Ok(()) 76 | } 77 | 78 | // -------------------------------------------------- 79 | #[test] 80 | fn empty() -> TestResult { 81 | run_short(EMPTY) 82 | } 83 | 84 | #[test] 85 | fn empty_long() -> TestResult { 86 | run_long(EMPTY, "-rw-r--r--", "0") 87 | } 88 | 89 | // -------------------------------------------------- 90 | #[test] 91 | fn bustle() -> TestResult { 92 | run_short(BUSTLE) 93 | } 94 | 95 | #[test] 96 | fn bustle_long() -> TestResult { 97 | run_long(BUSTLE, "-rw-r--r--", "193") 98 | } 99 | 100 | // -------------------------------------------------- 101 | #[test] 102 | fn fox() -> TestResult { 103 | run_short(FOX) 104 | } 105 | 106 | #[test] 107 | fn fox_long() -> TestResult { 108 | run_long(FOX, "-rw-------", "45") 109 | } 110 | 111 | // -------------------------------------------------- 112 | #[test] 113 | fn hidden() -> TestResult { 114 | run_short(HIDDEN) 115 | } 116 | 117 | #[test] 118 | fn hidden_long() -> TestResult { 119 | run_long(HIDDEN, "-rw-r--r--", "0") 120 | } 121 | 122 | // -------------------------------------------------- 123 | fn dir_short(args: &[&str], expected: &[&str]) -> TestResult { 124 | let cmd = Command::cargo_bin(PRG)?.args(args).assert().success(); 125 | let stdout = String::from_utf8(cmd.get_output().stdout.clone())?; 126 | let lines: Vec<&str> = 127 | stdout.split("\n").filter(|s| !s.is_empty()).collect(); 128 | assert_eq!(lines.len(), expected.len()); 129 | for filename in expected { 130 | assert!(lines.contains(&filename)); 131 | } 132 | Ok(()) 133 | } 134 | 135 | #[test] 136 | fn dir1() -> TestResult { 137 | dir_short( 138 | &["tests/inputs"], 139 | &[ 140 | "tests/inputs/empty.txt", 141 | "tests/inputs/bustle.txt", 142 | "tests/inputs/fox.txt", 143 | "tests/inputs/dir", 144 | ], 145 | ) 146 | } 147 | 148 | #[test] 149 | fn dir1_all() -> TestResult { 150 | dir_short( 151 | &["tests/inputs", "--all"], 152 | &[ 153 | "tests/inputs/empty.txt", 154 | "tests/inputs/bustle.txt", 155 | "tests/inputs/fox.txt", 156 | "tests/inputs/.hidden", 157 | "tests/inputs/dir", 158 | ], 159 | ) 160 | } 161 | 162 | #[test] 163 | fn dir2() -> TestResult { 164 | dir_short(&["tests/inputs/dir"], &["tests/inputs/dir/spiders.txt"]) 165 | } 166 | 167 | #[test] 168 | fn dir2_all() -> TestResult { 169 | dir_short( 170 | &["-a", "tests/inputs/dir"], 171 | &["tests/inputs/dir/spiders.txt", "tests/inputs/dir/.gitkeep"], 172 | ) 173 | } 174 | 175 | // -------------------------------------------------- 176 | fn dir_long(args: &[&str], expected: &[(&str, &str, &str)]) -> TestResult { 177 | let cmd = Command::cargo_bin(PRG)?.args(args).assert().success(); 178 | let stdout = String::from_utf8(cmd.get_output().stdout.clone())?; 179 | let lines: Vec<&str> = 180 | stdout.split("\n").filter(|s| !s.is_empty()).collect(); 181 | assert_eq!(lines.len(), expected.len()); 182 | 183 | let mut check = vec![]; 184 | for line in lines { 185 | let parts: Vec<_> = line.split_whitespace().collect(); 186 | let path = parts.last().unwrap().clone(); 187 | let permissions = parts.get(0).unwrap().clone(); 188 | let size = match permissions.chars().next() { 189 | Some('d') => "", 190 | _ => parts.get(4).unwrap().clone(), 191 | }; 192 | check.push((path, permissions, size)); 193 | } 194 | 195 | for entry in expected { 196 | assert!(check.contains(entry)); 197 | } 198 | 199 | Ok(()) 200 | } 201 | 202 | // -------------------------------------------------- 203 | #[test] 204 | fn dir1_long() -> TestResult { 205 | dir_long( 206 | &["-l", "tests/inputs"], 207 | &[ 208 | ("tests/inputs/empty.txt", "-rw-r--r--", "0"), 209 | ("tests/inputs/bustle.txt", "-rw-r--r--", "193"), 210 | ("tests/inputs/fox.txt", "-rw-------", "45"), 211 | ("tests/inputs/dir", "drwxr-xr-x", ""), 212 | ], 213 | ) 214 | } 215 | 216 | #[test] 217 | fn dir1_long_all() -> TestResult { 218 | dir_long( 219 | &["-la", "tests/inputs"], 220 | &[ 221 | ("tests/inputs/empty.txt", "-rw-r--r--", "0"), 222 | ("tests/inputs/bustle.txt", "-rw-r--r--", "193"), 223 | ("tests/inputs/fox.txt", "-rw-------", "45"), 224 | ("tests/inputs/dir", "drwxr-xr-x", ""), 225 | ("tests/inputs/.hidden", "-rw-r--r--", "0"), 226 | ], 227 | ) 228 | } 229 | 230 | #[test] 231 | fn dir2_long() -> TestResult { 232 | dir_long( 233 | &["--long", "tests/inputs/dir"], 234 | &[("tests/inputs/dir/spiders.txt", "-rw-r--r--", "45")], 235 | ) 236 | } 237 | 238 | #[test] 239 | fn dir2_long_all() -> TestResult { 240 | dir_long( 241 | &["tests/inputs/dir", "--long", "--all"], 242 | &[ 243 | ("tests/inputs/dir/spiders.txt", "-rw-r--r--", "45"), 244 | ("tests/inputs/dir/.gitkeep", "-rw-r--r--", "0"), 245 | ], 246 | ) 247 | } 248 | -------------------------------------------------------------------------------- /11-tailr/src/lib.rs: -------------------------------------------------------------------------------- 1 | use crate::TakeValue::*; 2 | use clap::{App, Arg}; 3 | use once_cell::sync::OnceCell; 4 | use regex::Regex; 5 | use std::{ 6 | error::Error, 7 | fs::File, 8 | io::{BufRead, BufReader, Read, Seek, SeekFrom}, 9 | }; 10 | 11 | type MyResult = Result>; 12 | 13 | static NUM_RE: OnceCell = OnceCell::new(); 14 | 15 | #[derive(Debug, PartialEq)] 16 | enum TakeValue { 17 | PlusZero, 18 | TakeNum(i64), 19 | } 20 | 21 | #[derive(Debug)] 22 | pub struct Config { 23 | files: Vec, 24 | lines: TakeValue, 25 | bytes: Option, 26 | quiet: bool, 27 | } 28 | 29 | // -------------------------------------------------- 30 | pub fn get_args() -> MyResult { 31 | let matches = App::new("tailr") 32 | .version("0.1.0") 33 | .author("Ken Youens-Clark ") 34 | .about("Rust tail") 35 | .arg( 36 | Arg::with_name("files") 37 | .value_name("FILE") 38 | .help("Input file(s)") 39 | .required(true) 40 | .multiple(true), 41 | ) 42 | .arg( 43 | Arg::with_name("lines") 44 | .short("n") 45 | .long("lines") 46 | .value_name("LINES") 47 | .help("Number of lines") 48 | .default_value("10"), 49 | ) 50 | .arg( 51 | Arg::with_name("bytes") 52 | .short("c") 53 | .long("bytes") 54 | .value_name("BYTES") 55 | .conflicts_with("lines") 56 | .help("Number of bytes"), 57 | ) 58 | .arg( 59 | Arg::with_name("quiet") 60 | .short("q") 61 | .long("quiet") 62 | .help("Suppress headers"), 63 | ) 64 | .get_matches(); 65 | 66 | let lines = matches 67 | .value_of("lines") 68 | .map(parse_num) 69 | .transpose() 70 | .map_err(|e| format!("illegal line count -- {}", e))?; 71 | 72 | let bytes = matches 73 | .value_of("bytes") 74 | .map(parse_num) 75 | .transpose() 76 | .map_err(|e| format!("illegal byte count -- {}", e))?; 77 | 78 | Ok(Config { 79 | files: matches.values_of_lossy("files").unwrap(), 80 | lines: lines.unwrap(), 81 | bytes, 82 | quiet: matches.is_present("quiet"), 83 | }) 84 | } 85 | 86 | // -------------------------------------------------- 87 | pub fn run(config: Config) -> MyResult<()> { 88 | let num_files = config.files.len(); 89 | for (file_num, filename) in config.files.iter().enumerate() { 90 | match File::open(filename) { 91 | Err(err) => eprintln!("{}: {}", filename, err), 92 | Ok(file) => { 93 | if !config.quiet && num_files > 1 { 94 | println!( 95 | "{}==> {} <==", 96 | if file_num > 0 { "\n" } else { "" }, 97 | filename 98 | ); 99 | } 100 | 101 | let (total_lines, total_bytes) = count_lines_bytes(filename)?; 102 | let file = BufReader::new(file); 103 | if let Some(num_bytes) = &config.bytes { 104 | print_bytes(file, num_bytes, total_bytes)?; 105 | } else { 106 | print_lines(file, &config.lines, total_lines)?; 107 | } 108 | } 109 | } 110 | } 111 | 112 | Ok(()) 113 | } 114 | 115 | // -------------------------------------------------- 116 | fn parse_num(val: &str) -> MyResult { 117 | let num_re = 118 | NUM_RE.get_or_init(|| Regex::new(r"^([+-])?(\d+)$").unwrap()); 119 | 120 | match num_re.captures(val) { 121 | Some(caps) => { 122 | let sign = caps.get(1).map_or("-", |m| m.as_str()); 123 | let num = format!("{}{}", sign, caps.get(2).unwrap().as_str()); 124 | if let Ok(val) = num.parse() { 125 | if sign == "+" && val == 0 { 126 | Ok(PlusZero) 127 | } else { 128 | Ok(TakeNum(val)) 129 | } 130 | } else { 131 | Err(From::from(val)) 132 | } 133 | } 134 | _ => Err(From::from(val)), 135 | } 136 | } 137 | 138 | // -------------------------------------------------- 139 | // We have to specify the type and assign to a variable here because 140 | // &['+', '-'] has the type &[char; 2], and we want to coerce it to 141 | // a slice, not a reference to an array. 142 | // 143 | // One day in the future we will be able to say 144 | // val.starts_with(['+', '-'].as_slice()) 145 | // but array_methods are currently an unstable nightly feature. 146 | //fn parse_num(val: &str) -> MyResult { 147 | // let signs: &[char] = &['+', '-']; 148 | // let res = val 149 | // .starts_with(signs) 150 | // .then(|| val.parse()) 151 | // .unwrap_or_else(|| val.parse().map(i64::wrapping_neg)); 152 | 153 | // match res { 154 | // Ok(num) => { 155 | // if num == 0 && val.starts_with('+') { 156 | // Ok(PlusZero) 157 | // } else { 158 | // Ok(TakeNum(num)) 159 | // } 160 | // } 161 | // _ => Err(From::from(val)), 162 | // } 163 | //} 164 | 165 | // -------------------------------------------------- 166 | fn count_lines_bytes(filename: &str) -> MyResult<(i64, i64)> { 167 | let mut file = BufReader::new(File::open(filename)?); 168 | let mut num_lines = 0; 169 | let mut num_bytes = 0; 170 | let mut buf = Vec::new(); 171 | loop { 172 | let bytes_read = file.read_until(b'\n', &mut buf)?; 173 | if bytes_read == 0 { 174 | break; 175 | } 176 | num_lines += 1; 177 | num_bytes += bytes_read as i64; 178 | buf.clear(); 179 | } 180 | Ok((num_lines, num_bytes)) 181 | } 182 | 183 | // -------------------------------------------------- 184 | fn print_bytes( 185 | mut file: T, 186 | num_bytes: &TakeValue, 187 | total_bytes: i64, 188 | ) -> MyResult<()> { 189 | if let Some(start) = get_start_index(num_bytes, total_bytes) { 190 | file.seek(SeekFrom::Start(start))?; 191 | let mut buffer = Vec::new(); 192 | file.read_to_end(&mut buffer)?; 193 | if !buffer.is_empty() { 194 | print!("{}", String::from_utf8_lossy(&buffer)); 195 | } 196 | } 197 | 198 | Ok(()) 199 | } 200 | 201 | // -------------------------------------------------- 202 | fn print_lines( 203 | mut file: impl BufRead, 204 | num_lines: &TakeValue, 205 | total_lines: i64, 206 | ) -> MyResult<()> { 207 | if let Some(start) = get_start_index(num_lines, total_lines) { 208 | let mut line_num = 0; 209 | let mut buf = Vec::new(); 210 | loop { 211 | let bytes_read = file.read_until(b'\n', &mut buf)?; 212 | if bytes_read == 0 { 213 | break; 214 | } 215 | if line_num >= start { 216 | print!("{}", String::from_utf8_lossy(&buf)); 217 | } 218 | line_num += 1; 219 | buf.clear(); 220 | } 221 | } 222 | 223 | Ok(()) 224 | } 225 | 226 | // -------------------------------------------------- 227 | fn get_start_index(take_val: &TakeValue, total: i64) -> Option { 228 | match take_val { 229 | PlusZero => { 230 | if total > 0 { 231 | Some(0) 232 | } else { 233 | None 234 | } 235 | } 236 | TakeNum(num) => { 237 | if num == &0 || total == 0 || num > &total { 238 | None 239 | } else { 240 | let start = if num < &0 { total + num } else { num - 1 }; 241 | Some(if start < 0 { 0 } else { start as u64 }) 242 | } 243 | } 244 | } 245 | } 246 | --------------------------------------------------------------------------------