<commit_before>#![feature(convert)]
#![feature(io)]

extern crate rustc_serialize;
extern crate docopt;
extern crate users;
extern crate glob;
extern crate tempfile;
extern crate libc;
extern crate cronparse;

use cronparse::{CrontabFile, CrontabFileError};
use cronparse::crontab::UserCrontabEntry;
use tempfile::NamedTempFile;
use docopt::Docopt;
use libc::{uid_t, gid_t};
use std::env;
use std::fs;
use std::io::{stdin, stdout, stderr, Write, Read, self};
use std::fs::File;
use std::os::unix::fs::PermissionsExt;
use std::path::{PathBuf, Path};
use std::process::{Command, exit};
use std::ops::Deref;
use std::ffi::CString;

include!(concat!(env!("OUT_DIR"), "/config.rs"));

extern "C" {
    fn chown(path: *const libc::c_char, owner: libc::uid_t, group: libc::gid_t) -> libc::c_int;
}

fn change_owner<P: AsRef<Path>>(path: P, owner: libc::uid_t, group: libc::gid_t) -> Result<(), io::Error> {
    match unsafe { chown(CString::new(path.as_ref().as_os_str().to_bytes().unwrap()).unwrap().as_ptr(), owner, group) } {
        0 => Ok(()),
        -1 => Err(io::Error::last_os_error()),
        _ => unreachable!()
    }
}

static USAGE: &'static str = r#"
Usage: crontab [-u <user>] -l
       crontab [-u <user>] -e [<file>]
       crontab [-u <user>] -s
       crontab [-u <user>] -r [-i]
       crontab -h | --help

Maintain crontab files for individual users

Options:

  -h, --help                Show this help message and exit.
  -u <user>, --user <user>  It specifies the name of the user whose crontab is to
                            be tweaked. If this option is not given, crontab
                            examines "your" crontab, i.e., the crontab of the
                            person executing the command. Note that su(8) can
                            confuse crontab and that if you are running inside of
                            su(8) you should always use the -u option for safety's
                            sake. The first form of this command is used to
                            install a new crontab from some named file or standard
                            input if the pseudo-filename "-" is given.
  -l, --list                The current crontab will be displayed on standard
                            output.
  -r, --remove              The current crontab will be removed.
  -e, --edit                This option is used to edit the current crontab using
                            the editor specified by the VISUAL or EDITOR
                            environment variables. After you exit from the editor,
                            the modified crontab will be installed automatically.
  -s, --show                Show all users who have a crontab.
  -i, --ask                 This option modifies the -r option to prompt the user
                            for a 'y/Y' response before actually removing the
                            crontab.
"#;

#[derive(Debug, RustcDecodable)]
#[allow(non_snake_case)]
struct Args {
    arg_file: Option<String>,
    flag_user: Option<String>,
    flag_list: bool,
    flag_remove: bool,
    flag_edit: bool,
    flag_show: bool,
    flag_ask: bool
}

fn get_editor() -> Option<String> {
    env::var("EDITOR").ok()
        .or_else(|| env::var("VISUAL").ok())
        .or_else(|| ["/usr/bin/editor", "/usr/bin/vim", "/usr/bin/nano", "/usr/bin/mcedit"].iter()
                 .find(|editor| fs::metadata(editor).map(|meta| meta.is_file() && meta.permissions().mode() & 0o0111 != 0).unwrap_or(false))
                 .map(|&s| s.to_owned()))
}

fn confirm(msg: &str) -> bool {
    let mut stdin = stdin();
    let mut stdout = stdout();
    loop {
        stdout.write_all(msg.as_bytes()).unwrap();
        stdout.flush().unwrap();
        let mut buf = [0u8; 1024];
        match stdin.read(&mut buf) {
            Ok(n) if n > 0 && (buf[0] == 121 || buf[0] == 89) => return true,
            Ok(n) if n > 0 && (buf[0] == 110 || buf[0] == 78) => return false,
            _ => { stdout.write_all("Please reply \"y\" or \"n\"\n".as_bytes()).unwrap(); },
        }
    }
}

fn list(cron_file: &Path, _cron_uid: (uid_t, gid_t), args: &Args) -> i32 {
    if let Err(e) = File::open(cron_file).map(|file| file.tee(stdout()).bytes().count()) {
        use std::io::ErrorKind::*;
        match e.kind() {
            NotFound => println!("no crontab for {}", args.flag_user.as_ref().map(String::deref).unwrap_or("???")),
            _ => println!("failed to read {}: {}", cron_file.display(), e),
        }
        return 1;
    }
    0
}

fn remove(cron_file: &Path, _cron_uid: (uid_t, gid_t), args: &Args) -> i32 {
    let mut stderr = stderr();

    if !args.flag_ask || confirm(&*format!("Are you sure you want to delete {} (y/n)? ", cron_file.display())) {
        if let Err(e) = fs::remove_file(cron_file) {
            use std::io::ErrorKind::*;
            match e.kind() {
                NotFound => writeln!(stderr, "no crontab for {}", args.flag_user.as_ref().map(String::deref).unwrap_or("???")),
                _ => writeln!(stderr, "failed to remove {}: {}", cron_file.display(), e)
            }.unwrap();
            return 1;
        }
    }
    0
}

fn show(_cron_file: &Path, _cron_uid: (uid_t, gid_t), _args: &Args) -> i32 {
    let mut stderr = stderr();

    if let Ok(dir) = fs::read_dir(USERS_CRONTAB_DIR) {
        for item in dir {
            if let Ok(entry) = item {
                if let Some(name) = entry.file_name().to_str() {
                    if users::get_user_by_name(name).is_some() {
                        println!("{}", name);
                    } else {
                        writeln!(stderr, "WARNING: crontab found with no matching user: {}", name).unwrap();
                    }
                }
            }
        }
    }
    0
}

fn edit(cron_file: &Path, cron_uid: (uid_t, gid_t), _args: &Args) -> i32 {
    use std::io::ErrorKind::*;

    let mut stderr = stderr();

    let editor = match get_editor() {
        None => {
            writeln!(stderr, "no editor found").unwrap();
            return 1;
        },
        Some(editor) => editor
    };

    let mut tmpfile = NamedTempFile::new_in(USERS_CRONTAB_DIR).unwrap();

    if let Err(e) = File::open(cron_file).map(|file| file.tee(&mut tmpfile).bytes().count()) {
        match e.kind() {
            NotFound => tmpfile.write_all("# min hour dom month dow command".as_bytes()).unwrap(),
            _ => {
                writeln!(stderr, "error copying crontab file {}: {}", cron_file.display(), e).unwrap();
                return 1;
            }
        }
    }

    tmpfile.flush().unwrap();
    {
        change_owner(tmpfile.path(), cron_uid.0, cron_uid.1).unwrap();
        let _guard = users::switch_user_group(cron_uid.0, cron_uid.1);
        match Command::new(editor).arg(tmpfile.path()).status() {
            Ok(status) if status.success() => (),
            _ => {
                writeln!(stderr, "edit aborted, your edit is kept here: {}", tmpfile.path().display()).unwrap();
                return 1;
            }
        }
    }

    if let Err(err) = check_crontab_syntax(tmpfile.path()) {
        writeln!(stderr, "syntax error in new crontab file: {}", err).unwrap();
        return 1;
    }

    if let Err(err) = tmpfile.persist(cron_file) {
        writeln!(stderr, "unexpected error: {}, your edit is kept here: {}", err.error, err.file.path().display()).unwrap();
        return 1;
    }

    0
}

fn replace(cron_file: &Path, cron_uid: (uid_t, gid_t), args: &Args) -> i32 {
    let mut stderr = stderr();
    let mut tmpfile = NamedTempFile::new_in(USERS_CRONTAB_DIR).unwrap();

    match args.arg_file {
        Some(ref name) if &**name == "-" => { stdin().tee(&mut tmpfile).bytes().count(); },
        Some(ref name) => { File::open(&**name).unwrap().tee(&mut tmpfile).bytes().count(); },
        None => unreachable!()
    }

    tmpfile.flush().unwrap();

    if let Err(err) = check_crontab_syntax(tmpfile.path()) {
        writeln!(stderr, "syntax error in new crontab file: {}", err).unwrap();
        return 1;
    }

    if let Err(e) = tmpfile.persist(cron_file) {
        writeln!(stderr, "error renaming {} to {}: {}", e.file.path().display(), cron_file.display(), e.error).unwrap();
        return 1;
    }

    change_owner(cron_file, cron_uid.0, cron_uid.1).unwrap();

    0
}

fn main() {
    let mut stderr = stderr();
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    let cron_uid = match args.flag_user {
        Some(_) if users::get_current_uid() != 0 => {
            writeln!(stderr, "must be privileged to use -u").unwrap();
            exit(1);
        },
        Some(ref user) => match users::get_user_by_name(&**user) {
            Some(user) => (user.uid, user.primary_group),
            None => {
                writeln!(stderr, "unknown user: {}", user).unwrap();
                exit(1);
            }
        },
        None => (users::get_current_uid(), users::get_current_gid()),
    };

    match fs::metadata(USERS_CRONTAB_DIR) {
        Ok(ref meta) if !meta.is_dir() => {
            writeln!(stderr, "{} is not a directory!", USERS_CRONTAB_DIR).unwrap();
            exit(1);
        },
        Err(_) => if let Err(_) = fs::create_dir_all(USERS_CRONTAB_DIR) {
            writeln!(stderr, "{} doesn't exist!", USERS_CRONTAB_DIR).unwrap();
            exit(1);
        },
        _ => ()
    }

    let cron_file = PathBuf::from(USERS_CRONTAB_DIR).join(args.flag_user.clone()
        .or_else(users::get_current_username).unwrap());

    exit(match args {
        Args { flag_show: true, .. } => show(&*cron_file, cron_uid, &args),
        Args { flag_list: true, .. } => list(&*cron_file, cron_uid, &args),
        Args { flag_edit: true, arg_file: None, .. } => edit(&*cron_file, cron_uid, &args),
        Args { flag_edit: true, .. } => replace(&*cron_file, cron_uid, &args),
        Args { flag_remove: true, .. } => remove(&*cron_file, cron_uid, &args),
        _ => unreachable!()
    })
}

fn check_crontab_syntax<P: AsRef<Path>>(path: P) -> Result<(), CrontabFileError> {
    match try!(CrontabFile::<UserCrontabEntry>::new(path)).find(Result::is_err) {
        Some(Err(err)) => Err(err),
        _ => Ok(())
    }
}
<commit_msg>crontab: consolidate cron user handling<commit_after>#![feature(convert)]
#![feature(io)]

extern crate rustc_serialize;
extern crate docopt;
extern crate users;
extern crate glob;
extern crate tempfile;
extern crate libc;
extern crate cronparse;

