1use crate::{Format, ReadDirOptions};
2
3const HELP: &str = r#" USAGE: rd -[OPTIONS]... [FILE]
4 DESCRIPTION: List files in the given directory
5
6 ARGUMENTS:
7 -A | -D => list dotfiles (files beginning with a '.') aswell as implied entries ('.' and '..'),
8 -a | -d => list dotfiles (files beginning with a '.'),
9 -e => no formatting will be applied; colors will be,
10 -b => no color,
11 -H => no new lines,
12 -l => {
13 files will be displayed vertically and additional metadata will be tacked on
14 the metadata includes (permissions owner group size)
15 }
16 -r => reverse the FINAL file vector,
17 -u => do not apply sorting,
18 -V => list each file on a new line,
19 -Vx => create a vertical matrix with `x` length; x must be greater than 0; see ERRORS,
20
21 -h => print this menu; exit,
22 -v => print the version; exit,
23
24 ERRORS:
25 Upon an error the program will print the help menu then the error; after it will proceed to exit
26 Possible errors:
27 * If you add multiple dashes in an argument
28 * If you add an invalid argument
29 * If you add multiple directories
30 * If you pass a number less than or equal to 0 into -Vx
31 * If you pass a directory which you do not have permission to read
32 Internal errors:
33 * If Rust fails to read a directory
34 * If Rust fails to read a file to a string
35 * If Rust fails to read a file entry
36 * If Rust fails to read files metadata
37 * If Rust failed to open /etc/passwd
38 * If Rust fails to open /etc/group
39 Other:
40 * There is a .expect() which should never occur
41 as an empty file should not be queried
42 * There are a few .expect() calls after parsing a number
43 which should never error since they are checked beforehand"#;
44
45
46pub fn parse_args(args: Vec<String>) -> ReadDirOptions {
47 let mut read_dir_options = ReadDirOptions::new();
48
49 let mut expect_number = false;
50 let mut directory: Option<String> = None;
51 for arg in args {
52 if arg.starts_with("-") {
53 let arg: String = arg.chars().skip(1).collect();
54
55 let args = split(arg);
56
57 for arg in args {
58 match arg.as_str() {
59 "a" | "d" => {
60 read_dir_options.dotfiles = true;
61 }
62
63 "A" | "D" => {
64 read_dir_options.dotfiles = true;
65 read_dir_options.implied = true;
66 }
67
68 "b" => {
69 read_dir_options.colored = false;
70 }
71
72 "e" => {
73 read_dir_options.format = None;
74 }
75
76 "H" => {
77 read_dir_options.format = Some(Format::Horizontal);
78 }
79
80 "l" => {
81 read_dir_options.format = Some(Format::Long);
82 }
83
84 "r" => {
85 read_dir_options.reverse = true;
86 }
87
88 "u" => {
89 read_dir_options.sort = false;
90 }
91
92 "V" => {
93 read_dir_options.format = Some(Format::Vertical);
94 expect_number = true;
95 continue;
96 }
97
98 "h" => {
99 println!("{}", HELP);
100 std::process::exit(0);
101 }
102
103 "v" => {
104 println!(env!("CARGO_PKG_VERSION"));
105 std::process::exit(0);
106 }
107
108 "-" => {
109 println!("{}", HELP);
110 eprintln!("Error: please include only one '-'; exiting");
111 std::process::exit(1);
112 }
113
114 arg => {
115 if arg.chars().all(|c| c.is_numeric()) && expect_number {
116 read_dir_options.format = Some(Format::VerticalMatrix(
117 arg.parse()
118 .expect("This has already been checked to be a number"),
119 ));
120 } else {
121 println!("{}", HELP);
122 eprintln!("Error: unknown argument \"{arg}\"; exiting");
123 std::process::exit(1);
124 }
125 }
126 }
127 expect_number = false;
128 }
129 } else {
130 if directory.is_none() {
131 if !std::path::Path::new(&arg).is_dir() {
132 eprintln!("Error: {} is not a directory; exiting", &arg);
133 std::process::exit(1);
134 }
135 directory = Some(arg);
136 } else {
137 eprintln!("Error: multiple directory arguments; exiting");
138 std::process::exit(1);
139 }
140 }
141 }
142
143 if let Some(directory) = directory {
144 read_dir_options.directory = directory;
145 }
146
147 read_dir_options
148}
149
150fn split(str: String) -> Vec<String> {
154 let mut vec: Vec<String> = Vec::new();
155
156 let mut number = String::new();
157 for char in str.chars() {
158 if char.is_numeric() {
159 number.push(char);
160 } else {
161 if !number.is_empty() {
162 vec.push(number.clone());
163 number.clear();
164 }
165
166 vec.push(char.to_string());
167 }
168 }
169
170 vec
171}