extern crate office; extern crate glob; use std::env; use glob::{glob, GlobError}; use office::{Excel, DataType, Error}; type MissingReference = Option; #[derive(Debug)] enum FileStatus { ExcelError(Error), VbaError(Error), RangeError(Error), Valid(MissingReference, usize), Glob(GlobError), } fn main() { // Search recursively for all excel files matching argument pattern // Output statistics: nb broken references, nb broken cells etc... let pattern = format!("{}/**/*.xl*", env::args().skip(1).next().unwrap_or(".".to_string())); let mut filecount = 0; for f in glob(&pattern).expect("Failed to read excel glob, the first \ argument must correspond to a directory") { filecount += 1; let mut status = Vec::new(); let f = match f { Ok(f) => f, Err(e) => { status.push(FileStatus::Glob(e)); continue; } }; println!("Analysing {:?}", f.display()); match Excel::open(&f) { Ok(mut xl) => { let mut missing = None; let mut cell_errors = 0; if xl.has_vba() { match xl.vba_project() { Ok(ref mut vba) => { let refs = vba.get_references(); missing = Some(refs.into_iter() .filter(|r| r.is_missing()).count()); }, Err(e) => status.push(FileStatus::VbaError(e)), } } match xl.sheet_names() { Ok(sheets) => { for s in sheets { match xl.worksheet_range(&s) { Ok(range) => { cell_errors += range.rows() .map(|r| r.iter() .map(|c| if let &DataType::Error(_) = c { 1usize } else { 0 }) .sum::()) .sum::(); }, Err(e) => status.push(FileStatus::RangeError(e)), } } }, Err(e) => status.push(FileStatus::ExcelError(e)), } status.push(FileStatus::Valid(missing, cell_errors)); }, Err(e) => status.push(FileStatus::ExcelError(e)), } println!("{:#?}\r\n", status); } println!("Found {} excel files", filecount); }