1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
mod args;
mod zip;
use std::fs::File;
use std::io;
use std::process::ExitCode;
fn guess_parser(args: &mut dyn Iterator<Item = String>) -> Box<dyn args::Parser> {
for arg in args {
if arg.len() > 2 && arg.starts_with("--") {
// --C.. can only be ShortAndLong
return Box::new(args::ShortAndLongParser::new());
}
}
// TODO: Can we make more guesses?
Box::new(args::LongOnlyParser::new())
}
struct Program {
classname: String,
args: Vec<String>,
classpath: String,
verbose: bool,
}
fn parse_args() -> Result<Option<Program>, String> {
let mut options = args::Options::new();
let help_idx = options.push(
args::OptionBuilder::default()
.short('h')
.long("help")
.description("display this and exit")
.build()
.unwrap(),
);
let version_idx = options.push(
args::OptionBuilder::default()
.short('V')
.long("version")
.description("display version and exit")
.build()
.unwrap(),
);
let verbose_idx = options.push(
args::OptionBuilder::default()
.long("verbose")
.description("be verbose")
.build()
.unwrap(),
);
let cp_idx = options.push(
args::OptionBuilder::default()
.long("cp")
.description("class search path of directories and zip/jar files")
.value(args::ValueRequirement::Required("CLASSPATH"))
.build()
.unwrap(),
);
let classpath_idx = options.push(
args::OptionBuilder::default()
.long("classpath")
.description("class search path of directories and zip/jar files")
.value(args::ValueRequirement::Required("CLASSPATH"))
.build()
.unwrap(),
);
let parser = guess_parser(&mut std::env::args());
let maybe_args = parser.run(&mut options, &mut std::env::args());
// help is special, check for it even if parser#run returned error.
let help = &options[help_idx];
if help.is_set() {
parser.print_help(&options);
return Ok(None);
}
let args = maybe_args?;
let version = &options[version_idx];
if version.is_set() {
println!("Version is 0.0.1");
return Ok(None);
}
let verbose = &options[verbose_idx];
let cp = &options[cp_idx];
let classpath = &options[classpath_idx];
let actual_classpath: &str;
if cp.is_set() {
if classpath.is_set() {
return Err("Both -cp and -classpath set, pick one.".to_string());
}
actual_classpath = cp.value().as_ref().unwrap();
} else if classpath.is_set() {
actual_classpath = classpath.value().as_ref().unwrap();
} else {
actual_classpath = "";
}
let mut run_args = args.args.iter();
if let Some(classname) = run_args.next() {
Ok(Some(Program {
classname: classname.clone(),
args: run_args.map(|s| s.clone()).collect(),
classpath: actual_classpath.to_string(),
verbose: verbose.is_set(),
}))
} else {
Err("Missing class name".to_string())
}
}
fn run(program: Program) -> io::Result<ExitCode> {
let mut paths = program.classpath.split(':');
let mut file = File::open(paths.next().unwrap())?;
let layout = zip::Layout::new(&mut file)?;
for (name, idx) in layout.names() {
let entry = &layout.entries()[*idx];
println!(
"{name}: {} {}",
entry.compressed_size(),
entry.uncompressed_size()
);
}
return Ok(ExitCode::SUCCESS);
}
fn main() -> ExitCode {
match parse_args() {
Ok(maybe_program) => match maybe_program {
Some(program) => match run(program) {
Ok(exit_code) => {
return exit_code;
}
Err(err) => {
eprintln!("{}", err);
return ExitCode::FAILURE;
}
},
None => {
return ExitCode::SUCCESS;
}
},
Err(msg) => {
eprintln!("{}", msg);
return ExitCode::FAILURE;
}
}
}
|