use cronparse::{CrontabFile, CrontabFileError};
use cronparse::crontab::UserCrontabEntry;
use tempfile::NamedTempFile;
use docopt::Docopt;
use libc::{uid_t, gid_t};
use users::User;
use std::env;
use std::fs;
use std::io::{stdin, stdout, stderr, Write, Read, self};
use std::fs::File;
use std::os::unix::fs::PermissionsExt;
use std::path::{PathBuf, Path};
use std::process::{Command, exit};
use std::ops::Deref;
use std::ffi::CString;

include!(concat!(env!("OUT_DIR"), "/config.rs"));

extern "C" {
    fn chown(path: *const libc::c_char, owner: libc::uid_t, group: libc::gid_t) -> libc::c_int;
}

fn change_owner<P: AsRef<Path>>(path: P, owner: libc::uid_t, group: libc::gid_t) -> Result<(), io::Error> {
    match unsafe { chown(CString::new(path.as_ref().as_os_str().to_bytes().unwrap()).unwrap().as_ptr(), owner, group) } {
        0 => Ok(()),
        -1 => Err(io::Error::last_os_error()),
        _ => unreachable!()
    }
}

static USAGE: &'static str = r#"
Usage: crontab [-u <user>] -l
       crontab [-u <user>] -e [<file>]
       crontab [-u <user>] -s
       crontab [-u <user>] -r [-i]
       crontab -h | --help

Maintain crontab files for individual users

Options:

  -h, --help                Show this help message and exit.
  -u <user>, --user <user>  It specifies the name of the user whose crontab is to
                            be tweaked. If this option is not given, crontab
                            examines "your" crontab, i.e., the crontab of the
                            person executing the command. Note that su(8) can
                            confuse crontab and that if you are running inside of
                            su(8) you should always use the -u option for safety's
                            sake. The first form of this command is used to
                            install a new crontab from some named file or standard
                            input if the pseudo-filename "-" is given.
  -l, --list                The current crontab will be displayed on standard
                            output.
  -r, --remove              The current crontab will be removed.
  -e, --edit                This option is used to edit the current crontab using
                            the editor specified by the VISUAL or EDITOR
                            environment variables. After you exit from the editor,
                            the modified crontab will be installed automatically.
  -s, --show                Show all users who have a crontab.
  -i, --ask                 This option modifies the -r option to prompt the user
                            for a 'y/Y' response before actually removing the
                            crontab.
"#;

#[derive(Debug, RustcDecodable)]
#[allow(non_snake_case)]
struct Args {
    arg_file: Option<String>,
    flag_user: Option<String>,
    flag_list: bool,
    flag_remove: bool,
    flag_edit: bool,
    flag_show: bool,
    flag_ask: bool
}

fn get_editor() -> Option<String> {
    env::var("EDITOR").ok()
        .or_else(|| env::var("VISUAL").ok())
        .or_else(|| ["/usr/bin/editor", "/usr/bin/vim", "/usr/bin/nano", "/usr/bin/mcedit"].iter()
                 .find(|editor| fs::metadata(editor).map(|meta| meta.is_file() && meta.permissions().mode() & 0o0111 != 0).unwrap_or(false))
                 .map(|&s| s.to_owned()))
}

fn confirm(msg: &str) -> bool {
    let mut stdin = stdin();
    let mut stdout = stdout();
    loop {
        stdout.write_all(msg.as_bytes()).unwrap();
        stdout.flush().unwrap();
        let mut buf = [0u8; 1024];
        match stdin.read(&mut buf) {
            Ok(n) if n > 0 && (buf[0] == 121 || buf[0] == 89) => return true,
            Ok(n) if n > 0 && (buf[0] == 110 || buf[0] == 78) => return false,
            _ => { stdout.write_all("Please reply \"y\" or \"n\"\n".as_bytes()).unwrap(); },
        }
    }
}

fn list(cron_file: &Path, cron_user: &User, args: &Args) -> i32 {
    if let Err(e) = File::open(cron_file).map(|file| file.tee(stdout()).bytes().count()) {
        use std::io::ErrorKind::*;
        match e.kind() {
            NotFound => println!("no crontab for {}", cron_user.name),
            _ => println!("failed to read {}: {}", cron_file.display(), e),
        }
        return 1;
    }
    0
}

fn remove(cron_file: &Path, cron_user: &User, args: &Args) -> i32 {
    let mut stderr = stderr();

    if !args.flag_ask || confirm(&*format!("Are you sure you want to delete {} (y/n)? ", cron_file.display())) {
        if let Err(e) = fs::remove_file(cron_file) {
            use std::io::ErrorKind::*;
            match e.kind() {
                NotFound => writeln!(stderr, "no crontab for {}", cron_user.name),
                _ => writeln!(stderr, "failed to remove {}: {}", cron_file.display(), e)
            }.unwrap();
            return 1;
        }
    }
    0
}

fn show(_cron_file: &Path, _cron_user: &User, _args: &Args) -> i32 {
    let mut stderr = stderr();

    if let Ok(dir) = fs::read_dir(USERS_CRONTAB_DIR) {
        for item in dir {
            if let Ok(entry) = item {
                if let Some(name) = entry.file_name().to_str() {
                    if users::get_user_by_name(name).is_some() {
                        println!("{}", name);
                    } else {
                        writeln!(stderr, "WARNING: crontab found with no matching user: {}", name).unwrap();
                    }
                }
            }
        }
    }
    0
}

fn edit(cron_file: &Path, cron_user: &User, _args: &Args) -> i32 {
    use std::io::ErrorKind::*;

    let mut stderr = stderr();

    let editor = match get_editor() {
        None => {
            writeln!(stderr, "no editor found").unwrap();
            return 1;
        },
        Some(editor) => editor
    };

    let mut tmpfile = NamedTempFile::new_in(USERS_CRONTAB_DIR).unwrap();

    if let Err(e) = File::open(cron_file).map(|file| file.tee(&mut tmpfile).bytes().count()) {
        match e.kind() {
            NotFound => tmpfile.write_all("# min hour dom month dow command".as_bytes()).unwrap(),
            _ => {
                writeln!(stderr, "error copying crontab file {}: {}", cron_file.display(), e).unwrap();
                return 1;
            }
        }
    }

    tmpfile.flush().unwrap();
    {
        change_owner(tmpfile.path(), cron_user.uid, cron_user.primary_group).unwrap();
        let _guard = users::switch_user_group(cron_user.uid, cron_user.primary_group);
        match Command::new(editor).arg(tmpfile.path()).status() {
            Ok(status) if status.success() => (),
            _ => {
                writeln!(stderr, "edit aborted, your edit is kept here: {}", tmpfile.path().display()).unwrap();
                return 1;
            }
        }
    }

    if let Err(err) = check_crontab_syntax(tmpfile.path()) {
        writeln!(stderr, "syntax error in new crontab file: {}", err).unwrap();
        return 1;
    }

    if let Err(err) = tmpfile.persist(cron_file) {
        writeln!(stderr, "unexpected error: {}, your edit is kept here: {}", err.error, err.file.path().display()).unwrap();
        return 1;
    }

    0
}

fn replace(cron_file: &Path, cron_user: &User, args: &Args) -> i32 {
    let mut stderr = stderr();
    let mut tmpfile = NamedTempFile::new_in(USERS_CRONTAB_DIR).unwrap();

    match args.arg_file {
        Some(ref name) if &**name == "-" => { stdin().tee(&mut tmpfile).bytes().count(); },
        Some(ref name) => { File::open(&**name).unwrap().tee(&mut tmpfile).bytes().count(); },
        None => unreachable!()
    }

    tmpfile.flush().unwrap();

    if let Err(err) = check_crontab_syntax(tmpfile.path()) {
        writeln!(stderr, "syntax error in new crontab file: {}", err).unwrap();
        return 1;
    }

    if let Err(e) = tmpfile.persist(cron_file) {
        writeln!(stderr, "error renaming {} to {}: {}", e.file.path().display(), cron_file.display(), e.error).unwrap();
        return 1;
    }

    change_owner(cron_file, cron_user.uid, cron_user.primary_group).unwrap();

    0
}

fn main() {
    let mut stderr = stderr();
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    let cron_user = match args.flag_user {
        Some(_) if users::get_current_uid() != 0 => {
            writeln!(stderr, "must be privileged to use -u").unwrap();
            exit(1);
        },
        Some(ref user) => match users::get_user_by_name(&**user) {
            Some(user) => user,
            None => {
                writeln!(stderr, "unknown user: {}", user).unwrap();
                exit(1);
            }
        },
        None => users::get_user_by_uid(users::get_current_uid()).unwrap(),
    };

    match fs::metadata(USERS_CRONTAB_DIR) {
        Ok(ref meta) if !meta.is_dir() => {
            writeln!(stderr, "{} is not a directory!", USERS_CRONTAB_DIR).unwrap();
            exit(1);
        },
        Err(_) => if let Err(_) = fs::create_dir_all(USERS_CRONTAB_DIR) {
            writeln!(stderr, "{} doesn't exist!", USERS_CRONTAB_DIR).unwrap();
            exit(1);
        },
        _ => ()
    }

    let cron_file = PathBuf::from(USERS_CRONTAB_DIR).join(cron_user.name.clone());

    exit(match args {
        Args { flag_show: true, .. } => show(&*cron_file, &cron_user, &args),
        Args { flag_list: true, .. } => list(&*cron_file, &cron_user, &args),
        Args { flag_edit: true, arg_file: None, .. } => edit(&*cron_file, &cron_user, &args),
        Args { flag_edit: true, .. } => replace(&*cron_file, &cron_user, &args),
        Args { flag_remove: true, .. } => remove(&*cron_file, &cron_user, &args),
        _ => unreachable!()
    })
}

