core-utils 0.1.2

A reimplementation of the GNU core utils in the Rust programming language
// Copyright (C) 2015, Alberto Corona <ac@albertocorona.com>
// All rights reserved. This file is part of core-utils, distributed under the
// GPL v3 license. For full terms please see the LICENSE file.

#![crate_type = "bin"]
#![crate_name = "ls"]
#![feature(path_ext)]

static UTIL: Prog = Prog { name: "ls", vers: "0.1.0", yr: "2015" };

extern crate pgetopts;
extern crate rpf;

use pgetopts::{Options};
use rpf::{Status,Styled,PathMod,Prog,AsPath};

use std::fs;
use std::env;
use std::io;
use std::fs::{PathExt};
use std::path::{PathBuf};

enum Format {
    Long,
    Short,
}

fn is_dot(dir: &PathBuf) -> bool {
    if dir.as_str().starts_with(".") {
        return true;
    } else {
        return false;
    }
}

fn format_print(rel_path: &PathBuf, path: &PathBuf, format: &Format) {
    match format {
        &Format::Short => {
            if path.is_dir() {
                print!("{}/ ", rel_path.as_str().bold());
            } else {
                print!("{} ", rel_path.display());
            }
        }
        &Format::Long => {
            if path.is_dir() {
                println!("{}/ ", rel_path.as_str().bold());
            } else {
                println!("{} ", rel_path.display());
            }
        }
    };
}

fn print(path: &Vec<String>, format: Format, all: bool) -> io::Result<()> {
    for item in path.iter() {
        if !item.as_path().exists() {
            Status::Error.err(UTIL.name, String::from("\'".to_string() +
                                                      item +
                                                      "\' does not exist"));
        }
        let fpath = PathBuf::from(item);
        if fpath.is_dir() {
            for entry in try!(fs::read_dir(&fpath)) {
                let entry = try!(entry);
                let rel_path = entry.path().rel_to(&fpath);
                match format {
                    Format::Short => {
                        if all {
                            format_print(&rel_path, &entry.path(), &format);
                        } else {
                            if !is_dot(&rel_path) {
                                format_print(&rel_path, &entry.path(), &format);
                            }
                        }
                    }
                    Format::Long => {
                        if all {
                            format_print(&rel_path, &entry.path(), &format);
                        } else {
                            if !is_dot(&rel_path) {
                                format_print(&rel_path, &entry.path(), &format);
                            }
                        }
                    }
                };
            }
        } else if fpath.is_file() {
            match format {
                Format::Short => {
                    if all {
                        format_print(&fpath, &fpath, &format);
                    } else {
                        if !is_dot(&fpath) {
                            format_print(&fpath, &fpath, &format);
                        }
                    }
                }
                Format::Long => {
                    if all {
                        format_print(&fpath, &fpath, &format);
                    } else {
                        if !is_dot(&fpath) {
                            format_print(&fpath, &fpath, &format);
                        }
                    }
                }
            };
        }
    }
    return Ok(());
}

fn print_usage(opts: Options) {
    print!("{}: {} {}... {}...\n\
    List information about the FILE(s)", "Usage".bold(), UTIL.name.bold(),
    "[OPTION]".underline(), "FILE".underline());
    println!("{}", opts.options());
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();

    opts.optflag("a", "all", "Display hidden files");
    opts.optflag("h", "help", "Print help information");
    opts.optflag("l", "long", "Use the long listing option");
    opts.optflag("", "version", "Print version information");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => {
            Status::Error.err(UTIL.name, f.to_string());
            panic!(f.to_string())
        }
    };

    let mut current = Vec::new();
    current.push(String::from(env::current_dir().unwrap().as_str()));

    let all = matches.opt_present("a");

    if matches.opt_present("h") {
        print_usage(opts);
    } else if matches.opt_present("version") {
        UTIL.copyright("Copyright (C) 2015 core-utils developers\n\
                       License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n\
                       This is free software: you are free to change and redistribute it.\n\
                       There is NO WARRANTY, to the extent permitted by law.\n\n",
                       vec!["Alberto Corona"]);
    } else if matches.opt_present("l") {
        if !matches.free.is_empty() {
            print(&matches.free, Format::Long, all).ok();
        } else {
            print(&current, Format::Long, all).ok();
        }
    } else {
        if matches.free.is_empty() {
            print(&current, Format::Short, all).ok();
        } else {
            print(&matches.free, Format::Short, all).ok();
        }
    }
}