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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
#[macro_use]
extern crate clap;
use std::fs::File;
use std::path::Path;
use std::io::*;
use std::path::PathBuf;
use clap::{App, Arg};
mod config;
struct FileTypeStats{
file_type: String,
count: i64,
}
fn omit_line(line: String, in_comment_section: &mut bool, comment_tokens: &config::CommentTokens) -> bool {
let s = line.trim();
let begin_comment_section = s.starts_with(comment_tokens.begin_comment_block.as_str());
let end_comment_section = s.starts_with(comment_tokens.end_comment_block.as_str());
if begin_comment_section {
*in_comment_section = true;
return true;
}
else if *in_comment_section && !end_comment_section {
return true;
}
else if *in_comment_section && end_comment_section {
*in_comment_section = false;
return true;
}
s.starts_with(comment_tokens.single_line.as_str()) || s.is_empty()
}
fn get_config<'a>(config: &'a Vec<config::CommentTokens>, extension: &str) -> Option<&'a config::CommentTokens> {
for conf in config.iter() {
if conf.file_ending == extension {
return Some(conf);
}
}
None
}
fn count_lines(filename: &str, file_type_stats: &mut Vec<FileTypeStats>,
config: &mut Vec<config::CommentTokens>) -> Result<i64>{
let mut sum = 0;
let mut in_comment_section = false;
let extension = match Path::new(filename).extension() {
Some(ext) => ext.to_str().unwrap(),
None => return Err(Error::new(std::io::ErrorKind::Other, "could not get file extension")),
};
let comment_tokens = match get_config(&config, extension) {
Some(conf) => conf,
None => return Err(Error::new(std::io::ErrorKind::NotFound, "config not found")),
};
let bufread = BufReader::new(try!(File::open(filename)));
for line in bufread.lines() {
if omit_line(try!(line), &mut in_comment_section, &comment_tokens) {
continue;
}
sum += 1;
}
let mut to_add = false;
{
let file = file_type_stats.iter_mut().find(|x| x.file_type == extension);
match file {
Some(mut e) => e.count += sum,
None => to_add = true,
}
}
if to_add {
file_type_stats.push(FileTypeStats { file_type: extension.to_string(), count: sum });
}
Ok(sum)
}
fn count_files_for_dir(dir: PathBuf, mut file_types: &mut Vec<FileTypeStats>,
mut config: &mut Vec<config::CommentTokens>) {
match dir.read_dir() {
Ok(iter) => {
for entry in iter {
match entry {
Ok(i) => {
if i.path().is_dir() {
count_files_for_dir(i.path(),
&mut file_types, &mut config);
}
else {
count_lines_for_file(i.path().to_str().unwrap(),
&mut file_types, &mut config);
} },
Err(e) => println!("error: {}", e),
}
}
},
Err(e) => println!("error: {}", e),
}
}
fn count_lines_for_file(filename: &str, mut file_type_stats: &mut Vec<FileTypeStats>,
mut config: &mut Vec<config::CommentTokens>) {
match count_lines(filename, &mut file_type_stats, &mut config) {
Ok(i) => {
println!("{}\t: {}", i, filename);
},
Err(e) => println!("error for file {}: {}", filename, e),
}
}
fn main() {
let m = App::new("loc").about("Count lines of code. Without parameter read recursive all \
files from current directory and count lines of code\
for each")
.version(crate_version!())
.author(crate_authors!())
.arg(Arg::with_name("file")
.help("files to count lines of code")
.short("f")
.long("file")
.takes_value(true)
.multiple(true))
.arg(Arg::with_name("summary")
.help("Print a summary for each file type")
.short("s")
.long("summary"))
.get_matches();
let mut config = match config::read_config() {
Err(e) => panic!("error reading config file(s): {}", e),
Ok(i) => i,
};
let mut file_types = Vec::new();
if let Some(files) = m.values_of("file") {
for file in files {
count_lines_for_file(file, &mut file_types, &mut config)
}
}
else {
match std::env::current_dir() {
Ok(i) => count_files_for_dir(i, &mut file_types, &mut config),
Err(e) => panic!("could not determine current dir: {}", e),
}
}
if m.is_present("summary") {
let mut sum = 0;
for f in file_types {
println!("{}\t: *.{}", f.count, f.file_type);
sum += f.count;
}
println!("{}\t: total", sum);
}
}
|