fn check_crontab_syntax<P: AsRef<Path>>(path: P) -> Result<(), CrontabFileError> {
    match try!(CrontabFile::<UserCrontabEntry>::new(path)).find(Result::is_err) {
        Some(Err(err)) => Err(err),
        _ => Ok(())
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, World");
}
<commit_msg>Add rustyline as a crate for the example<commit_after>extern crate rustyline;

fn main() {
    rustyline::readline();
}
<|endoftext|>


<commit_before>//! `cargo rm`

#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

#![deny(missing_docs)]

extern crate docopt;
extern crate toml;
extern crate semver;
extern crate rustc_serialize;

use std::error::Error;
use std::process;

extern crate cargo_edit;
use cargo_edit::Manifest;

mod args;
use args::Args;

static USAGE: &'static str = r"
Usage:
    cargo rm <crate> [--dev|--build] [options]
    cargo rm (-h|--help)
    cargo rm --version

Options:
    -D --dev                Remove crate as development dependency.
    -B --build              Remove crate as build dependency.
    --manifest-path=<path>  Path to the manifest to remove a dependency from.
    -h --help               Show this help page.
    --version               Show version.

Remove a dependency to a Cargo.toml manifest file.
";

fn handle_rm(args: &Args) -> Result<(), Box<Error>> {
    let mut manifest = try!(Manifest::open(&args.flag_manifest_path.as_ref().map(|s| &s[..])));

    manifest.remove_from_table(args.get_section(), &args.arg_crate.as_ref())
            .map_err(From::from)
            .and_then(|_| {
                let mut file = try!(Manifest::find_file(&args.flag_manifest_path.as_ref().map(|s| &s[..])));
                manifest.write_to_file(&mut file)
            })
           .or_else(|err| {
               println!("Could not edit `Cargo.toml`.\n\nERROR: {}", err);
               Err(err)
           })
}

fn main() {
    let args = docopt::Docopt::new(USAGE)
                    .and_then(|d| d.decode::<Args>())
                    .unwrap_or_else(|err| err.exit());

    if args.flag_version {
        println!("cargo-rm version {}", env!("CARGO_PKG_VERSION"));
        process::exit(0);
    }

    if let Err(err) = handle_rm(&args) {
        println!("{}", err);
        process::exit(1);
    }
}
<commit_msg>Remove extra println because the manifest.rs already printsinfo<commit_after>//! `cargo rm`

#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

#![deny(missing_docs)]

extern crate docopt;
extern crate toml;
extern crate semver;
extern crate rustc_serialize;

use std::error::Error;
use std::process;

extern crate cargo_edit;
use cargo_edit::Manifest;

mod args;
use args::Args;

static USAGE: &'static str = r"
Usage:
    cargo rm <crate> [--dev|--build] [options]
    cargo rm (-h|--help)
    cargo rm --version

Options:
    -D --dev                Remove crate as development dependency.
    -B --build              Remove crate as build dependency.
    --manifest-path=<path>  Path to the manifest to remove a dependency from.
    -h --help               Show this help page.
    --version               Show version.

Remove a dependency to a Cargo.toml manifest file.
";

fn handle_rm(args: &Args) -> Result<(), Box<Error>> {
    let mut manifest = try!(Manifest::open(&args.flag_manifest_path.as_ref().map(|s| &s[..])));

    manifest.remove_from_table(args.get_section(), &args.arg_crate.as_ref())
            .map_err(From::from)
            .and_then(|_| {
                let mut file = try!(Manifest::find_file(&args.flag_manifest_path.as_ref().map(|s| &s[..])));
                manifest.write_to_file(&mut file)
            })
           .or_else(|err| {
               println!("Could not edit `Cargo.toml`.\n\nERROR: {}", err);
               Err(err)
           })
}

fn main() {
    let args = docopt::Docopt::new(USAGE)
                    .and_then(|d| d.decode::<Args>())
                    .unwrap_or_else(|err| err.exit());

    if args.flag_version {
        println!("cargo-rm version {}", env!("CARGO_PKG_VERSION"));
        process::exit(0);
    }

    if let Err(_) = handle_rm(&args) {
        process::exit(1);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg(not(test))]

#[macro_use]
extern crate log;
extern crate rustfmt;
extern crate toml;
extern crate env_logger;
extern crate getopts;

use rustfmt::{WriteMode, run, run_from_stdin};
use rustfmt::config::Config;

use std::env;
use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};

use getopts::Options;

/// Rustfmt operations.
enum Operation {
    /// Format a file and its child modules.
    Format(PathBuf, WriteMode),
    /// Print the help message.
    Help,
    /// Print detailed configuration help.
    ConfigHelp,
    /// Invalid program input, including reason.
    InvalidInput(String),
    /// No file specified, read from stdin
    Stdin(String, WriteMode),
}

/// Try to find a project file in the input file directory and its parents.
fn lookup_project_file(input_file: &Path) -> io::Result<PathBuf> {
    let mut current = if input_file.is_relative() {
        try!(env::current_dir()).join(input_file)
    } else {
        input_file.to_path_buf()
    };

    // FIXME: We should canonize path to properly handle its parents,
    // but `canonicalize` function is unstable now (recently added API)
    // current = try!(fs::canonicalize(current));

    loop {
        // If the current directory has no parent, we're done searching.
        if !current.pop() {
            return Err(io::Error::new(io::ErrorKind::NotFound, "Config not found"));
        }
        let config_file = current.join("rustfmt.toml");
        if fs::metadata(&config_file).is_ok() {
            return Ok(config_file);
        }
    }
}

/// Try to find a project file. If it's found, read it.
fn lookup_and_read_project_file(input_file: &Path) -> io::Result<(PathBuf, String)> {
    let path = try!(lookup_project_file(input_file));
    let mut file = try!(File::open(&path));
    let mut toml = String::new();
    try!(file.read_to_string(&mut toml));
    Ok((path, toml))
}

fn execute() -> i32 {
    let mut opts = Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optopt("",
                "write-mode",
                "mode to write in (not usable when piping from stdin)",
                "[replace|overwrite|display|diff|coverage]");

    opts.optflag("",
                 "config-help",
                 "show details of rustfmt configuration options");

    let operation = determine_operation(&opts, env::args().skip(1));

    match operation {
        Operation::InvalidInput(reason) => {
            print_usage(&opts, &reason);
            1
        }
        Operation::Help => {
            print_usage(&opts, "");
            0
        }
        Operation::ConfigHelp => {
            Config::print_docs();
            0
        }
        Operation::Stdin(input, write_mode) => {
            // try to read config from local directory
            let config = match lookup_and_read_project_file(&Path::new(".")) {
                Ok((_, toml)) => {
                    Config::from_toml(&toml)
                }
                Err(_) => Default::default(),
            };

            run_from_stdin(input, write_mode, &config);
            0
        }
        Operation::Format(file, write_mode) => {
            let config = match lookup_and_read_project_file(&file) {
                Ok((path, toml)) => {
                    println!("Using rustfmt config file: {}", path.display());
                    Config::from_toml(&toml)
                }
                Err(_) => Default::default(),
            };

            run(&file, write_mode, &config);
            0
        }
    }
}

fn main() {
    let _ = env_logger::init();
    let exit_code = execute();

    // Make sure standard output is flushed before we exit.
    std::io::stdout().flush().unwrap();

    // Exit with given exit code.
    //
    // NOTE: This immediately terminates the process without doing any cleanup,
    // so make sure to finish all necessary cleanup before this is called.
    std::process::exit(exit_code);
}

fn print_usage(opts: &Options, reason: &str) {
    let reason = format!("{}\nusage: {} [options] <file>",
                         reason,
                         env::current_exe().unwrap().display());
    println!("{}", opts.usage(&reason));
}

fn determine_operation<I>(opts: &Options, args: I) -> Operation
    where I: Iterator<Item = String>
{
    let matches = match opts.parse(args) {
        Ok(m) => m,
        Err(e) => return Operation::InvalidInput(e.to_string()),
    };

    if matches.opt_present("h") {
        return Operation::Help;
    }

    if matches.opt_present("config-help") {
        return Operation::ConfigHelp;
    }

    // if no file argument is supplied, read from stdin
    if matches.free.len() == 0 {

        let mut buffer = String::new();
        match io::stdin().read_to_string(&mut buffer) {
            Ok(..) => (),
            Err(e) => return Operation::InvalidInput(e.to_string()),
        }

        // WriteMode is always plain for Stdin
        return Operation::Stdin(buffer, WriteMode::Plain);
    }

    let write_mode = match matches.opt_str("write-mode") {
        Some(mode) => {
            match mode.parse() {
                Ok(mode) => mode,
                Err(..) => return Operation::InvalidInput("Unrecognized write mode".into()),
            }
        }
        None => WriteMode::Replace,
    };

    Operation::Format(PathBuf::from(&matches.free[0]), write_mode)
}
<commit_msg>Check if the CWD contains a config (previously it only checked parents)<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg(not(test))]

#[macro_use]
extern crate log;
extern crate rustfmt;
extern crate toml;
extern crate env_logger;
extern crate getopts;

use rustfmt::{WriteMode, run, run_from_stdin};
use rustfmt::config::Config;

use std::env;
use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};

use getopts::Options;

/// Rustfmt operations.
enum Operation {
    /// Format a file and its child modules.
    Format(PathBuf, WriteMode),
    /// Print the help message.
    Help,
    /// Print detailed configuration help.
    ConfigHelp,
    /// Invalid program input, including reason.
    InvalidInput(String),
    /// No file specified, read from stdin
    Stdin(String, WriteMode),
}

/// Try to find a project file in the input file directory and its parents.
fn lookup_project_file(input_file: &Path) -> io::Result<PathBuf> {
    let mut current = if input_file.is_relative() {
        try!(env::current_dir()).join(input_file)
    } else {
        input_file.to_path_buf()
    };

    // FIXME: We should canonize path to properly handle its parents,
    // but `canonicalize` function is unstable now (recently added API)
    // current = try!(fs::canonicalize(current));

    loop {
        let config_file = current.join("rustfmt.toml");
        if fs::metadata(&config_file).is_ok() {
            return Ok(config_file);
        }

        // If the current directory has no parent, we're done searching.
        if !current.pop() {
            return Err(io::Error::new(io::ErrorKind::NotFound, "Config not found"));
        }
    }
}

/// Try to find a project file. If it's found, read it.
fn lookup_and_read_project_file(input_file: &Path) -> io::Result<(PathBuf, String)> {
    let path = try!(lookup_project_file(input_file));
    let mut file = try!(File::open(&path));
    let mut toml = String::new();
    try!(file.read_to_string(&mut toml));
    Ok((path, toml))
}

fn execute() -> i32 {
    let mut opts = Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optopt("",
                "write-mode",
                "mode to write in (not usable when piping from stdin)",
                "[replace|overwrite|display|diff|coverage]");

    opts.optflag("",
                 "config-help",
                 "show details of rustfmt configuration options");

    let operation = determine_operation(&opts, env::args().skip(1));

    match operation {
        Operation::InvalidInput(reason) => {
            print_usage(&opts, &reason);
            1
        }
        Operation::Help => {
            print_usage(&opts, "");
            0
        }
        Operation::ConfigHelp => {
            Config::print_docs();
            0
        }
        Operation::Stdin(input, write_mode) => {
            // try to read config from local directory
            let config = match lookup_and_read_project_file(&Path::new(".")) {
                Ok((_, toml)) => {
                    Config::from_toml(&toml)
                }
                Err(_) => Default::default(),
            };

            run_from_stdin(input, write_mode, &config);
            0
        }
        Operation::Format(file, write_mode) => {
            let config = match lookup_and_read_project_file(&file) {
                Ok((path, toml)) => {
                    println!("Using rustfmt config file: {}", path.display());
                    Config::from_toml(&toml)
                }
                Err(_) => Default::default(),
            };

            run(&file, write_mode, &config);
            0
        }
    }
}

fn main() {
    let _ = env_logger::init();
    let exit_code = execute();

    // Make sure standard output is flushed before we exit.
    std::io::stdout().flush().unwrap();

    // Exit with given exit code.
    //
    // NOTE: This immediately terminates the process without doing any cleanup,
    // so make sure to finish all necessary cleanup before this is called.
    std::process::exit(exit_code);
}

fn print_usage(opts: &Options, reason: &str) {
    let reason = format!("{}\nusage: {} [options] <file>",
                         reason,
                         env::current_exe().unwrap().display());
    println!("{}", opts.usage(&reason));
}

fn determine_operation<I>(opts: &Options, args: I) -> Operation
    where I: Iterator<Item = String>
{
    let matches = match opts.parse(args) {
        Ok(m) => m,
        Err(e) => return Operation::InvalidInput(e.to_string()),
    };

    if matches.opt_present("h") {
        return Operation::Help;
    }

    if matches.opt_present("config-help") {
        return Operation::ConfigHelp;
    }

    // if no file argument is supplied, read from stdin
    if matches.free.len() == 0 {

        let mut buffer = String::new();
        match io::stdin().read_to_string(&mut buffer) {
            Ok(..) => (),
            Err(e) => return Operation::InvalidInput(e.to_string()),
        }

        // WriteMode is always plain for Stdin
        return Operation::Stdin(buffer, WriteMode::Plain);
    }

    let write_mode = match matches.opt_str("write-mode") {
        Some(mode) => {
            match mode.parse() {
                Ok(mode) => mode,
                Err(..) => return Operation::InvalidInput("Unrecognized write mode".into()),
            }
        }
        None => WriteMode::Replace,
    };

    Operation::Format(PathBuf::from(&matches.free[0]), write_mode)
}
<|endoftext|>


<commit_before>use super::*;
use redox::*;

impl Editor {
    /// Remove from a given motion (row based)
    pub fn remove_rb<'a>(&mut self, (x, y): (usize, usize)) {
        if y == self.y() {
            // Single line mode
            let (a, b) = if self.x() < x {
                (self.x(), x)
            } else {
                (x, self.x())
            };
            for i in a..b {
                self.text[y].remove(i);
            }
        } else {
            // Full line mode
            let (a, b) = if self.y() <= y {
                (self.y(), y)
            } else {
                (y, self.y())
            };
            for ln in a..b {
                self.text.remove(ln);
            }
        }
    }
}
<commit_msg>Fix off-by-one bug<commit_after>use super::*;
use redox::*;

impl Editor {
    /// Remove from a given motion (row based)
    pub fn remove_rb<'a>(&mut self, (x, y): (usize, usize)) {
        if y == self.y() {
            // Single line mode
            let (a, b) = if self.x() < x {
                (self.x(), x)
            } else {
                (x, self.x())
            };
            for i in a..b {
                self.text[y].remove(i);
            }
        } else {
            // Full line mode
            let (a, b) = if self.y() <= y {
                (self.y(), y)
            } else {
                (y, self.y())
            };
            for ln in a..(b + 1) {
                self.text.remove(ln);
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Decoding and Encoding of TIFF Images
//!
//! TIFF (Tagged Image File Format) is a versatile image format that supports
//! lossless and lossy compression.
//!
//! # Related Links
//! * <http://partners.adobe.com/public/developer/tiff/index.html> - The TIFF specification

extern crate tiff;

use std::convert::TryFrom;
use std::io::{self, Cursor, Read, Seek, Write};
use std::marker::PhantomData;
use std::mem;

use crate::color::{ColorType, ExtendedColorType};
use crate::error::{
    DecodingError, EncodingError, ImageError, ImageResult, LimitError, LimitErrorKind,
    ParameterError, ParameterErrorKind, UnsupportedError, UnsupportedErrorKind,
};
use crate::image::{ImageDecoder, ImageEncoder, ImageFormat};
use crate::utils;

/// Decoder for TIFF images.
pub struct TiffDecoder<R>
where
    R: Read + Seek,
{
    dimensions: (u32, u32),
    color_type: ColorType,
    inner: tiff::decoder::Decoder<R>,
}

impl<R> TiffDecoder<R>
where
    R: Read + Seek,
{
    /// Create a new TiffDecoder.
    pub fn new(r: R) -> Result<TiffDecoder<R>, ImageError> {
        let mut inner = tiff::decoder::Decoder::new(r).map_err(ImageError::from_tiff_decode)?;

        let dimensions = inner.dimensions().map_err(ImageError::from_tiff_decode)?;
        let color_type = inner.colortype().map_err(ImageError::from_tiff_decode)?;
        match inner.find_tag_unsigned_vec::<u16>(tiff::tags::Tag::SampleFormat) {
            Ok(Some(sample_formats)) => {
                for format in sample_formats {
                    check_sample_format(format)?;
                }
            }
            Ok(None) => { /* assume UInt format */ }
            Err(other) => return Err(ImageError::from_tiff_decode(other)),
        };

        let color_type = match color_type {
            tiff::ColorType::Gray(8) => ColorType::L8,
            tiff::ColorType::Gray(16) => ColorType::L16,
            tiff::ColorType::GrayA(8) => ColorType::La8,
            tiff::ColorType::GrayA(16) => ColorType::La16,
            tiff::ColorType::RGB(8) => ColorType::Rgb8,
            tiff::ColorType::RGB(16) => ColorType::Rgb16,
            tiff::ColorType::RGBA(8) => ColorType::Rgba8,
            tiff::ColorType::RGBA(16) => ColorType::Rgba16,

            tiff::ColorType::Palette(n) | tiff::ColorType::Gray(n) => {
                return Err(err_unknown_color_type(n))
            }
            tiff::ColorType::GrayA(n) => return Err(err_unknown_color_type(n * 2)),
            tiff::ColorType::RGB(n) => return Err(err_unknown_color_type(n * 3)),
            tiff::ColorType::RGBA(n) | tiff::ColorType::CMYK(n) => {
                return Err(err_unknown_color_type(n * 4))
            }
        };

        Ok(TiffDecoder {
            dimensions,
            color_type,
            inner,
        })
    }
}

fn check_sample_format(sample_format: u16) -> Result<(), ImageError> {
    match tiff::tags::SampleFormat::from_u16(sample_format) {
        Some(tiff::tags::SampleFormat::Uint) => Ok(()),
        Some(other) => Err(ImageError::Unsupported(
            UnsupportedError::from_format_and_kind(
                ImageFormat::Tiff.into(),
                UnsupportedErrorKind::GenericFeature(format!(
                    "Unhandled TIFF sample format {:?}",
                    other
                )),
            ),
        )),
        None => Err(ImageError::Decoding(DecodingError::from_format_hint(
            ImageFormat::Tiff.into(),
        ))),
    }
}

fn err_unknown_color_type(value: u8) -> ImageError {
    ImageError::Unsupported(UnsupportedError::from_format_and_kind(
        ImageFormat::Tiff.into(),
        UnsupportedErrorKind::Color(ExtendedColorType::Unknown(value)),
    ))
}

impl ImageError {
    fn from_tiff_decode(err: tiff::TiffError) -> ImageError {
        match err {
            tiff::TiffError::IoError(err) => ImageError::IoError(err),
            err @ tiff::TiffError::FormatError(_)
            | err @ tiff::TiffError::IntSizeError
            | err @ tiff::TiffError::UsageError(_) => {
                ImageError::Decoding(DecodingError::new(ImageFormat::Tiff.into(), err))
            }
            tiff::TiffError::UnsupportedError(desc) => {
                ImageError::Unsupported(UnsupportedError::from_format_and_kind(
                    ImageFormat::Tiff.into(),
                    UnsupportedErrorKind::GenericFeature(desc.to_string()),
                ))
            }
            tiff::TiffError::LimitsExceeded => {
                ImageError::Limits(LimitError::from_kind(LimitErrorKind::InsufficientMemory))
            }
        }
    }

    fn from_tiff_encode(err: tiff::TiffError) -> ImageError {
        match err {
            tiff::TiffError::IoError(err) => ImageError::IoError(err),
            err @ tiff::TiffError::FormatError(_)
            | err @ tiff::TiffError::IntSizeError
            | err @ tiff::TiffError::UsageError(_) => {
                ImageError::Encoding(EncodingError::new(ImageFormat::Tiff.into(), err))
            }
            tiff::TiffError::UnsupportedError(desc) => {
                ImageError::Unsupported(UnsupportedError::from_format_and_kind(
                    ImageFormat::Tiff.into(),
                    UnsupportedErrorKind::GenericFeature(desc.to_string()),
                ))
            }
            tiff::TiffError::LimitsExceeded => {
                ImageError::Limits(LimitError::from_kind(LimitErrorKind::InsufficientMemory))
            }
        }
    }
}

/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct TiffReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for TiffReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        if self.0.position() == 0 && buf.is_empty() {
            mem::swap(buf, self.0.get_mut());
            Ok(buf.len())
        } else {
            self.0.read_to_end(buf)
        }
    }
}

impl<'a, R: 'a + Read + Seek> ImageDecoder<'a> for TiffDecoder<R> {
    type Reader = TiffReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        self.dimensions
    }

    fn color_type(&self) -> ColorType {
        self.color_type
    }

    fn into_reader(mut self) -> ImageResult<Self::Reader> {
        let buf = match self
            .inner
            .read_image()
            .map_err(ImageError::from_tiff_decode)?
        {
            tiff::decoder::DecodingResult::U8(v) => v,
            tiff::decoder::DecodingResult::U16(v) => utils::vec_copy_to_u8(&v),
            tiff::decoder::DecodingResult::U32(v) => utils::vec_copy_to_u8(&v),
            tiff::decoder::DecodingResult::U64(v) => utils::vec_copy_to_u8(&v),
            tiff::decoder::DecodingResult::I8(v) => utils::vec_copy_to_u8(&v),
            tiff::decoder::DecodingResult::I16(v) => utils::vec_copy_to_u8(&v),
            tiff::decoder::DecodingResult::I32(v) => utils::vec_copy_to_u8(&v),
            tiff::decoder::DecodingResult::I64(v) => utils::vec_copy_to_u8(&v),
            tiff::decoder::DecodingResult::F32(v) => utils::vec_copy_to_u8(&v),
            tiff::decoder::DecodingResult::F64(v) => utils::vec_copy_to_u8(&v),
        };

        Ok(TiffReader(Cursor::new(buf), PhantomData))
    }

    fn read_image(mut self, buf: &mut [u8]) -> ImageResult<()> {
        assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
        match self
            .inner
            .read_image()
            .map_err(ImageError::from_tiff_decode)?
        {
            tiff::decoder::DecodingResult::U8(v) => {
                buf.copy_from_slice(&v);
            }
            tiff::decoder::DecodingResult::U16(v) => {
                buf.copy_from_slice(bytemuck::cast_slice(&v));
            }
            tiff::decoder::DecodingResult::U32(v) => {
                buf.copy_from_slice(bytemuck::cast_slice(&v));
            }
            tiff::decoder::DecodingResult::U64(v) => {
                buf.copy_from_slice(bytemuck::cast_slice(&v));
            }
            tiff::decoder::DecodingResult::I8(v) => {
                buf.copy_from_slice(bytemuck::cast_slice(&v));
            }
            tiff::decoder::DecodingResult::I16(v) => {
                buf.copy_from_slice(bytemuck::cast_slice(&v));
            }
            tiff::decoder::DecodingResult::I32(v) => {
                buf.copy_from_slice(bytemuck::cast_slice(&v));
            }
            tiff::decoder::DecodingResult::I64(v) => {
                buf.copy_from_slice(bytemuck::cast_slice(&v));
            }
            tiff::decoder::DecodingResult::F32(v) => {
                buf.copy_from_slice(bytemuck::cast_slice(&v));
            }
            tiff::decoder::DecodingResult::F64(v) => {
                buf.copy_from_slice(bytemuck::cast_slice(&v));
            }
        }
        Ok(())
    }
}

/// Encoder for tiff images
pub struct TiffEncoder<W> {
    w: W,
}

// Utility to simplify and deduplicate error handling during 16-bit encoding.
fn u8_slice_as_u16(buf: &[u8]) -> ImageResult<&[u16]> {
    bytemuck::try_cast_slice(buf).map_err(|err| {
        // If the buffer is not aligned or the correct length for a u16 slice, err.
        //
        // `bytemuck::PodCastError` of bytemuck-1.2.0 does not implement
        // `Error` and `Display` trait.
        // See <https://github.com/Lokathor/bytemuck/issues/22>.
        ImageError::Parameter(ParameterError::from_kind(ParameterErrorKind::Generic(
            format!("{:?}", err),
        )))
    })
}

impl<W: Write + Seek> TiffEncoder<W> {
    /// Create a new encoder that writes its output to `w`
    pub fn new(w: W) -> TiffEncoder<W> {
        TiffEncoder { w }
    }

    /// Encodes the image `image` that has dimensions `width` and `height` and `ColorType` `c`.
    ///
    /// 16-bit types assume the buffer is native endian.
    pub fn encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> ImageResult<()> {
        let mut encoder =
            tiff::encoder::TiffEncoder::new(self.w).map_err(ImageError::from_tiff_encode)?;
        match color {
            ColorType::L8 => {
                encoder.write_image::<tiff::encoder::colortype::Gray8>(width, height, data)
            }
            ColorType::Rgb8 => {
                encoder.write_image::<tiff::encoder::colortype::RGB8>(width, height, data)
            }
            ColorType::Rgba8 => {
                encoder.write_image::<tiff::encoder::colortype::RGBA8>(width, height, data)
            }
            ColorType::L16 => encoder.write_image::<tiff::encoder::colortype::Gray16>(
                width,
                height,
                u8_slice_as_u16(data)?,
            ),
            ColorType::Rgb16 => encoder.write_image::<tiff::encoder::colortype::RGB16>(
                width,
                height,
                u8_slice_as_u16(data)?,
            ),
            ColorType::Rgba16 => encoder.write_image::<tiff::encoder::colortype::RGBA16>(
                width,
                height,
                u8_slice_as_u16(data)?,
            ),
            _ => {
                return Err(ImageError::Unsupported(
                    UnsupportedError::from_format_and_kind(
                        ImageFormat::Tiff.into(),
                        UnsupportedErrorKind::Color(color.into()),
                    ),
                ))
            }
        }
        .map_err(ImageError::from_tiff_encode)?;

        Ok(())
    }
}

impl<W: Write + Seek> ImageEncoder for TiffEncoder<W> {
    fn write_image(
        self,
        buf: &[u8],
        width: u32,
        height: u32,
        color_type: ColorType,
    ) -> ImageResult<()> {
        self.encode(buf, width, height, color_type)
    }
}
<commit_msg>Implement TiffReader::set_limits<commit_after>//! Decoding and Encoding of TIFF Images
//!
//! TIFF (Tagged Image File Format) is a versatile image format that supports
//! lossless and lossy compression.
//!
//! # Related Links
//! * <http://partners.adobe.com/public/developer/tiff/index.html> - The TIFF specification

extern crate tiff;

use std::convert::TryFrom;
use std::io::{self, Cursor, Read, Seek, Write};
use std::marker::PhantomData;
use std::mem;

use crate::color::{ColorType, ExtendedColorType};
use crate::error::{
    DecodingError, EncodingError, ImageError, ImageResult, LimitError, LimitErrorKind,
    ParameterError, ParameterErrorKind, UnsupportedError, UnsupportedErrorKind,
};
use crate::image::{ImageDecoder, ImageEncoder, ImageFormat};
use crate::utils;

/// Decoder for TIFF images.
pub struct TiffDecoder<R>
where
    R: Read + Seek,
{
    dimensions: (u32, u32),
    color_type: ColorType,
    inner: Option<tiff::decoder::Decoder<R>>,
}

impl<R> TiffDecoder<R>
where
    R: Read + Seek,
{
    /// Create a new TiffDecoder.
    pub fn new(r: R) -> Result<TiffDecoder<R>, ImageError> {
        let mut inner = tiff::decoder::Decoder::new(r).map_err(ImageError::from_tiff_decode)?;

        let dimensions = inner.dimensions().map_err(ImageError::from_tiff_decode)?;
        let color_type = inner.colortype().map_err(ImageError::from_tiff_decode)?;
        match inner.find_tag_unsigned_vec::<u16>(tiff::tags::Tag::SampleFormat) {
            Ok(Some(sample_formats)) => {
                for format in sample_formats {
                    check_sample_format(format)?;
                }
            }
            Ok(None) => { /* assume UInt format */ }
            Err(other) => return Err(ImageError::from_tiff_decode(other)),
        };

        let color_type = match color_type {
            tiff::ColorType::Gray(8) => ColorType::L8,
            tiff::ColorType::Gray(16) => ColorType::L16,
            tiff::ColorType::GrayA(8) => ColorType::La8,
            tiff::ColorType::GrayA(16) => ColorType::La16,
            tiff::ColorType::RGB(8) => ColorType::Rgb8,
            tiff::ColorType::RGB(16) => ColorType::Rgb16,
            tiff::ColorType::RGBA(8) => ColorType::Rgba8,
            tiff::ColorType::RGBA(16) => ColorType::Rgba16,

            tiff::ColorType::Palette(n) | tiff::ColorType::Gray(n) => {
                return Err(err_unknown_color_type(n))
            }
            tiff::ColorType::GrayA(n) => return Err(err_unknown_color_type(n * 2)),
            tiff::ColorType::RGB(n) => return Err(err_unknown_color_type(n * 3)),
            tiff::ColorType::RGBA(n) | tiff::ColorType::CMYK(n) => {
                return Err(err_unknown_color_type(n * 4))
            }
        };

        Ok(TiffDecoder {
            dimensions,
            color_type,
            inner: Some(inner),
        })
    }
}

fn check_sample_format(sample_format: u16) -> Result<(), ImageError> {
    match tiff::tags::SampleFormat::from_u16(sample_format) {
        Some(tiff::tags::SampleFormat::Uint) => Ok(()),
        Some(other) => Err(ImageError::Unsupported(
            UnsupportedError::from_format_and_kind(
                ImageFormat::Tiff.into(),
                UnsupportedErrorKind::GenericFeature(format!(
                    "Unhandled TIFF sample format {:?}",
                    other
                )),
            ),
        )),
        None => Err(ImageError::Decoding(DecodingError::from_format_hint(
            ImageFormat::Tiff.into(),
        ))),
    }
}

fn err_unknown_color_type(value: u8) -> ImageError {
    ImageError::Unsupported(UnsupportedError::from_format_and_kind(
        ImageFormat::Tiff.into(),
        UnsupportedErrorKind::Color(ExtendedColorType::Unknown(value)),
    ))
}

impl ImageError {
    fn from_tiff_decode(err: tiff::TiffError) -> ImageError {
        match err {
            tiff::TiffError::IoError(err) => ImageError::IoError(err),
            err @ tiff::TiffError::FormatError(_)
            | err @ tiff::TiffError::IntSizeError
            | err @ tiff::TiffError::UsageError(_) => {
                ImageError::Decoding(DecodingError::new(ImageFormat::Tiff.into(), err))
            }
            tiff::TiffError::UnsupportedError(desc) => {
                ImageError::Unsupported(UnsupportedError::from_format_and_kind(
                    ImageFormat::Tiff.into(),
                    UnsupportedErrorKind::GenericFeature(desc.to_string()),
                ))
            }
            tiff::TiffError::LimitsExceeded => {
                ImageError::Limits(LimitError::from_kind(LimitErrorKind::InsufficientMemory))
            }
        }
    }

    fn from_tiff_encode(err: tiff::TiffError) -> ImageError {
        match err {
            tiff::TiffError::IoError(err) => ImageError::IoError(err),
            err @ tiff::TiffError::FormatError(_)
            | err @ tiff::TiffError::IntSizeError
            | err @ tiff::TiffError::UsageError(_) => {
                ImageError::Encoding(EncodingError::new(ImageFormat::Tiff.into(), err))
            }
            tiff::TiffError::UnsupportedError(desc) => {
                ImageError::Unsupported(UnsupportedError::from_format_and_kind(
                    ImageFormat::Tiff.into(),
                    UnsupportedErrorKind::GenericFeature(desc.to_string()),
                ))
            }
            tiff::TiffError::LimitsExceeded => {
                ImageError::Limits(LimitError::from_kind(LimitErrorKind::InsufficientMemory))
            }
        }
    }
}

/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct TiffReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for TiffReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        if self.0.position() == 0 && buf.is_empty() {
            mem::swap(buf, self.0.get_mut());
            Ok(buf.len())
        } else {
            self.0.read_to_end(buf)
        }
    }
}

impl<'a, R: 'a + Read + Seek> ImageDecoder<'a> for TiffDecoder<R> {
    type Reader = TiffReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        self.dimensions
    }

    fn color_type(&self) -> ColorType {
        self.color_type
    }

    fn set_limits(&mut self, limits: crate::io::Limits) -> ImageResult<()> {
        limits.check_support(&crate::io::LimitSupport::default())?;

        let (width, height) = self.dimensions();
        limits.check_dimensions(width, height)?;

        let max_alloc = limits.max_alloc.unwrap_or(u64::MAX);
        let max_intermediate_alloc = max_alloc.saturating_sub(self.total_bytes());

        let mut tiff_limits: tiff::decoder::Limits = Default::default();
        tiff_limits.decoding_buffer_size =
            usize::try_from(max_alloc - max_intermediate_alloc).unwrap_or(usize::MAX);
        tiff_limits.intermediate_buffer_size =
            usize::try_from(max_intermediate_alloc).unwrap_or(usize::MAX);
        tiff_limits.ifd_value_size = tiff_limits.intermediate_buffer_size;
        self.inner = Some(self.inner.take().unwrap().with_limits(tiff_limits));

        Ok(())
    }

    fn into_reader(self) -> ImageResult<Self::Reader> {
        let buf = match self
            .inner
            .unwrap()
            .read_image()
            .map_err(ImageError::from_tiff_decode)?
        {
            tiff::decoder::DecodingResult::U8(v) => v,
            tiff::decoder::DecodingResult::U16(v) => utils::vec_copy_to_u8(&v),
            tiff::decoder::DecodingResult::U32(v) => utils::vec_copy_to_u8(&v),
            tiff::decoder::DecodingResult::U64(v) => utils::vec_copy_to_u8(&v),
            tiff::decoder::DecodingResult::I8(v) => utils::vec_copy_to_u8(&v),
            tiff::decoder::DecodingResult::I16(v) => utils::vec_copy_to_u8(&v),
            tiff::decoder::DecodingResult::I32(v) => utils::vec_copy_to_u8(&v),
            tiff::decoder::DecodingResult::I64(v) => utils::vec_copy_to_u8(&v),
            tiff::decoder::DecodingResult::F32(v) => utils::vec_copy_to_u8(&v),
            tiff::decoder::DecodingResult::F64(v) => utils::vec_copy_to_u8(&v),
        };

        Ok(TiffReader(Cursor::new(buf), PhantomData))
    }

    fn read_image(self, buf: &mut [u8]) -> ImageResult<()> {
        assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));
        match self
            .inner
            .unwrap()
            .read_image()
            .map_err(ImageError::from_tiff_decode)?
        {
            tiff::decoder::DecodingResult::U8(v) => {
                buf.copy_from_slice(&v);
            }
            tiff::decoder::DecodingResult::U16(v) => {
                buf.copy_from_slice(bytemuck::cast_slice(&v));
            }
            tiff::decoder::DecodingResult::U32(v) => {
                buf.copy_from_slice(bytemuck::cast_slice(&v));
            }
            tiff::decoder::DecodingResult::U64(v) => {
                buf.copy_from_slice(bytemuck::cast_slice(&v));
            }
            tiff::decoder::DecodingResult::I8(v) => {
                buf.copy_from_slice(bytemuck::cast_slice(&v));
            }
            tiff::decoder::DecodingResult::I16(v) => {
                buf.copy_from_slice(bytemuck::cast_slice(&v));
            }
            tiff::decoder::DecodingResult::I32(v) => {
                buf.copy_from_slice(bytemuck::cast_slice(&v));
            }
            tiff::decoder::DecodingResult::I64(v) => {
                buf.copy_from_slice(bytemuck::cast_slice(&v));
            }
            tiff::decoder::DecodingResult::F32(v) => {
                buf.copy_from_slice(bytemuck::cast_slice(&v));
            }
            tiff::decoder::DecodingResult::F64(v) => {
                buf.copy_from_slice(bytemuck::cast_slice(&v));
            }
        }
        Ok(())
    }
}

/// Encoder for tiff images
pub struct TiffEncoder<W> {
    w: W,
}

// Utility to simplify and deduplicate error handling during 16-bit encoding.
fn u8_slice_as_u16(buf: &[u8]) -> ImageResult<&[u16]> {
    bytemuck::try_cast_slice(buf).map_err(|err| {
        // If the buffer is not aligned or the correct length for a u16 slice, err.
        //
        // `bytemuck::PodCastError` of bytemuck-1.2.0 does not implement
        // `Error` and `Display` trait.
        // See <https://github.com/Lokathor/bytemuck/issues/22>.
        ImageError::Parameter(ParameterError::from_kind(ParameterErrorKind::Generic(
            format!("{:?}", err),
        )))
    })
}

impl<W: Write + Seek> TiffEncoder<W> {
    /// Create a new encoder that writes its output to `w`
    pub fn new(w: W) -> TiffEncoder<W> {
        TiffEncoder { w }
    }

    /// Encodes the image `image` that has dimensions `width` and `height` and `ColorType` `c`.
    ///
    /// 16-bit types assume the buffer is native endian.
    pub fn encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> ImageResult<()> {
        let mut encoder =
            tiff::encoder::TiffEncoder::new(self.w).map_err(ImageError::from_tiff_encode)?;
        match color {
            ColorType::L8 => {
                encoder.write_image::<tiff::encoder::colortype::Gray8>(width, height, data)
            }
            ColorType::Rgb8 => {
                encoder.write_image::<tiff::encoder::colortype::RGB8>(width, height, data)
            }
            ColorType::Rgba8 => {
                encoder.write_image::<tiff::encoder::colortype::RGBA8>(width, height, data)
            }
            ColorType::L16 => encoder.write_image::<tiff::encoder::colortype::Gray16>(
                width,
                height,
                u8_slice_as_u16(data)?,
            ),
            ColorType::Rgb16 => encoder.write_image::<tiff::encoder::colortype::RGB16>(
                width,
                height,
                u8_slice_as_u16(data)?,
            ),
            ColorType::Rgba16 => encoder.write_image::<tiff::encoder::colortype::RGBA16>(
                width,
                height,
                u8_slice_as_u16(data)?,
            ),
            _ => {
                return Err(ImageError::Unsupported(
                    UnsupportedError::from_format_and_kind(
                        ImageFormat::Tiff.into(),
                        UnsupportedErrorKind::Color(color.into()),
                    ),
                ))
            }
        }
        .map_err(ImageError::from_tiff_encode)?;

        Ok(())
    }
}

impl<W: Write + Seek> ImageEncoder for TiffEncoder<W> {
    fn write_image(
        self,
        buf: &[u8],
        width: u32,
        height: u32,
        color_type: ColorType,
    ) -> ImageResult<()> {
        self.encode(buf, width, height, color_type)
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Command Buffer device interface

use attrib;
use back;
use shade;
use target;
use tex;

type Offset = u32;
type Size = u32;

/// The place of some data in the data buffer.
#[deriving(PartialEq, Show)]
pub struct DataPointer(Offset, Size);

/// A buffer of data accompanying the commands. It can be vertex data, texture
/// updates, uniform blocks, or even some draw states.
pub struct DataBuffer {
    buf: Vec<u8>,
}

impl DataBuffer {
    /// Create a fresh new data buffer.
    pub fn new() -> DataBuffer {
        DataBuffer {
            buf: Vec::new(),
        }
    }

    /// Clear all the data but retain the allocated storage.
    pub fn clear(&mut self) {
        self.buf.clear();
    }

    /// Copy a given structure into the buffer, return the offset and the size.
    #[inline(always)]
    pub fn add_struct<T: Copy>(&mut self, v: &T) -> DataPointer {
        use std::slice::ref_slice;
        self.add_vec(ref_slice(v))
    }

    /// Copy a given vector slice into the buffer
    pub fn add_vec<T: Copy>(&mut self, v: &[T]) -> DataPointer {
        use std::mem;
        use std::slice::raw::buf_as_slice;
        let offset = self.buf.len();
        let size = mem::size_of::<T>() * v.len();
        self.buf.reserve_additional(size);
        unsafe {
            self.buf.set_len(offset + size);
            buf_as_slice(v.as_ptr() as *const u8, size,
                |slice|
                self.buf.slice_from_mut(offset).copy_memory(slice)
            );
        }
        DataPointer(offset as Offset, size as Size)
    }

    /// Return a reference to a stored data object.
    pub fn get_ref(&self, data: DataPointer) -> &[u8] {
        let DataPointer(offset, size) = data;
        self.buf.slice(offset as uint, offset as uint + size as uint)
    }
}

#[allow(missing_doc)]    //TODO
pub trait CommandBuffer {
    /// An empty constructor
    fn new() -> Self;
    /// Clear the command buffer contents, retain the allocated storage
    fn clear(&mut self);
    fn bind_program(&mut self, back::Program);
    fn bind_array_buffer(&mut self, back::ArrayBuffer);
    fn bind_attribute(&mut self, ::AttributeSlot, back::Buffer, attrib::Format);
    fn bind_index(&mut self, back::Buffer);
    fn bind_frame_buffer(&mut self, target::Access, back::FrameBuffer);
    /// Unbind any surface from the specified target slot
    fn unbind_target(&mut self, target::Access, target::Target);
    /// Bind a surface to the specified target slot
    fn bind_target_surface(&mut self, target::Access, target::Target, back::Surface);
    /// Bind a level of the texture to the specified target slot
    fn bind_target_texture(&mut self, target::Access, target::Target, back::Texture,
                           target::Level, Option<target::Layer>);
    fn bind_uniform_block(&mut self, back::Program, ::UniformBufferSlot,
                          ::UniformBlockIndex, back::Buffer);
    fn bind_uniform(&mut self, shade::Location, shade::UniformValue);
    fn bind_texture(&mut self, ::TextureSlot, tex::TextureKind, back::Texture,
                    Option<::SamplerHandle>);
    fn set_primitive(&mut self, ::state::Primitive);
    fn set_viewport(&mut self, target::Rect);
    fn set_multi_sample(&mut self, Option<::state::MultiSample>);
    fn set_scissor(&mut self, Option<target::Rect>);
    fn set_depth_stencil(&mut self, Option<::state::Depth>,
                         Option<::state::Stencil>, ::state::CullMode);
    fn set_blend(&mut self, Option<::state::Blend>);
    fn set_color_mask(&mut self, ::state::ColorMask);
    fn update_buffer(&mut self, back::Buffer, DataPointer, uint);
    fn update_texture(&mut self, tex::TextureKind, back::Texture,
                      tex::ImageInfo, DataPointer);
    fn call_clear(&mut self, target::ClearData, target::Mask);
    fn call_draw(&mut self, ::PrimitiveType, ::VertexCount, ::VertexCount,
                 Option<::InstanceCount>);
    fn call_draw_indexed(&mut self, ::PrimitiveType, ::IndexType, ::IndexCount,
                         ::IndexCount, Option<::InstanceCount>);
    fn call_blit(&mut self, target::Rect, target::Rect, target::Mask);
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_data_buffer() {
        let mut buf = super::DataBuffer::new();
        assert_eq!(buf.add_struct(&(0u, false)), super::DataPointer(0, 16));
        assert_eq!(buf.add_vec(&[5i, 6i]), super::DataPointer(16, 16));
    }
}
<commit_msg>Optimize DataBuffer clear<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Command Buffer device interface

use attrib;
use back;
use shade;
use target;
use tex;

type Offset = u32;
type Size = u32;

/// The place of some data in the data buffer.
#[deriving(PartialEq, Show)]
pub struct DataPointer(Offset, Size);

/// A buffer of data accompanying the commands. It can be vertex data, texture
/// updates, uniform blocks, or even some draw states.
pub struct DataBuffer {
    buf: Vec<u8>,
}

impl DataBuffer {
    /// Create a fresh new data buffer.
    pub fn new() -> DataBuffer {
        DataBuffer {
            buf: Vec::new(),
        }
    }

    /// Clear all the data but retain the allocated storage.
    pub fn clear(&mut self) {
        unsafe { self.buf.set_len(0); }
    }

    /// Copy a given structure into the buffer, return the offset and the size.
    #[inline(always)]
    pub fn add_struct<T: Copy>(&mut self, v: &T) -> DataPointer {
        use std::slice::ref_slice;
        self.add_vec(ref_slice(v))
    }

    /// Copy a given vector slice into the buffer
    pub fn add_vec<T: Copy>(&mut self, v: &[T]) -> DataPointer {
        use std::mem;
        use std::slice::raw::buf_as_slice;
        let offset = self.buf.len();
        let size = mem::size_of::<T>() * v.len();
        self.buf.reserve_additional(size);
        unsafe {
            self.buf.set_len(offset + size);
            buf_as_slice(v.as_ptr() as *const u8, size,
                |slice|
                self.buf.slice_from_mut(offset).copy_memory(slice)
            );
        }
        DataPointer(offset as Offset, size as Size)
    }

    /// Return a reference to a stored data object.
    pub fn get_ref(&self, data: DataPointer) -> &[u8] {
        let DataPointer(offset, size) = data;
        self.buf.slice(offset as uint, offset as uint + size as uint)
    }
}

#[allow(missing_doc)]    //TODO
pub trait CommandBuffer {
    /// An empty constructor
    fn new() -> Self;
    /// Clear the command buffer contents, retain the allocated storage
    fn clear(&mut self);
    fn bind_program(&mut self, back::Program);
    fn bind_array_buffer(&mut self, back::ArrayBuffer);
    fn bind_attribute(&mut self, ::AttributeSlot, back::Buffer, attrib::Format);
    fn bind_index(&mut self, back::Buffer);
    fn bind_frame_buffer(&mut self, target::Access, back::FrameBuffer);
    /// Unbind any surface from the specified target slot
    fn unbind_target(&mut self, target::Access, target::Target);
    /// Bind a surface to the specified target slot
    fn bind_target_surface(&mut self, target::Access, target::Target, back::Surface);
    /// Bind a level of the texture to the specified target slot
    fn bind_target_texture(&mut self, target::Access, target::Target, back::Texture,
                           target::Level, Option<target::Layer>);
    fn bind_uniform_block(&mut self, back::Program, ::UniformBufferSlot,
                          ::UniformBlockIndex, back::Buffer);
    fn bind_uniform(&mut self, shade::Location, shade::UniformValue);
    fn bind_texture(&mut self, ::TextureSlot, tex::TextureKind, back::Texture,
                    Option<::SamplerHandle>);
    fn set_primitive(&mut self, ::state::Primitive);
    fn set_viewport(&mut self, target::Rect);
    fn set_multi_sample(&mut self, Option<::state::MultiSample>);
    fn set_scissor(&mut self, Option<target::Rect>);
    fn set_depth_stencil(&mut self, Option<::state::Depth>,
                         Option<::state::Stencil>, ::state::CullMode);
    fn set_blend(&mut self, Option<::state::Blend>);
    fn set_color_mask(&mut self, ::state::ColorMask);
    fn update_buffer(&mut self, back::Buffer, DataPointer, uint);
    fn update_texture(&mut self, tex::TextureKind, back::Texture,
                      tex::ImageInfo, DataPointer);
    fn call_clear(&mut self, target::ClearData, target::Mask);
    fn call_draw(&mut self, ::PrimitiveType, ::VertexCount, ::VertexCount,
                 Option<::InstanceCount>);
    fn call_draw_indexed(&mut self, ::PrimitiveType, ::IndexType, ::IndexCount,
                         ::IndexCount, Option<::InstanceCount>);
    fn call_blit(&mut self, target::Rect, target::Rect, target::Mask);
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_data_buffer() {
        let mut buf = super::DataBuffer::new();
        assert_eq!(buf.add_struct(&(0u, false)), super::DataPointer(0, 16));
        assert_eq!(buf.add_vec(&[5i, 6i]), super::DataPointer(16, 16));
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate orbclient;
extern crate orbtk;

use orbtk::{Action, Button, Menu, Point, Rect, Separator, TextBox, Window};
use orbtk::traits::{Click, Place, Text};

use std::{cmp, env};
use std::fs::File;
use std::io::{Read, Write};

fn main(){
    let path_option = env::args().nth(1);

    let title = if let Some(ref path) = path_option {
        format!("{} - Editor", path)
    } else {
        format!("Editor")
    };

    let (display_width, display_height) = orbclient::get_display_size().expect("viewer: failed to get display size");
    let (width, height) = (cmp::min(1024, display_width * 4/5), cmp::min(768, display_height * 4/5));

    let mut window = Window::new(Rect::new(-1, -1, width, height), &title);

    let text_box = TextBox::new();
    text_box.position(0, 16)
        .size(width, height - 16);
    window.add(&text_box);

    if let Some(ref path) = path_option {
        match File::open(path) {
            Ok(mut file) => {
                let mut text = String::new();
                match file.read_to_string(&mut text) {
                    Ok(_) => text_box.text.set(text),
                    Err(err) => println!("Failed to read {}: {}", path, err)
                }
            },
            Err(err) => println!("Failed to open {}: {}", path, err)
        }
    }

    let menu = Menu::new("File");
    menu.position(0, 0).size(32, 16);

    let open_action = Action::new("Open");
    let open_text_box = text_box.clone();
    open_action.on_click(move |_action: &Action, _point: Point| {
        println!("Open");
        let mut window = Window::new(Rect::new(-1, -1, 220, 32), "Open");

        let path_box = TextBox::new();
        path_box.position(0, 0)
            .size(220, 16);
        window.add(&path_box);

        {
            let window_cancel = &mut window as *mut Window;
            let button = Button::new();
            button.position(0, 16)
                .size(220/2, 16)
                .text("Cancel")
                .on_click(move |_button: &Button, _point: Point| {
                    unsafe { (&mut *window_cancel).close(); }
                });
            window.add(&button);
        }

        {
            let open_text_box = open_text_box.clone();
            let window_save_as = &mut window as *mut Window;
            let button = Button::new();
            button.position(220/2, 16)
                .size(220/2, 16)
                .text("Open")
                .on_click(move |_button: &Button, _point: Point| {
                    match File::open(path_box.text.get()) {
                        Ok(mut f) => {
                            let mut contents = String::new();
                            f.read_to_string(&mut contents).expect("Cannot read file");
                            open_text_box.text.set(contents);
                        },
                        Err(e) => {
                            println!("File does not exist: {}", e);
                        }
                    }
                    unsafe { (&mut *window_save_as).close(); }
                });
            window.add(&button);
        }

        window.exec();

    });
    menu.add(&open_action);

    menu.add(&Separator::new());

    let save_action = Action::new("Save");
    let save_path_option = path_option.clone();
    let save_text_box = text_box.clone();
    save_action.on_click(move |_action: &Action, _point: Point| {
        println!("Save");
        if let Some(ref path) = save_path_option {
            println!("Create {}", path);
            match File::create(path) {
                Ok(mut file) => {
                    let text = save_text_box.text.borrow();
                    match file.write(&text.as_bytes()) {
                        Ok(_) => match file.set_len(text.len() as u64) {
                            Ok(_) => println!("Successfully saved {}", path),
                            Err(err) => println!("Failed to truncate {}: {}", path, err)
                        },
                        Err(err) => println!("Failed to write {}: {}", path, err)
                    }
                },
                Err(err) => println!("Failed to open {}: {}", path, err)
            }
        } else {
            println!("Need to create file!");
        }
    });
    menu.add(&save_action);

    let save_as_action = Action::new("Save As");
    let save_as_path_option = path_option.clone();
    save_as_action.on_click(move |_action: &Action, _point: Point| {
        println!("Save As");
        let mut window = Window::new(Rect::new(-1, -1, 320, 32), "Save As");

        let text_box = TextBox::new();
        text_box.position(0, 0)
            .size(320, 16);
        window.add(&text_box);

        if let Some(ref path) = save_as_path_option {
            text_box.text.set(path.clone());
        }

        {
            let window_cancel = &mut window as *mut Window;
            let button = Button::new();
            button.position(0, 16)
                .size(320/2, 16)
                .text("Cancel")
                .on_click(move |_button: &Button, _point: Point| {
                    unsafe { (&mut *window_cancel).close(); }
                });
            window.add(&button);
        }

        {
            let window_save_as = &mut window as *mut Window;
            let button = Button::new();
            button.position(320/2, 16)
                .size(320/2, 16)
                .text("Save As")
                .on_click(move |_button: &Button, _point: Point| {
                    println!("Save {}", text_box.text.get());
                    unsafe { (&mut *window_save_as).close(); }
                });
            window.add(&button);
        }

        window.exec();
    });
    menu.add(&save_as_action);

    menu.add(&Separator::new());

    let close_action = Action::new("Close");
    let window_close = &mut window as *mut Window;
    close_action.on_click(move |_action: &Action, _point: Point| {
        println!("Close");
        unsafe { (&mut *window_close).close(); }
    });
    menu.add(&close_action);

    window.add(&menu);

    window.exec();
}
<commit_msg>Resize editor<commit_after>#![deny(warnings)]

extern crate orbclient;
extern crate orbtk;

use orbclient::WindowFlag;
use orbtk::{Action, Button, Menu, Point, Rect, Separator, TextBox, Window};
use orbtk::traits::{Click, Place, Resize, Text};

use std::{cmp, env};
use std::fs::File;
use std::io::{Read, Write};

fn main(){
    let path_option = env::args().nth(1);

    let title = if let Some(ref path) = path_option {
        format!("{} - Editor", path)
    } else {
        format!("Editor")
    };

    let (display_width, display_height) = orbclient::get_display_size().expect("viewer: failed to get display size");
    let (width, height) = (cmp::min(1024, display_width * 4/5), cmp::min(768, display_height * 4/5));

    let mut window = Window::new_flags(Rect::new(-1, -1, width, height), &title, &[WindowFlag::Resizable]);

    let text_box = TextBox::new();
    text_box.position(0, 16)
        .size(width, height - 16);
    window.add(&text_box);

    if let Some(ref path) = path_option {
        match File::open(path) {
            Ok(mut file) => {
                let mut text = String::new();
                match file.read_to_string(&mut text) {
                    Ok(_) => text_box.text.set(text),
                    Err(err) => println!("Failed to read {}: {}", path, err)
                }
            },
            Err(err) => println!("Failed to open {}: {}", path, err)
        }
    }

    let menu = Menu::new("File");
    menu.position(0, 0).size(32, 16);

    let open_action = Action::new("Open");
    let open_text_box = text_box.clone();
    open_action.on_click(move |_action: &Action, _point: Point| {
        println!("Open");
        let mut window = Window::new(Rect::new(-1, -1, 220, 32), "Open");

        let path_box = TextBox::new();
        path_box.position(0, 0)
            .size(220, 16);
        window.add(&path_box);

        {
            let window_cancel = &mut window as *mut Window;
            let button = Button::new();
            button.position(0, 16)
                .size(220/2, 16)
                .text("Cancel")
                .on_click(move |_button: &Button, _point: Point| {
                    unsafe { (&mut *window_cancel).close(); }
                });
            window.add(&button);
        }

        {
            let open_text_box = open_text_box.clone();
            let window_save_as = &mut window as *mut Window;
            let button = Button::new();
            button.position(220/2, 16)
                .size(220/2, 16)
                .text("Open")
                .on_click(move |_button: &Button, _point: Point| {
                    match File::open(path_box.text.get()) {
                        Ok(mut f) => {
                            let mut contents = String::new();
                            f.read_to_string(&mut contents).expect("Cannot read file");
                            open_text_box.text.set(contents);
                        },
                        Err(e) => {
                            println!("File does not exist: {}", e);
                        }
                    }
                    unsafe { (&mut *window_save_as).close(); }
                });
            window.add(&button);
        }

        window.exec();

    });
    menu.add(&open_action);

    menu.add(&Separator::new());

    let save_action = Action::new("Save");
    let save_path_option = path_option.clone();
    let save_text_box = text_box.clone();
    save_action.on_click(move |_action: &Action, _point: Point| {
        println!("Save");
        if let Some(ref path) = save_path_option {
            println!("Create {}", path);
            match File::create(path) {
                Ok(mut file) => {
                    let text = save_text_box.text.borrow();
                    match file.write(&text.as_bytes()) {
                        Ok(_) => match file.set_len(text.len() as u64) {
                            Ok(_) => println!("Successfully saved {}", path),
                            Err(err) => println!("Failed to truncate {}: {}", path, err)
                        },
                        Err(err) => println!("Failed to write {}: {}", path, err)
                    }
                },
                Err(err) => println!("Failed to open {}: {}", path, err)
            }
        } else {
            println!("Need to create file!");
        }
    });
    menu.add(&save_action);

    let save_as_action = Action::new("Save As");
    let save_as_path_option = path_option.clone();
    save_as_action.on_click(move |_action: &Action, _point: Point| {
        println!("Save As");
        let mut window = Window::new(Rect::new(-1, -1, 320, 32), "Save As");

        let text_box = TextBox::new();
        text_box.position(0, 0)
            .size(320, 16);
        window.add(&text_box);

        if let Some(ref path) = save_as_path_option {
            text_box.text.set(path.clone());
        }

        {
            let window_cancel = &mut window as *mut Window;
            let button = Button::new();
            button.position(0, 16)
                .size(320/2, 16)
                .text("Cancel")
                .on_click(move |_button: &Button, _point: Point| {
                    unsafe { (&mut *window_cancel).close(); }
                });
            window.add(&button);
        }

        {
            let window_save_as = &mut window as *mut Window;
            let button = Button::new();
            button.position(320/2, 16)
                .size(320/2, 16)
                .text("Save As")
                .on_click(move |_button: &Button, _point: Point| {
                    println!("Save {}", text_box.text.get());
                    unsafe { (&mut *window_save_as).close(); }
                });
            window.add(&button);
        }

        window.exec();
    });
    menu.add(&save_as_action);

    menu.add(&Separator::new());

    let close_action = Action::new("Close");
    let window_close = &mut window as *mut Window;
    close_action.on_click(move |_action: &Action, _point: Point| {
        println!("Close");
        unsafe { (&mut *window_close).close(); }
    });
    menu.add(&close_action);

    window.add(&menu);

    window.on_resize(move |_, width, height| {
        text_box.size(width, height - 16);
    });

    window.exec();
}
<|endoftext|>


<commit_before>use engine::Game;
use gui::screens::{self, Screen, ScreenChange};
use gui::{Console, Colors, Key};
use gui::chars;
use util::Rectangle;
use util::units::{Direction, Point, Size};

#[allow(missing_copy_implementations)]
pub struct GameScreen {
    map_frame: Rectangle,
    info_frame: Rectangle,
    message_frame: Rectangle,
}

impl GameScreen {
    pub fn new() -> Box<Screen> {
        Box::new(
            GameScreen {
                map_frame: Rectangle::new(Point::new(16, 1), Size::new(63, 38)),
                info_frame: Rectangle::new(Point::new(1, 1), Size::new(13, 48)),
                message_frame: Rectangle::new(Point::new(16, 41), Size::new(63, 8)),
            }
        )
    }
}

impl Screen for GameScreen {

    #[allow(unused)]
    fn input(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        if let Some(key) = console.check_for_keypress() {
            match key {
                Key::Up => {
                    game.world.walk(Direction::Up);
                },
                Key::Down => {
                    game.world.walk(Direction::Down);
                },
                Key::Left => {
                    game.world.walk(Direction::Left);
                },
                Key::Right => {
                    game.world.walk(Direction::Right);
                },
                Key::Escape => {
                    return Some(ScreenChange::AddScreen(screens::PauseScreen::new()));
                },
                _ => {}
            }
        }

        None
    }

    #[allow(unused)]
    fn update(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        None
    }

    #[allow(unused)]
    fn render(&mut self, game: &mut Game, console: &mut Console) {
        self.render_map(game, console);

        let repr = game.world.player.repr;
        let pos = game.world.player.pos;

        console.put_plain(self.map_frame.location() + pos, repr);

        self.draw_borders(game, console);
    }
}

impl GameScreen {

    #[allow(unused)]
    fn draw_borders(&self, game: &mut Game, console: &mut Console) {
        self.draw_box(console, self.map_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.map_frame.move_dir(Point::new(0, -1)).location(), "Map");

        self.draw_box(console, self.info_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.info_frame.move_dir(Point::new(0, -1)).location(), "Info");

        self.draw_box(console, self.message_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.message_frame.move_dir(Point::new(0, -1)).location(), "Messages");
    }

    fn draw_box(&self, console: &mut Console, rect: Rectangle) {
        console.put_plain(rect.location() + Point::new(0, 0), chars::NW);
        console.put_plain(rect.location() + Point::new(rect.width(), 0), chars::NE);
        console.put_plain(rect.location() + Point::new(0, rect.height()), chars::SW);
        console.put_plain(rect.location() + Point::new(rect.width(), rect.height()), chars::SE);

        for x in 1..rect.width() {
            console.put_plain(rect.location() + Point::new(x, 0), chars::HLINE);
            console.put_plain(rect.location() + Point::new(x, rect.height()), chars::HLINE);
        }

        for y in 1..rect.height() {
            console.put_plain(rect.location() + Point::new(0, y), chars::VLINE);
            console.put_plain(rect.location() + Point::new(rect.width(), y), chars::VLINE);
        }
    }

    #[allow(unused)]
    fn render_map(&self, game: &mut Game, console: &mut Console) {
        let map = &(game.world.map);

        let (width, height) = (63, 38);

        for (y, line) in map.tiles[0..height].iter().enumerate() {
            for (x, cell) in line[0..width].iter().enumerate() {
                console.put(self.map_frame.location() + Point::new(x as i32, y as i32), ' ', Colors::white, cell.b_color());
            }
        }
    }

}
<commit_msg>Base map location on a view into the map<commit_after>use engine::Game;
use gui::screens::{self, Screen, ScreenChange};
use gui::{Console, Colors, Key};
use gui::chars;
use util::Rectangle;
use util::units::{Direction, Point, Size};

#[allow(missing_copy_implementations)]
pub struct GameScreen {
    map_frame: Rectangle,
    map_view: Point,
    info_frame: Rectangle,
    message_frame: Rectangle,
}

impl GameScreen {
    pub fn new() -> Box<Screen> {
        Box::new(
            GameScreen {
                map_frame: Rectangle::new(Point::new(16, 1), Size::new(63, 38)),
                map_view: Point::new(0, 0),
                info_frame: Rectangle::new(Point::new(1, 1), Size::new(13, 48)),
                message_frame: Rectangle::new(Point::new(16, 41), Size::new(63, 8)),
            }
        )
    }
}

impl Screen for GameScreen {

    #[allow(unused)]
    fn input(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        if let Some(key) = console.check_for_keypress() {
            match key {
                Key::Up => {
                    game.world.walk(Direction::Up);
                },
                Key::Down => {
                    game.world.walk(Direction::Down);
                },
                Key::Left => {
                    game.world.walk(Direction::Left);
                },
                Key::Right => {
                    game.world.walk(Direction::Right);
                },
                Key::Escape => {
                    return Some(ScreenChange::AddScreen(screens::PauseScreen::new()));
                },
                _ => {}
            }
        }

        None
    }

    #[allow(unused)]
    fn update(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        None
    }

    #[allow(unused)]
    fn render(&mut self, game: &mut Game, console: &mut Console) {
        self.render_map(game, console);

        let repr = game.world.player.repr;
        let pos = game.world.player.pos;

        console.put_plain(self.map_frame.location() + pos, repr);

        self.draw_borders(game, console);
    }
}

impl GameScreen {

    #[allow(unused)]
    fn draw_borders(&self, game: &mut Game, console: &mut Console) {
        self.draw_box(console, self.map_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.map_frame.move_dir(Point::new(0, -1)).location(), "Map");

        self.draw_box(console, self.info_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.info_frame.move_dir(Point::new(0, -1)).location(), "Info");

        self.draw_box(console, self.message_frame.move_dir(Point::new(-1, -1)).resize(Size::new(1, 1)));
        console.print_plain(self.message_frame.move_dir(Point::new(0, -1)).location(), "Messages");
    }

    fn draw_box(&self, console: &mut Console, rect: Rectangle) {
        console.put_plain(rect.location() + Point::new(0, 0), chars::NW);
        console.put_plain(rect.location() + Point::new(rect.width(), 0), chars::NE);
        console.put_plain(rect.location() + Point::new(0, rect.height()), chars::SW);
        console.put_plain(rect.location() + Point::new(rect.width(), rect.height()), chars::SE);

        for x in 1..rect.width() {
            console.put_plain(rect.location() + Point::new(x, 0), chars::HLINE);
            console.put_plain(rect.location() + Point::new(x, rect.height()), chars::HLINE);
        }

        for y in 1..rect.height() {
            console.put_plain(rect.location() + Point::new(0, y), chars::VLINE);
            console.put_plain(rect.location() + Point::new(rect.width(), y), chars::VLINE);
        }
    }

    #[allow(unused)]
    fn render_map(&self, game: &mut Game, console: &mut Console) {
        let map = &(game.world.map);

        let (width, height) = (63, 38);

        for (y, line) in map.tiles[self.map_view.y as usize .. height].iter().enumerate() {
            for (x, cell) in line[self.map_view.x as usize .. width].iter().enumerate() {
                console.put(self.map_frame.location() + Point::new(x as i32, y as i32), ' ', Colors::white, cell.b_color());
            }
        }
    }

}
<|endoftext|>