<commit_before>#![crate_id = "bindgen"]
#![crate_type = "bin"]
#![feature(phase)]

extern crate bindgen;
#[phase(syntax, link)] extern crate log;
extern crate syntax;

use bindgen::{Logger, generate_bindings, BindgenOptions};
use std::{io, os, path};
use std::default::Default;
use std::io::fs;
use syntax::ast;
use syntax::codemap::DUMMY_SP;
use syntax::print::pprust;
use syntax::print::pp::eof;

struct StdLogger;

impl Logger for StdLogger {
    fn error(&self, msg: &str) {
        error!("{}", msg);
    }

    fn warn(&self, msg: &str) {
        warn!("{}", msg);
    }
}

enum ParseResult {
    CmdUsage,
    ParseOk(BindgenOptions, Box<io::Writer>),
    ParseErr(~str)
}

fn parse_args(args: &[~str]) -> ParseResult {
    let args_len = args.len();

    let mut options: BindgenOptions = Default::default();
    let mut out = box io::BufferedWriter::new(io::stdout()) as Box<io::Writer>;

    if args_len == 0u {
        return CmdUsage;
    }

    let mut ix = 0u;
    while ix < args_len {
        if args[ix].len() > 2 && args[ix].slice_to(2) == "-l" {
            options.links.push(args[ix].slice_from(2).to_owned());
            ix += 1u;
        } else {
            match args[ix].as_slice() {
                "--help" | "-h" => {
                    return CmdUsage;
                }
                "-emit-clang-ast" => {
                  options.emit_ast = true;
                  ix += 1u;
                }
                "-o" => {
                    if ix + 1u >= args_len {
                        return ParseErr("Missing output filename".to_owned());
                    }
                    let path = path::Path::new(args[ix + 1].clone());
                    match fs::File::create(&path) {
                      Ok(f) => { out = box io::BufferedWriter::new(f) as Box<io::Writer>; }
                      Err(_) => { return ParseErr(format!("Open {} failed", args[ix + 1])); }
                    }
                    ix += 2u;
                }
                "-l" => {
                    if ix + 1u >= args_len {
                        return ParseErr("Missing link name".to_owned());
                    }
                    options.links.push(args[ix + 1u].clone());
                    ix += 2u;
                }
                "-match" => {
                    if ix + 1u >= args_len {
                        return ParseErr("Missing match pattern".to_owned());
                    }
                    options.match_pat.push(args[ix + 1u].clone());
                    ix += 2u;
                }
                "-builtins" => {
                    options.builtins = true;
                    ix += 1u;
                }
                "-abi" => {
                    options.abi = args[ix + 1u].clone();
                    ix += 2u;
                }
                "-allow-bitfields" => {
                    options.fail_on_bitfield = false;
                    ix += 1u;
                }
                "-allow-unknown-types" => {
                    options.fail_on_unknown_type = false;
                    ix += 1u;
                }
                _ => {
                    options.clang_args.push(args[ix].clone());
                    ix += 1u;
                }
            }
        }
    }

    return ParseOk(options, out);
}

fn print_usage(bin: ~str) {
    io::stdio::print(format!("Usage: {} [options] input.h", bin) +
"
Options:
    -h or --help          Display help message
    -l <name> or -l<name> Name of a library to link to, can be proivded
                          multiple times
    -o <output.rs>        Write bindings to <output.rs> (default stdout)
    -match <name>         Only output bindings for definitions from files
                          whose name contains <name>
                          If multiple -match options are provided, files
                          matching any rule are bound to.
    -builtins             Output bindings for builtin definitions
                          (for example __builtin_va_list)
    -abi <abi>            Indicate abi of extern functions (default C)
    -allow-bitfields      Don't fail if we encounter a bitfield
                          (default is false, as rust doesn't support bitfields)
    -allow-unknown-types  Don't fail if we encounter types we do not support,
                          instead treat them as void
    -emit-clang-ast       Output the ast (for debugging purposes)

    Options other than stated above are passed to clang.
"
    );
}

#[main]
pub fn main() {
    let mut bind_args = os::args();
    let bin = bind_args.shift().unwrap();

    match parse_args(bind_args.as_slice()) {
        ParseErr(e) => fail!(e),
        CmdUsage => print_usage(bin),
        ParseOk(options, out) => {
            let logger = StdLogger;
            match generate_bindings(options, Some(&logger as &Logger)) {
                Ok(items) => {
                    let module = ast::Mod {
                        inner: DUMMY_SP,
                        view_items: Vec::new(),
                        items: items,
                    };

                    let mut ps = pprust::rust_printer(out);
                    ps.s.out.write("/* automatically generated by rust-bindgen */\n\n".as_bytes());

//    /*let attrs = vec!(mk_attr_list(&mut ctx, "allow", ["dead_code", "non_camel_case_types", "uppercase_variables"]));*/
                    ps.print_mod(&module, &[]);//attrs.as_slice());
                    ps.print_remaining_comments();
                    eof(&mut ps.s);

                    ps.s.out.flush();
                }
                Err(_) => ()
            }
        }
    }
}<commit_msg>Handle printing errors<commit_after>#![crate_id = "bindgen"]
#![crate_type = "bin"]
#![feature(phase)]

extern crate bindgen;
#[phase(syntax, link)] extern crate log;
extern crate syntax;

use bindgen::{Logger, generate_bindings, BindgenOptions};
use std::{io, os, path};
use std::default::Default;
use std::io::{fs, IoResult};
use syntax::ast;
use syntax::codemap::DUMMY_SP;
use syntax::print::pprust;
use syntax::print::pp::eof;

struct StdLogger;

impl Logger for StdLogger {
    fn error(&self, msg: &str) {
        error!("{}", msg);
    }

    fn warn(&self, msg: &str) {
        warn!("{}", msg);
    }
}

enum ParseResult {
    CmdUsage,
    ParseOk(BindgenOptions, Box<io::Writer>),
    ParseErr(~str)
}

fn parse_args(args: &[~str]) -> ParseResult {
    let args_len = args.len();

    let mut options: BindgenOptions = Default::default();
    let mut out = box io::BufferedWriter::new(io::stdout()) as Box<io::Writer>;

    if args_len == 0u {
        return CmdUsage;
    }

    let mut ix = 0u;
    while ix < args_len {
        if args[ix].len() > 2 && args[ix].slice_to(2) == "-l" {
            options.links.push(args[ix].slice_from(2).to_owned());
            ix += 1u;
        } else {
            match args[ix].as_slice() {
                "--help" | "-h" => {
                    return CmdUsage;
                }
                "-emit-clang-ast" => {
                  options.emit_ast = true;
                  ix += 1u;
                }
                "-o" => {
                    if ix + 1u >= args_len {
                        return ParseErr("Missing output filename".to_owned());
                    }
                    let path = path::Path::new(args[ix + 1].clone());
                    match fs::File::create(&path) {
                      Ok(f) => { out = box io::BufferedWriter::new(f) as Box<io::Writer>; }
                      Err(_) => { return ParseErr(format!("Open {} failed", args[ix + 1])); }
                    }
                    ix += 2u;
                }
                "-l" => {
                    if ix + 1u >= args_len {
                        return ParseErr("Missing link name".to_owned());
                    }
                    options.links.push(args[ix + 1u].clone());
                    ix += 2u;
                }
                "-match" => {
                    if ix + 1u >= args_len {
                        return ParseErr("Missing match pattern".to_owned());
                    }
                    options.match_pat.push(args[ix + 1u].clone());
                    ix += 2u;
                }
                "-builtins" => {
                    options.builtins = true;
                    ix += 1u;
                }
                "-abi" => {
                    options.abi = args[ix + 1u].clone();
                    ix += 2u;
                }
                "-allow-bitfields" => {
                    options.fail_on_bitfield = false;
                    ix += 1u;
                }
                "-allow-unknown-types" => {
                    options.fail_on_unknown_type = false;
                    ix += 1u;
                }
                _ => {
                    options.clang_args.push(args[ix].clone());
                    ix += 1u;
                }
            }
        }
    }

    return ParseOk(options, out);
}

fn print_usage(bin: ~str) {
    io::stdio::print(format!("Usage: {} [options] input.h", bin) +
"
Options:
    -h or --help          Display help message
    -l <name> or -l<name> Name of a library to link to, can be proivded
                          multiple times
    -o <output.rs>        Write bindings to <output.rs> (default stdout)
    -match <name>         Only output bindings for definitions from files
                          whose name contains <name>
                          If multiple -match options are provided, files
                          matching any rule are bound to.
    -builtins             Output bindings for builtin definitions
                          (for example __builtin_va_list)
    -abi <abi>            Indicate abi of extern functions (default C)
    -allow-bitfields      Don't fail if we encounter a bitfield
                          (default is false, as rust doesn't support bitfields)
    -allow-unknown-types  Don't fail if we encounter types we do not support,
                          instead treat them as void
    -emit-clang-ast       Output the ast (for debugging purposes)

    Options other than stated above are passed to clang.
"
    );
}

fn try_pprint(module: &ast::Mod, out: Box<io::Writer>) -> IoResult<()> {
    let mut ps = pprust::rust_printer(out);
    try!(ps.s.out.write("/* automatically generated by rust-bindgen */\n\n".as_bytes()));

    try!(ps.print_mod(module, &[]));
    try!(ps.print_remaining_comments());
    try!(eof(&mut ps.s));

    ps.s.out.flush()
}

#[main]
pub fn main() {
    let mut bind_args = os::args();
    let bin = bind_args.shift().unwrap();

    match parse_args(bind_args.as_slice()) {
        ParseErr(e) => fail!(e),
        CmdUsage => print_usage(bin),
        ParseOk(options, out) => {
            let logger = StdLogger;
            match generate_bindings(options, Some(&logger as &Logger)) {
                Ok(items) => {
                    let module = ast::Mod {
                        inner: DUMMY_SP,
                        view_items: Vec::new(),
                        items: items,
                    };

                    match try_pprint(&module, out) {
                        Err(e) => logger.error(format!("Unable to write bindings to file. {}", e)),
                        _ => ()
                    }
                }
                Err(_) => ()
            }
        }
    }
}<|endoftext|>


<commit_before>extern crate builtins;

use std::slice::Iter;
use std::borrow::Cow;

pub fn read(command_line: &str) {
	match tokenize(command_line) {
		Ok(token_list) => {
			let mut token_iter = token_list.iter();
			match generate_tree(&mut token_iter) {
				Ok(mut tree) => tree.execute_command(),
				Err(err) => println_stderr!("Parse error: {}", err),
			}
		},
		Err(err) => println_stderr!("Tokenization error: {}", err),
	}
}

#[derive(Copy, Clone)] // this enum takes 8b therefore copying it is better than having a 32b or 64b pointer
enum TokenMachineState {
	Start,
	StrCmd(usize),
	StrCmdFirstQuote,
	QuotedStrCmd(usize),
	SeparateWs,
	StrArg(usize),
	StrArgFirstQuote,
	QuotedStrArg(usize),
}

#[derive(PartialEq, Debug)] // used for tests
enum Token<'a, 'b> {
	LeftParen,
	RightParen,
	Cmd(&'a str),
	Arg(&'b str),
}

fn tokenize(command_line: &str) -> Result<Vec<Token>, &'static str> {
	use self::TokenMachineState::*;
	use self::Token::*;

	let mut state = Start;
	let mut token_list = Vec::new();

	let mut char_it = command_line.char_indices();

	loop {
		if let Some((i, curr_char)) = char_it.next() {
			match (state, curr_char) {
				(Start, ' ') | (Start, '\t') => {},
				(Start, '(') => token_list.push(LeftParen),
				(Start, ')') => token_list.push(RightParen), // this is invalid but it's the parser's job to find it out
				(Start, '\'') => state = StrCmdFirstQuote,
				(Start, _) => state = StrCmd(i),

				(StrCmdFirstQuote, '\'') => token_list.push(Cmd("")),
				(StrCmdFirstQuote, _) => state = QuotedStrCmd(i),

				(QuotedStrCmd(slice_start), '\'') => {
					token_list.push(Cmd(&command_line[slice_start..i]));
					state = SeparateWs;
				},

				(StrCmd(slice_start), ')') => {
					token_list.push(Cmd(&command_line[slice_start..i]));
					token_list.push(RightParen);
					state = SeparateWs;
				},
				(StrCmd(slice_start), ' ') | (StrCmd(slice_start), '\t') => {
					token_list.push(Cmd(&command_line[slice_start..i]));
					state = SeparateWs;
				},

				(SeparateWs, ' ') | (SeparateWs, '\t') => {},
				(SeparateWs, ')') => token_list.push(RightParen),
				(SeparateWs, '(') => {
					token_list.push(LeftParen);
					state = Start;
				},
				(SeparateWs, '\'') => state = StrArgFirstQuote,
				(SeparateWs, _) => state = StrArg(i),

				(StrArgFirstQuote, '\'') => token_list.push(Arg("")),
				(StrArgFirstQuote, _) => state = QuotedStrArg(i),

				(QuotedStrArg(slice_start), '\'') => {
					token_list.push(Arg(&command_line[slice_start..i]));
					state = SeparateWs;
				},

				(StrArg(slice_start), ' ') | (StrArg(slice_start), '\t') => {
					token_list.push(Arg(&command_line[slice_start..i]));
					state = SeparateWs;
				},
				(StrArg(slice_start), ')') => {
					token_list.push(Arg(&command_line[slice_start..i]));
					token_list.push(RightParen);
					state = SeparateWs;
				}

				(StrCmd(_), '(') | (StrArg(_), '(') => return Err("Unexpected '(' in command or argument"),
				(StrCmd(_), _) | (StrArg(_), _) | (QuotedStrCmd(_), _) | (QuotedStrArg(_), _) => {},
			}
		} else {
			// there might be a last token undergoing the token creation process
			// it has to be appended to the token list
			match state {
				StrCmd(slice_start) => token_list.push(Cmd(&command_line[slice_start..])),
				StrArg(slice_start) => token_list.push(Arg(&command_line[slice_start..])),
				StrArgFirstQuote | StrCmdFirstQuote | QuotedStrCmd(_) | QuotedStrArg(_) => return Err("Unclosed string literal"),
				_ => {},
			}
			break;
		}
	}

	Ok(token_list)
}

#[derive(PartialEq, Copy, Clone)] // this enum takes 8b therefore copying it is better than having a 32b or 64b pointer
enum ParseMachineState {
	Start,
	CollectArg,
	SubcommandEnd,
}

fn generate_tree<'a>(token_iter: &mut Iter<Token<'a, 'a>>) -> Result<Command<'a>, &'static str> {
	use self::ParseMachineState::*;

	let (res, state) = parse(token_iter);

	if state != CollectArg && res.is_ok() { // accepting state when not doing recursion
		Err("Missing matching parenthese")
	} else {
		res
	}
}

fn parse<'a>(token_iter: &mut Iter<Token<'a, 'a>>) -> (Result<Command<'a>, &'static str>, ParseMachineState) {
	use self::ParseMachineState::*;
	use self::Token::*;
	use std::{ptr, mem};

	let mut state = Start;
	let mut cmd = Command::new();

	loop {
		if let Some(token) = token_iter.next() {
			match (state, token) {
				(Start, &Cmd(cmd_name)) => {
					unsafe {
						ptr::write(&mut cmd.cmd, Box::new(Param::Arg(cmd_name)));
					}
					state = CollectArg;
				},
				(Start, &LeftParen) => {
					// do recursion
					let (res, recur_state) = parse(token_iter);
					match res {
						Err(_) => {
							mem::forget(cmd.cmd);
							return (res, state)
						},
						Ok(subcmd) => {
							if recur_state != SubcommandEnd {
								mem::forget(cmd.cmd);
								return (Err("Error in subcommand"), state);
							} else {
								unsafe {
									ptr::write(&mut cmd.cmd, Box::new(Param::Cmd(subcmd)));
								}
								state = CollectArg;
							}
						},
					}
				},
				(Start, &RightParen) => {
					mem::forget(cmd.cmd);
					return (Err("Unexpected ')' at start of (sub)command"), state)
				},
				(Start, &Arg(_)) => unreachable!(), // if that happens the tokenizer is buggy

				(CollectArg, &Arg(arg_str)) => {
					cmd.params.push(Param::Arg(arg_str));
				}
				(CollectArg, &Cmd(_)) => unreachable!(), // if that happens the tokenizer is buggy
				(CollectArg, &RightParen) => {
					return (Ok(cmd), SubcommandEnd);
				},
				(CollectArg, &LeftParen) => {
					//do recursion
					let (res, recur_state) = parse(token_iter);
					match res {
						Err(_) => return (res, state),
						Ok(subcmd) => {
							if recur_state != SubcommandEnd {
								return (Err("Error in subcommand"), state);
							} else {
								cmd.params.push(Param::Cmd(subcmd));
							}
						},
					}
				}

				(SubcommandEnd, _) => unreachable!(),
			}
		} else {
			break;
		}
	}

	if state == Start {
		mem::forget(cmd.cmd);
		(Err("Subcommand never closed"), state)
	} else {
		(Ok(cmd), state)
	}
}

struct Command<'a> {
	cmd: Box<Param<'a>>,
	params: Vec<Param<'a>>,
}
impl<'a> Command<'a> {
	fn new() -> Command<'a> {
		use std::mem;

		unsafe {
			Command {
				cmd: mem::uninitialized(),
				params: Vec::new(),
			}
		}
	}
	fn get_final(&'a mut self) -> (String, Vec<String>) {
		// the calls to `into_owned()` are ugly, is there a way to get rid of them?
		let mut final_arglist: Vec<String> = Vec::with_capacity(self.params.len());

		for arg in self.params.iter_mut() { // substitue subcommands recursively
			final_arglist.push(arg.as_arg().into_owned());
		}

		(self.cmd.as_arg().into_owned(), final_arglist)
	}
	fn execute_command(&'a mut self) {//returns stdout - possibly return a array of strings?
		let (cmd, arglist) = self.get_final();
		let actual_arglist: Vec<&str> = arglist.iter().map(|arg| &arg[..]).collect();

		match &cmd[..] {
			"" => {},
			"cd" => builtins::cd(&actual_arglist),
			"exit" => builtins::exit(&actual_arglist),
			_ => {
				use std::process::Command;
				match Command::new(cmd)
					.args(&actual_arglist)
					.spawn() {
						Ok(mut subproc) => {
							subproc.wait();
						},
						Err(err) => println_stderr!("{}", err),
				}
			},
		};
	}
	fn execute_subcommand(&'a mut self) -> Cow<'a, str> {
		let (cmd, arglist) = self.get_final();
		let actual_arglist: Vec<&str> = arglist.iter().map(|arg| &arg[..]).collect();

		return match &cmd[..] {
			"" => Cow::Borrowed(""),
			"cd" => {
				builtins::cd(&actual_arglist);
				Cow::Borrowed("")
			},
			"exit" => {
				builtins::exit(&actual_arglist);
				Cow::Borrowed("")
			},
			_ => {
				use std::process::Command;
				match Command::new(cmd)
					.args(&actual_arglist)
					.output() {
						Ok(output) => {
							use std::string::String;

							unsafe {
								Cow::Owned(String::from_utf8_unchecked(output.stdout))
							}
						},
						Err(err) => {
							println_stderr!("{}", err);
							Cow::Borrowed("")
						},
				}
			},
		};
	}
}
enum Param<'a> {
	Arg(&'a str),
	Cmd(Command<'a>),

}
impl<'a> Param<'a> {
	fn as_arg(&'a mut self) -> Cow<'a, str> {
		match self {
			&mut Param::Cmd(ref mut subcmd) => subcmd.execute_subcommand(),
			&mut Param::Arg(arg_str) => Cow::Borrowed(arg_str),
		}
	}
}

#[cfg(test)]
mod tests {
	use super::tokenize;
	use super::Token::*;

	#[test]
	fn empty_command() {
		assert_eq!(
			[LeftParen, RightParen],
			tokenize("()").unwrap().as_slice()
		);
	}

	#[test]
	fn tokenize_proper() {
		assert_eq!(
			[Cmd("echo"), Arg("foo"), LeftParen, Cmd("bar"), RightParen],
			tokenize("echo foo (bar)").unwrap().as_slice()
		);

		assert_eq!(
			[Cmd("echo")],
			tokenize("echo").unwrap().as_slice()
		);

		assert_eq!(
			[Cmd("echo"), Arg("foo")],
			tokenize("echo foo").unwrap().as_slice()
		);

		assert_eq!(
			[LeftParen, Cmd("echo"), RightParen, Arg("foo")],
			tokenize("(echo) foo").unwrap().as_slice()
		);
		assert_eq!(
			[LeftParen, Cmd("echo"), Arg("echo"), RightParen, Arg("foo")],
			tokenize("(echo echo) foo").unwrap().as_slice()
		);
	}

	#[test]
	fn tokenize_string_literal() {
		assert_eq!(
			[Cmd("echo hole"), Arg("stuff")],
			tokenize("'echo hole' stuff").unwrap().as_slice()
		);
		assert_eq!(
			[Cmd("echo"), Arg("foo bar")],
			tokenize("echo 'foo bar'").unwrap().as_slice()
		);
		assert_eq!(
			[Cmd("echo"), Arg("foo"), Arg("bar")],
			tokenize("'echo' 'foo' 'bar'").unwrap().as_slice()
		);
		assert_eq!(
			[Cmd("foo bar               baz"), Arg("qux"), Arg(" quux")],
			tokenize("'foo bar               baz' qux ' quux'").unwrap().as_slice()
		);
	}

	#[test]
	#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: \"Unclosed string literal\"")]
	fn tokenize_unclosed_string_literal_cmd() {
		tokenize("'echo foo").unwrap();
	}

	#[test]
	#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: \"Unclosed string literal\"")]
	fn tokenize_unclosed_string_literal_arg() {
		tokenize("echo 'foo bar").unwrap();
	}

	#[test]
	#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: \"Unclosed string literal\"")]
	fn tokenize_unclosed_string_literal_end() {
		tokenize("echo '").unwrap();
	}

	#[test]
	fn tokenize_proper_though_not_for_the_parser() {
		assert_eq!(
			[LeftParen, LeftParen, LeftParen, Cmd("echo"), Arg("lol"), RightParen, RightParen, RightParen, Arg("stuff")],
			tokenize("(((echo lol))) stuff").unwrap().as_slice()
		);
		assert_eq!(
			[Cmd("garbage"), RightParen],
			tokenize("garbage)").unwrap().as_slice()
		);
	}

	#[test]
	#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: \"Unexpected \\'(\\' in command or argument\"")]
	fn tokenize_paren_in_cmd_middle() {
		tokenize("ech(o").unwrap();
	}
	#[test]
	#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: \"Unexpected \\'(\\' in command or argument\"")]
	fn tokenize_paren_in_arg_middle() {
		tokenize("echo oops(typo").unwrap();
	}
	#[test]
	#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: \"Unexpected \\'(\\' in command or argument\"")]
	fn tokenize_paren_in_cmd_end() {
		tokenize("echo( stuff").unwrap();
	}
	#[test]
	#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: \"Unexpected \\'(\\' in command or argument\"")]
	fn tokenize_paren_in_arg_end() {
		tokenize("echo oops(").unwrap();
	}
}
<commit_msg>Remove distinction between `Cmd`s and `Arg`s during tokenization<commit_after>extern crate builtins;

use std::slice::Iter;
use std::borrow::Cow;

type CmdLine<'a> = Vec<Param<'a>>;

pub fn read(command_line: &str) {
	match tokenize(command_line) {
		Ok(token_list) => {
			let mut token_iter = token_list.iter();
			match generate_tree(&mut token_iter) {
				Ok(ref tree) => execute_command(tree),
				Err(err) => println_stderr!("Parse error: {}", err),
			}
		},
		Err(err) => println_stderr!("Tokenization error: {}", err),
	}
}

#[derive(Copy, Clone)] // this enum takes only 1B more than usize so copying it is no big deal
enum TokenMachineState {
	Start,
	SeparateWs,
	StrWord(usize),
	WordFirstQuote,
	QuotedWord(usize),
}

#[derive(PartialEq, Debug)] // used for tests
enum Token<'a> {
	LeftParen,
	RightParen,
	Word(&'a str),
}

fn tokenize(command_line: &str) -> Result<Vec<Token>, &'static str> {
	use self::TokenMachineState::*;
	use self::Token::*;

	let mut state = Start;
	let mut token_list = Vec::new();

	let mut char_it = command_line.char_indices();

	loop {
		if let Some((i, curr_char)) = char_it.next() {
			match (state, curr_char) {
				(Start, ' ') | (Start, '\t') => {},
				(Start, '(') => token_list.push(LeftParen),
				(Start, ')') => token_list.push(RightParen), // this is invalid but it's the parser's job to find it out
				(Start, '\'') => state = WordFirstQuote,
				(Start, _) => state = StrWord(i),

				(WordFirstQuote, '\'') => token_list.push(Word("")),
				(WordFirstQuote, _) => state = QuotedWord(i),

				(QuotedWord(slice_start), '\'') => {
					token_list.push(Word(&command_line[slice_start..i]));
					state = SeparateWs;
				},

				(StrWord(slice_start), ')') => {
					token_list.push(Word(&command_line[slice_start..i]));
					token_list.push(RightParen);
					state = SeparateWs;
				},
				(StrWord(slice_start), ' ') | (StrWord(slice_start), '\t') => {
					token_list.push(Word(&command_line[slice_start..i]));
					state = SeparateWs;
				},
				(StrWord(_), '(') => return Err("Unexpected '(' in command or argument"),
				(StrWord(_), _) | (QuotedWord(_), _) => {},

				(SeparateWs, ' ') | (SeparateWs, '\t') => {},
				(SeparateWs, ')') => token_list.push(RightParen),
				(SeparateWs, '(') => {
					token_list.push(LeftParen);
					state = Start;
				},
				(SeparateWs, '\'') => state = WordFirstQuote,
				(SeparateWs, _) => state = StrWord(i),

			}
		} else {
			// there might be a last token undergoing the token creation process
			// it has to be appended to the token list
			match state {
				StrWord(slice_start) => token_list.push(Word(&command_line[slice_start..])),
				WordFirstQuote | QuotedWord(_) => return Err("Unclosed string literal"),
				_ => {},
			}
			break;
		}
	}

	Ok(token_list)
}

#[derive(PartialEq, Copy, Clone)] // this enum takes 8b therefore copying it is better than having a 32b or 64b pointer
enum ParseMachineState {
	Start,
	CollectArg,
	SubcommandEnd,
}

fn generate_tree<'a>(token_iter: &mut Iter<Token<'a>>) -> Result<CmdLine<'a>, &'static str> {
	use self::ParseMachineState::*;

	let (res, state) = parse(token_iter);

	if state != CollectArg && res.is_ok() { // accepting state when not doing recursion
		Err("Missing matching parenthese")
	} else {
		res
	}
}

fn parse<'a>(token_iter: &mut Iter<Token<'a>>) -> (Result<CmdLine<'a>, &'static str>, ParseMachineState) {
	use self::ParseMachineState::*;
	use self::Token::*;
	use self::Param::*;

	let mut state = Start;
	let mut cmd_line: CmdLine = Vec::new();

	loop {
		if let Some(token) = token_iter.next() {
			match (state, token) {
				(Start, &Word(cmd_name)) | (CollectArg, &Word(cmd_name)) => {
					cmd_line.push(Arg(cmd_name));
					state = CollectArg;
				},
				(Start, &LeftParen) | (CollectArg, &LeftParen) => {
					// do recursion
					let (res, recur_state) = parse(token_iter);
					match res {
						Err(_) => return (res, state),
						Ok(subcmd) => {
							if recur_state != SubcommandEnd {
								return (Err("Error in subcommand"), state);
							} else {
								cmd_line.push(Cmd(subcmd));
								state = CollectArg;
							}
						},
					}
				},
				(Start, &RightParen) => {
					return (Err("Unexpected empty subcommand"), state)
				},

				(CollectArg, &RightParen) => {
					return (Ok(cmd_line), SubcommandEnd);
				},

				(SubcommandEnd, _) => unreachable!(),
			}
		} else {
			break;
		}
	}

	if state == Start {
		(Err("Subcommand never closed"), state)
	} else {
		(Ok(cmd_line), state)
	}
}

fn get_final<'a>(cmd_line: &'a CmdLine<'a>) -> Vec<String> {
	// the calls to `into_owned()` are ugly, is there a way to get rid of them?
	let mut final_arglist: Vec<String> = Vec::with_capacity(cmd_line.len());

	for arg in cmd_line.iter() { // substitue subcommands recursively
		final_arglist.push(arg.as_arg().into_owned());
	}

	final_arglist
}
fn execute_command<'a>(cmd_line: &'a CmdLine<'a>) {//returns stdout - possibly return a array of strings?
	let arglist = get_final(cmd_line);
	let actual_arglist: Vec<&str> = arglist.iter().map(|arg| &arg[..]).collect();

	match actual_arglist[0] { // there is always at least a command
		"" => {},
		"cd" => builtins::cd(&actual_arglist[1..]),
		"exit" => builtins::exit(&actual_arglist[1..]),
		_ => {
			use std::process::Command;
			match Command::new(actual_arglist[0])
				.args(&actual_arglist[1..])
				.spawn() {
					Ok(mut subproc) => {
						subproc.wait();
					},
					Err(err) => println_stderr!("{}", err),
			}
		},
	};
}
fn execute_subcommand<'a>(cmd_line: &CmdLine<'a>) -> Cow<'a, str> {
	let arglist = get_final(cmd_line);
	let actual_arglist: Vec<&str> = arglist.iter().map(|arg| &arg[..]).collect();

	return match actual_arglist[0] { // ther is always at least a command
		"" => Cow::Borrowed(""),
		"cd" => {
			builtins::cd(&actual_arglist[1..]);
			Cow::Borrowed("")
		},
		"exit" => {
			builtins::exit(&actual_arglist[1..]);
			Cow::Borrowed("")
		},
		_ => {
			use std::process::Command;
			match Command::new(actual_arglist[0])
				.args(&actual_arglist[1..])
				.output() {
					Ok(output) => {
						use std::string::String;

						unsafe {
							Cow::Owned(String::from_utf8_unchecked(output.stdout))
						}
					},
					Err(err) => {
						println_stderr!("{}", err);
						Cow::Borrowed("")
					},
			}
		},
	};
}
enum Param<'a> {
	Arg(&'a str),
	Cmd(CmdLine<'a>),

}
impl<'a> Param<'a> {
	fn as_arg(&'a self) -> Cow<'a, str> {
		match self {
			&Param::Cmd(ref subcmd) => execute_subcommand(subcmd),
			&Param::Arg(arg_str) => Cow::Borrowed(arg_str),
		}
	}
}

#[cfg(test)]
mod tests {
	use super::tokenize;
	use super::Token::*;

	#[test]
	fn empty_command() {
		assert_eq!(
			[LeftParen, RightParen],
			tokenize("()").unwrap().as_slice()
		);
	}

	#[test]
	fn tokenize_proper() {
		assert_eq!(
			[Word("echo"), Word("foo"), LeftParen, Word("bar"), RightParen],
			tokenize("echo foo (bar)").unwrap().as_slice()
		);

		assert_eq!(
			[Word("echo")],
			tokenize("echo").unwrap().as_slice()
		);

		assert_eq!(
			[Word("echo"), Word("foo")],
			tokenize("echo foo").unwrap().as_slice()
		);

		assert_eq!(
			[LeftParen, Word("echo"), RightParen, Word("foo")],
			tokenize("(echo) foo").unwrap().as_slice()
		);
		assert_eq!(
			[LeftParen, Word("echo"), Word("echo"), RightParen, Word("foo")],
			tokenize("(echo echo) foo").unwrap().as_slice()
		);
	}

	#[test]
	fn tokenize_string_literal() {
		assert_eq!(
			[Word("echo hole"), Word("stuff")],
			tokenize("'echo hole' stuff").unwrap().as_slice()
		);
		assert_eq!(
			[Word("echo"), Word("foo bar")],
			tokenize("echo 'foo bar'").unwrap().as_slice()
		);
		assert_eq!(
			[Word("echo"), Word("foo"), Word("bar")],
			tokenize("'echo' 'foo' 'bar'").unwrap().as_slice()
		);
		assert_eq!(
			[Word("foo bar               baz"), Word("qux"), Word(" quux")],
			tokenize("'foo bar               baz' qux ' quux'").unwrap().as_slice()
		);
	}

	#[test]
	#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: \"Unclosed string literal\"")]
	fn tokenize_unclosed_string_literal_cmd() {
		tokenize("'echo foo").unwrap();
	}

	#[test]
	#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: \"Unclosed string literal\"")]
	fn tokenize_unclosed_string_literal_arg() {
		tokenize("echo 'foo bar").unwrap();
	}

	#[test]
	#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: \"Unclosed string literal\"")]
	fn tokenize_unclosed_string_literal_end() {
		tokenize("echo '").unwrap();
	}

	#[test]
	fn tokenize_proper_though_not_for_the_parser() {
		assert_eq!(
			[LeftParen, LeftParen, LeftParen, Word("echo"), Word("lol"), RightParen, RightParen, RightParen, Word("stuff")],
			tokenize("(((echo lol))) stuff").unwrap().as_slice()
		);
		assert_eq!(
			[Word("garbage"), RightParen],
			tokenize("garbage)").unwrap().as_slice()
		);
	}

	#[test]
	#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: \"Unexpected \\'(\\' in command or argument\"")]
	fn tokenize_paren_in_cmd_middle() {
		tokenize("ech(o").unwrap();
	}
	#[test]
	#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: \"Unexpected \\'(\\' in command or argument\"")]
	fn tokenize_paren_in_arg_middle() {
		tokenize("echo oops(typo").unwrap();
	}
	#[test]
	#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: \"Unexpected \\'(\\' in command or argument\"")]
	fn tokenize_paren_in_cmd_end() {
		tokenize("echo( stuff").unwrap();
	}
	#[test]
	#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: \"Unexpected \\'(\\' in command or argument\"")]
	fn tokenize_paren_in_arg_end() {
		tokenize("echo oops(").unwrap();
	}
}
<|endoftext|>


<commit_before>// Claxon -- A FLAC decoding library in Rust
// Copyright 2015 van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

extern crate claxon;
extern crate hound;

use claxon::{Block, FlacReader};
use hound::{WavSpec, WavWriter};
use std::env;
use std::fs::File;
use std::io::{Cursor, Read};
use std::path;

fn main() {
    let arg = env::args().nth(1).expect("no file given");
    let fname = path::Path::new(&arg);
    let mut file = File::open(fname).expect("failed to open FLAC file");

    // Load the entire file into memory at once. This allows using a cursor
    // afterwards to read the data, which is cheaper than mixing IO with the
    // actual FLAC reading due to inlining.
    let mut bytes = Vec::new();
    bytes.reserve(file.metadata().unwrap().len() as usize);
    file.read_to_end(&mut bytes).expect("failed to read FLAC data into memory");

    let data = Cursor::new(bytes);
    let mut reader = FlacReader::new(data).expect("failed to open FLAC stream");

    let spec = WavSpec {
        // TODO: u8 for channels, is that weird? Would u32 be better?
        channels: reader.streaminfo().channels as u16,
        sample_rate: reader.streaminfo().sample_rate,
        // TODO: again, would u32 be better, even if the range is smaller?
        bits_per_sample: reader.streaminfo().bits_per_sample as u16,
        sample_format: hound::SampleFormat::Int,
    };
    let fname_wav = fname.with_extension("wav");
    let mut wav_writer = WavWriter::create(fname_wav, spec).expect("failed to create wav file");
    {
        // TODO: Write fallback for other sample widths.
        assert!(reader.streaminfo().bits_per_sample == 16);
        let mut sample_writer = wav_writer.get_i16_writer();

        let mut frame_reader = reader.blocks();
        let mut block = Block::empty();
        loop {
            // Read a single frame. Recycle the buffer from the previous frame to
            // avoid allocations as much as possible.
            match frame_reader.read_next_or_eof(block.into_buffer()) {
                Ok(Some(next_block)) => block = next_block,
                Ok(None) => break, // EOF.
                Err(error) => panic!("{}", error),
            }

            // Write the samples in the block to the wav file, channels interleaved.
            for s in 0..block.duration() {
                for ch in 0..block.channels() {
                    sample_writer.write_sample(block.sample(ch, s))
                                 .expect("failed to write to wav file");
                }
            }
        }
    }

    wav_writer.finalize().expect("failed to finalize wav file");
}
<commit_msg>Use new Hound API for faster writing in decoder<commit_after>// Claxon -- A FLAC decoding library in Rust
// Copyright 2015 van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

extern crate claxon;
extern crate hound;

use claxon::{Block, FlacReader};
use hound::{WavSpec, WavWriter};
use std::env;
use std::path;

fn main() {
    let arg = env::args().nth(1).expect("no file given");
    let fname = path::Path::new(&arg);
    let mut reader = FlacReader::open(fname).expect("failed to open FLAC stream");

    let spec = WavSpec {
        // TODO: u8 for channels, is that weird? Would u32 be better?
        channels: reader.streaminfo().channels as u16,
        sample_rate: reader.streaminfo().sample_rate,
        // TODO: again, would u32 be better, even if the range is smaller?
        bits_per_sample: reader.streaminfo().bits_per_sample as u16,
        sample_format: hound::SampleFormat::Int,
    };
    let fname_wav = fname.with_extension("wav");
    let mut wav_writer = WavWriter::create(fname_wav, spec).expect("failed to create wav file");
    {
        // TODO: Write fallback for other sample widths.
        assert!(reader.streaminfo().bits_per_sample == 16);
        // TODO: block_size could be confusing. Call it duration instead?
        let max_bs_len = reader.streaminfo().max_block_size as u32 * reader.streaminfo().channels as u32;
        let mut sample_writer = wav_writer.get_i16_writer(max_bs_len);

        let mut frame_reader = reader.blocks();
        let mut block = Block::empty();
        loop {
            // Read a single frame. Recycle the buffer from the previous frame to
            // avoid allocations as much as possible.
            match frame_reader.read_next_or_eof(block.into_buffer()) {
                Ok(Some(next_block)) => block = next_block,
                Ok(None) => break, // EOF.
                Err(error) => panic!("{}", error),
            }

            // Write the samples in the block to the wav file, channels interleaved.
            for s in 0..block.duration() {
                for ch in 0..block.channels() {
                    sample_writer.write_sample(block.sample(ch, s));
                }
            }

            sample_writer.flush().expect("failed to write samples to wav file");
        }
    }

    wav_writer.finalize().expect("failed to finalize wav file");
}
<|endoftext|>


<commit_before>extern crate rustbox;

use cursor::Direction;
use buffer::Buffer;
use cursor::Cursor;
use uibuf::UIBuffer;

use utils;

/// A View is an abstract Window (into a Buffer).
///
/// It draws a portion of a Buffer to a UIBuffer which in turn is drawn to the
/// screen. It maintains the status bar for the current view, the "dirty status"
/// which is whether the buffer has been modified or not and a number of other
/// pieces of information.
pub struct View<'v> {
    pub buffer: Buffer,
    // the line number of the topmost `Line` for the View to render
    pub top_line_num: uint,
    pub cursor: Cursor<'v>,

    uibuf: UIBuffer,
    threshold: int,
}

impl<'v> View<'v> {
    pub fn new(path: Option<String>) -> View<'v> {
        let buffer = match path {
            Some(s) => Buffer::new_from_file(&Path::new(s)),
            None    => Buffer::new_empty(),
        };

        let height: uint = utils::get_term_height();
        let width: uint = utils::get_term_width();

        // NOTE(greg): this may not play well with resizing
        let uibuf = UIBuffer::new(width, height);

        let mut cursor = Cursor::new();
        cursor.set_line(Some(&buffer.lines[0]));

        View {
            buffer: buffer,
            top_line_num: 0,
            cursor: cursor,
            uibuf: uibuf,
            threshold: 5,
        }
    }

    /// Clear the buffer
    ///
    /// Fills every cell in the UIBuffer with the space (' ') char.
    pub fn clear(&mut self) {
        self.uibuf.fill(' ');
        self.uibuf.draw_everything();
    }

    pub fn get_height(&self) -> uint {
        // NOTE(greg): when the status bar needs to move up, this value should be changed
        self.uibuf.get_height() -1
    }

    pub fn get_width(&self) -> uint {
        self.uibuf.get_width()
    }

    pub fn draw(&mut self) {
        let end_line = self.get_height();
        let num_lines = self.buffer.lines.len();
        let width = self.get_width() -1;
        let lines_to_draw = self.buffer.lines.slice(self.top_line_num, num_lines);

        for (index, line) in lines_to_draw.iter().enumerate() {
            if index < end_line {
                let mut internal_index = 0;
                for ch in line.borrow().data.iter() {

                    if internal_index < width {
                        let ch = *ch as char;
                        match ch {
                            '\t' => {
                                // TODO(greg): draw four spaces
                                // need to update how the cursor is rendered before doing this
                                // think about what will happen if the cursor sees a single '\t' char
                                // in the line, however this is represented as four chars to the user
                                // the actual cursor position will become separated from the drawn
                                // cursor position.
                                rustbox::shutdown();
                                panic!("Found TAB chars - can't process these right now")
                            }
                            _ => {
                                // draw the character
                                self.uibuf.update_cell_content(internal_index, index, ch);
                            }
                        }
                        internal_index += 1;
                    }

                    // if the line is longer than the width of the view, draw a special char
                    if internal_index == width {
                        // FIXME(greg): iota cant render this line correctly right now
                        self.uibuf.update_cell_content(internal_index, index, '→');
                        break;
                    }
                }
            }
        }

        self.uibuf.draw_everything();
    }

    pub fn draw_status(&mut self) {
        let buffer_status = self.buffer.get_status_text();
        let cursor_status = self.cursor.get_status_text();
        let status_text = format!("{} {}", buffer_status, cursor_status).into_bytes();
        let status_text_len = status_text.len();
        let width = self.get_width();
        let height = self.get_height();

        for index in range(0, width) {
            let mut ch: char = ' ';
            if index < status_text_len {
                ch = status_text[index] as char;
            }
            self.uibuf.update_cell(index, height, ch, rustbox::Color::Black, rustbox::Color::Blue);
        }

        self.uibuf.draw_range(height, height+1);
    }

    pub fn draw_cursor(&self) {
        let offset = self.cursor.get_offset();
        let linenum = self.cursor.get_linenum();

        utils::draw_cursor(offset, linenum-self.top_line_num);
    }

    pub fn resize(&mut self) {
        let width = self.uibuf.get_width();
        self.clear();
        self.uibuf = UIBuffer::new(width, 15);
    }

    pub fn move_cursor(&mut self, direction: Direction) {
        match direction {
            Direction::Up    => { self.move_cursor_up(); },
            Direction::Down  => { self.move_cursor_down(); },
            Direction::Right => { self.move_cursor_right(); },
            Direction::Left  => { self.cursor.move_left(); },
        }
    }

    fn move_cursor_right(&mut self) {
        let cursor_offset = self.cursor.get_offset();
        let next_offset = cursor_offset + 1;
        let width = self.get_width() - 1;

        if next_offset < width {
            self.cursor.move_right()
        }
    }

    // TODO(greg): refactor this method with move_cursor_down
    pub fn move_cursor_up(&mut self) {
        let cursor_linenum = self.cursor.get_linenum();
        let prev_linenum = cursor_linenum - 1;

        let num_lines = self.buffer.lines.len() - 1;
        if prev_linenum > num_lines { return }

        self.set_cursor_line(prev_linenum);

        let cursor_linenum = self.cursor.get_linenum() as int;
        let cursor_offset = cursor_linenum - self.top_line_num as int;

        if cursor_offset < self.threshold {
            let times = cursor_offset - self.threshold;
            self.move_top_line_n_times(times);
        }

    }

    // TODO(greg): refactor this method with move_cursor_up
    pub fn move_cursor_down(&mut self) {
        let cursor_linenum = self.cursor.get_linenum();
        let next_linenum = cursor_linenum + 1;

        let num_lines = self.buffer.lines.len() - 1;
        if next_linenum > num_lines { return }

        self.set_cursor_line(next_linenum);

        let cursor_linenum = self.cursor.get_linenum() as int;
        let cursor_offset = cursor_linenum - self.top_line_num as int;
        let height = self.get_height() as int;

        if cursor_offset >= (height - self.threshold) {
            let times = cursor_offset - (height - self.threshold) + 1;
            self.move_top_line_n_times(times);
        }
    }

    fn set_cursor_line(&mut self, linenum: uint) {
        let line = &self.buffer.lines[linenum];
        self.cursor.set_line(Some(line));
    }

    fn move_top_line_n_times(&mut self, mut num_times: int) {
        if num_times == 0 { return }

        // moving down
        if num_times > 0 {
            while num_times > 0 {
                self.top_line_num += 1;
                num_times -= 1;
            }
            return
        }

        // moving up
        if num_times < 0 {
            while num_times < 0 {
                if self.top_line_num == 0 { return }
                self.top_line_num -= 1;
                num_times += 1;
            }
            return
        }
    }

    pub fn delete_char(&mut self, direction: Direction) {
        let (offset, line_num) = self.cursor.get_position();

        if offset == 0 && direction.is_left() {
            let offset = self.buffer.join_line_with_previous(offset, line_num);
            self.move_cursor_up();
            self.cursor.set_offset(offset);
            return
        }

        let line_len = self.cursor.get_line_length();
        if offset == line_len && direction.is_right() {
            self.buffer.join_line_with_previous(offset, line_num+1);
            return
        }

        match direction {
            Direction::Left  => self.cursor.delete_backward_char(),
            Direction::Right => self.cursor.delete_forward_char(),
            _                => {}
        }
    }

    pub fn insert_tab(&mut self) {
        // A tab is just 4 spaces
        for _ in range(0i, 4) {
            self.insert_char(' ');
        }
    }

    pub fn insert_char(&mut self, ch: char) {
        self.cursor.insert_char(ch);
    }

    pub fn insert_line(&mut self) {
        let (offset, line_num) = self.cursor.get_position();
        self.buffer.insert_line(offset, line_num);

        self.move_cursor_down();
        self.cursor.set_offset(0);
    }
}

#[cfg(test)]
mod tests {

    use std::cell::RefCell;

    use buffer::{Line, Buffer};
    use cursor::{Cursor, Direction};
    use view::View;
    use uibuf::UIBuffer;
    use utils::data_from_str;

    fn setup_view<'v>() -> View<'v> {
        let mut view = View {
            buffer: Buffer::new(),
            top_line_num: 0,
            cursor: Cursor::new(),
            uibuf: UIBuffer::new(50, 50),
            threshold: 5,
        };

        let first_line = RefCell::new(Line::new(data_from_str("test"), 0));
        let second_line = RefCell::new(Line::new(data_from_str("second"), 1));

        view.buffer.lines = vec!(first_line, second_line);
        view.cursor.set_line(Some(&view.buffer.lines[0]));

        return view
    }

    #[test]
    fn test_move_cursor_down() {
        let mut view = setup_view();
        view.move_cursor_down();

        assert_eq!(view.cursor.get_linenum(), 1);
        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("second"));
    }

    #[test]
    fn test_move_cursor_up() {
        let mut view = setup_view();
        view.move_cursor_down();
        view.move_cursor_up();
        assert_eq!(view.cursor.get_linenum(), 0);
        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("test"));
    }

    #[test]
    fn test_insert_line() {
        let mut view = setup_view();
        view.cursor.move_right();
        view.insert_line();

        assert_eq!(view.buffer.lines.len(), 3);
        assert_eq!(view.cursor.get_offset(), 0);
        assert_eq!(view.cursor.get_line().borrow().linenum, 1);
    }

    #[test]
    fn test_insert_char() {
        let mut view = setup_view();
        view.insert_char('t');

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("ttest"));
    }

    #[test]
    fn test_delete_char_to_right() {
        let mut view = setup_view();
        view.delete_char(Direction::Right);

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("est"));
    }

    #[test]
    fn test_delete_char_to_left() {
        let mut view = setup_view();
        view.cursor.move_right();
        view.delete_char(Direction::Left);

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("est"));
    }

    #[test]
    fn test_delete_char_at_start_of_line() {
        let mut view = setup_view();
        view.move_cursor_down();
        view.delete_char(Direction::Left);

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("testsecond"));
    }

    #[test]
    fn test_delete_char_at_end_of_line() {
        let mut view = setup_view();
        view.cursor.set_offset(4);
        view.delete_char(Direction::Right);

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("testsecond"));
    }

    #[test]
    fn deleting_backward_at_start_of_first_line_does_nothing() {
        let mut view = setup_view();
        view.delete_char(Direction::Left);

        assert_eq!(view.buffer.lines.len(), 2);
        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("test"));
    }
}
<commit_msg>Split line drawing to its own method - refs #10<commit_after>extern crate rustbox;

use std::cell::RefCell;

use buffer::{Line, Buffer};
use cursor::Direction;
use cursor::Cursor;
use uibuf::UIBuffer;

use utils;

/// A View is an abstract Window (into a Buffer).
///
/// It draws a portion of a Buffer to a UIBuffer which in turn is drawn to the
/// screen. It maintains the status bar for the current view, the "dirty status"
/// which is whether the buffer has been modified or not and a number of other
/// pieces of information.
pub struct View<'v> {
    pub buffer: Buffer,
    // the line number of the topmost `Line` for the View to render
    pub top_line_num: uint,
    pub cursor: Cursor<'v>,

    uibuf: UIBuffer,
    threshold: int,
}

impl<'v> View<'v> {
    pub fn new(path: Option<String>) -> View<'v> {
        let buffer = match path {
            Some(s) => Buffer::new_from_file(&Path::new(s)),
            None    => Buffer::new_empty(),
        };

        let height: uint = utils::get_term_height();
        let width: uint = utils::get_term_width();

        // NOTE(greg): this may not play well with resizing
        let uibuf = UIBuffer::new(width, height);

        let mut cursor = Cursor::new();
        cursor.set_line(Some(&buffer.lines[0]));

        View {
            buffer: buffer,
            top_line_num: 0,
            cursor: cursor,
            uibuf: uibuf,
            threshold: 5,
        }
    }

    /// Clear the buffer
    ///
    /// Fills every cell in the UIBuffer with the space (' ') char.
    pub fn clear(&mut self) {
        self.uibuf.fill(' ');
        self.uibuf.draw_everything();
    }

    pub fn get_height(&self) -> uint {
        // NOTE(greg): when the status bar needs to move up, this value should be changed
        self.uibuf.get_height() -1
    }

    pub fn get_width(&self) -> uint {
        self.uibuf.get_width()
    }

    pub fn draw(&mut self) {
        let end_line = self.get_height();
        let num_lines = self.buffer.lines.len();
        // TODO(greg): remove the clone from this line - it seems dirty
        let lines_to_draw = self.buffer.lines.slice(self.top_line_num, num_lines).clone();

        for (index, line) in lines_to_draw.iter().enumerate() {
            if index < end_line {
                self.draw_line(line)
            }
        }

        self.uibuf.draw_everything();
    }

    pub fn draw_line(&mut self, line: &'v RefCell<Line>) {
        let width = self.get_width() -1;
        let index = line.borrow().linenum;
        let mut internal_index = 0;
        for ch in line.borrow().data.iter() {

            if internal_index < width {
                let ch = *ch as char;
                match ch {
                    '\t' => {
                        // todo(greg): draw four spaces
                        // need to update how the cursor is rendered before doing this
                        // think about what will happen if the cursor sees a single '\t' char
                        // in the line, however this is represented as four chars to the user
                        // the actual cursor position will become separated from the drawn
                        // cursor position.
                        rustbox::shutdown();
                        panic!("found tab chars - can't process these right now")
                    }
                    _ => {
                        // draw the character
                        self.uibuf.update_cell_content(internal_index, index, ch);
                    }
                }
                internal_index += 1;
            }

            // if the line is longer than the width of the view, draw a special char
            if internal_index == width {
                // fixme(greg): iota cant render this line correctly right now
                self.uibuf.update_cell_content(internal_index, index, '→');
                break;
            }
        }
    }

    pub fn draw_status(&mut self) {
        let buffer_status = self.buffer.get_status_text();
        let cursor_status = self.cursor.get_status_text();
        let status_text = format!("{} {}", buffer_status, cursor_status).into_bytes();
        let status_text_len = status_text.len();
        let width = self.get_width();
        let height = self.get_height();

        for index in range(0, width) {
            let mut ch: char = ' ';
            if index < status_text_len {
                ch = status_text[index] as char;
            }
            self.uibuf.update_cell(index, height, ch, rustbox::Color::Black, rustbox::Color::Blue);
        }

        self.uibuf.draw_range(height, height+1);
    }

    pub fn draw_cursor(&self) {
        let offset = self.cursor.get_offset();
        let linenum = self.cursor.get_linenum();

        utils::draw_cursor(offset, linenum-self.top_line_num);
    }

    pub fn resize(&mut self) {
        let width = self.uibuf.get_width();
        self.clear();
        self.uibuf = UIBuffer::new(width, 15);
    }

    pub fn move_cursor(&mut self, direction: Direction) {
        match direction {
            Direction::Up    => { self.move_cursor_up(); },
            Direction::Down  => { self.move_cursor_down(); },
            Direction::Right => { self.move_cursor_right(); },
            Direction::Left  => { self.cursor.move_left(); },
        }
    }

    fn move_cursor_right(&mut self) {
        let cursor_offset = self.cursor.get_offset();
        let next_offset = cursor_offset + 1;
        let width = self.get_width() - 1;

        if next_offset < width {
            self.cursor.move_right()
        }
    }

    // TODO(greg): refactor this method with move_cursor_down
    pub fn move_cursor_up(&mut self) {
        let cursor_linenum = self.cursor.get_linenum();
        let prev_linenum = cursor_linenum - 1;

        let num_lines = self.buffer.lines.len() - 1;
        if prev_linenum > num_lines { return }

        self.set_cursor_line(prev_linenum);

        let cursor_linenum = self.cursor.get_linenum() as int;
        let cursor_offset = cursor_linenum - self.top_line_num as int;

        if cursor_offset < self.threshold {
            let times = cursor_offset - self.threshold;
            self.move_top_line_n_times(times);
        }

    }

    // TODO(greg): refactor this method with move_cursor_up
    pub fn move_cursor_down(&mut self) {
        let cursor_linenum = self.cursor.get_linenum();
        let next_linenum = cursor_linenum + 1;

        let num_lines = self.buffer.lines.len() - 1;
        if next_linenum > num_lines { return }

        self.set_cursor_line(next_linenum);

        let cursor_linenum = self.cursor.get_linenum() as int;
        let cursor_offset = cursor_linenum - self.top_line_num as int;
        let height = self.get_height() as int;

        if cursor_offset >= (height - self.threshold) {
            let times = cursor_offset - (height - self.threshold) + 1;
            self.move_top_line_n_times(times);
        }
    }

    fn set_cursor_line(&mut self, linenum: uint) {
        let line = &self.buffer.lines[linenum];
        self.cursor.set_line(Some(line));
    }

    fn move_top_line_n_times(&mut self, mut num_times: int) {
        if num_times == 0 { return }

        // moving down
        if num_times > 0 {
            while num_times > 0 {
                self.top_line_num += 1;
                num_times -= 1;
            }
            return
        }

        // moving up
        if num_times < 0 {
            while num_times < 0 {
                if self.top_line_num == 0 { return }
                self.top_line_num -= 1;
                num_times += 1;
            }
            return
        }
    }

    pub fn delete_char(&mut self, direction: Direction) {
        let (offset, line_num) = self.cursor.get_position();

        if offset == 0 && direction.is_left() {
            let offset = self.buffer.join_line_with_previous(offset, line_num);
            self.move_cursor_up();
            self.cursor.set_offset(offset);
            return
        }

        let line_len = self.cursor.get_line_length();
        if offset == line_len && direction.is_right() {
            self.buffer.join_line_with_previous(offset, line_num+1);
            return
        }

        match direction {
            Direction::Left  => self.cursor.delete_backward_char(),
            Direction::Right => self.cursor.delete_forward_char(),
            _                => {}
        }
    }

    pub fn insert_tab(&mut self) {
        // A tab is just 4 spaces
        for _ in range(0i, 4) {
            self.insert_char(' ');
        }
    }

    pub fn insert_char(&mut self, ch: char) {
        self.cursor.insert_char(ch);
    }

    pub fn insert_line(&mut self) {
        let (offset, line_num) = self.cursor.get_position();
        self.buffer.insert_line(offset, line_num);

        self.move_cursor_down();
        self.cursor.set_offset(0);
    }
}

#[cfg(test)]
mod tests {

    use std::cell::RefCell;

    use buffer::{Line, Buffer};
    use cursor::{Cursor, Direction};
    use view::View;
    use uibuf::UIBuffer;
    use utils::data_from_str;

    fn setup_view<'v>() -> View<'v> {
        let mut view = View {
            buffer: Buffer::new(),
            top_line_num: 0,
            cursor: Cursor::new(),
            uibuf: UIBuffer::new(50, 50),
            threshold: 5,
        };

        let first_line = RefCell::new(Line::new(data_from_str("test"), 0));
        let second_line = RefCell::new(Line::new(data_from_str("second"), 1));

        view.buffer.lines = vec!(first_line, second_line);
        view.cursor.set_line(Some(&view.buffer.lines[0]));

        return view
    }

    #[test]
    fn test_move_cursor_down() {
        let mut view = setup_view();
        view.move_cursor_down();

        assert_eq!(view.cursor.get_linenum(), 1);
        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("second"));
    }

    #[test]
    fn test_move_cursor_up() {
        let mut view = setup_view();
        view.move_cursor_down();
        view.move_cursor_up();
        assert_eq!(view.cursor.get_linenum(), 0);
        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("test"));
    }

    #[test]
    fn test_insert_line() {
        let mut view = setup_view();
        view.cursor.move_right();
        view.insert_line();

        assert_eq!(view.buffer.lines.len(), 3);
        assert_eq!(view.cursor.get_offset(), 0);
        assert_eq!(view.cursor.get_line().borrow().linenum, 1);
    }

    #[test]
    fn test_insert_char() {
        let mut view = setup_view();
        view.insert_char('t');

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("ttest"));
    }

    #[test]
    fn test_delete_char_to_right() {
        let mut view = setup_view();
        view.delete_char(Direction::Right);

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("est"));
    }

    #[test]
    fn test_delete_char_to_left() {
        let mut view = setup_view();
        view.cursor.move_right();
        view.delete_char(Direction::Left);

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("est"));
    }

    #[test]
    fn test_delete_char_at_start_of_line() {
        let mut view = setup_view();
        view.move_cursor_down();
        view.delete_char(Direction::Left);

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("testsecond"));
    }

    #[test]
    fn test_delete_char_at_end_of_line() {
        let mut view = setup_view();
        view.cursor.set_offset(4);
        view.delete_char(Direction::Right);

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("testsecond"));
    }

    #[test]
    fn deleting_backward_at_start_of_first_line_does_nothing() {
        let mut view = setup_view();
        view.delete_char(Direction::Left);

        assert_eq!(view.buffer.lines.len(), 2);
        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("test"));
    }
}
<|endoftext|>


<commit_before>//! This crate provides a thread-safe data container.
//!
//! # Description
//!
//! This structure behaves a lot like a normal Mutex. There are some differences:
//!
//! - It may be used outside the runtime.
//!   - A normal mutex will fail when used without the runtime, this will just lock
//!   - When the runtime is present, it will call the deschedule function when appropriate
//! - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
//!
//! When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
//! helpfull. In other cases however, you are encouraged to use the locks from the standard
//! library.
//!
//! # Simple example
//!
//! ```
//! use spinlock::Spinlock;
//! let spinlock = Spinlock::new(0);
//!
//! // Modify the data
//! {
//!     let mut data = spinlock.lock();
//!     *data = 2;
//! }
//!
//! // Read the data
//! let answer =
//! {
//!     let data = spinlock.lock();
//!     *data
//! };
//!
//! assert_eq!(answer, 2);
//! ```
//!
//! # Thread-safety example
//!
//! ```
//! use spinlock::Spinlock;
//! use std::sync::{Arc, Barrier};
//!
//! let numthreads = 1000;
//! let spinlock = Arc::new(Spinlock::new(0));
//!
//! // We use a barrier to ensure the readout happens after all writing
//! let barrier = Arc::new(Barrier::new(numthreads + 1));
//!
//! for _ in (0..numthreads)
//! {
//!     let my_barrier = barrier.clone();
//!     let my_lock = spinlock.clone();
//!     std::thread::Thread::spawn(move||
//!     {
//!         let mut guard = my_lock.lock();
//!         *guard += 1;
//!
//!         // Release the lock to prevent a deadlock
//!         drop(guard);
//!         my_barrier.wait();
//!     });
//! }
//!
//! barrier.wait();
//!
//! let answer = { *spinlock.lock() };
//! assert_eq!(answer, numthreads);
//! ```

use std::sync::atomic::{AtomicUint, Ordering, ATOMIC_UINT_INIT};
use std::cell::UnsafeCell;
use std::ops::{Drop, Deref, DerefMut};
use thread_local;

/// A wrapper for the data giving access in a thread-safe manner
pub struct Spinlock<T>
{
    lock: AtomicUint,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
pub struct SpinlockGuard<'a, T:'a>
{
    lock: &'a AtomicUint,
    data: &'a mut T,
}

#[allow(unstable)]
unsafe impl<T> Sync for Spinlock<T> {}

/// A Spinlock which may be used statically.
///
/// ```
/// use spinlock::{StaticSpinlock, STATIC_SPINLOCK_INIT};
///
/// static SPLCK: StaticSpinlock = STATIC_SPINLOCK_INIT;
///
/// fn demo() {
///     let lock = SPLCK.lock();
///     // do something with lock
///     drop(lock);
/// }
/// ```
pub type StaticSpinlock = Spinlock<()>;

/// A initializer for StaticSpinlock, containing no data.
pub const STATIC_SPINLOCK_INIT: StaticSpinlock = Spinlock {
    lock: ATOMIC_UINT_INIT,
    data: UnsafeCell { value: () },
};

#[deprecated = "renamed to STATIC_SPINLOCK_INIT"]
pub const INIT_STATIC_SPINLOCK: StaticSpinlock = STATIC_SPINLOCK_INIT;

impl<T> Spinlock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    pub fn new(user_data: T) -> Spinlock<T>
    {
        Spinlock
        {
            lock: ATOMIC_UINT_INIT,
            data: UnsafeCell::new(user_data),
        }
    }

    fn obtain_lock(&self)
    {
        let current_id = thread_local::borrow().current_thread.id.as_usize();
        while self.lock.compare_and_swap(0, current_id, Ordering::SeqCst) != 0
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spinlock::Spinlock::new(0);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    /// }
    /// // The lock is dropped
    /// ```
    pub fn lock(&self) -> SpinlockGuard<T>
    {
        self.obtain_lock();
        SpinlockGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }

    pub fn held_by_current_thread(&self) -> bool {
        let current_thread_id = thread_local::borrow().current_thread.id.as_usize();
        self.lock.load(Ordering::Relaxed) == current_thread_id
    }
}

impl<'a, T> Deref for SpinlockGuard<'a, T>
{
    type Target = T;
    fn deref<'b>(&'b self) -> &'b T { &*self.data }
}

impl<'a, T> DerefMut for SpinlockGuard<'a, T>
{
    fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T> Drop for SpinlockGuard<'a, T>
{
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(0, Ordering::SeqCst);
    }
}<commit_msg>use thread_local::data()<commit_after>//! This crate provides a thread-safe data container.
//!
//! # Description
//!
//! This structure behaves a lot like a normal Mutex. There are some differences:
//!
//! - It may be used outside the runtime.
//!   - A normal mutex will fail when used without the runtime, this will just lock
//!   - When the runtime is present, it will call the deschedule function when appropriate
//! - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
//!
//! When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
//! helpfull. In other cases however, you are encouraged to use the locks from the standard
//! library.
//!
//! # Simple example
//!
//! ```
//! use spinlock::Spinlock;
//! let spinlock = Spinlock::new(0);
//!
//! // Modify the data
//! {
//!     let mut data = spinlock.lock();
//!     *data = 2;
//! }
//!
//! // Read the data
//! let answer =
//! {
//!     let data = spinlock.lock();
//!     *data
//! };
//!
//! assert_eq!(answer, 2);
//! ```
//!
//! # Thread-safety example
//!
//! ```
//! use spinlock::Spinlock;
//! use std::sync::{Arc, Barrier};
//!
//! let numthreads = 1000;
//! let spinlock = Arc::new(Spinlock::new(0));
//!
//! // We use a barrier to ensure the readout happens after all writing
//! let barrier = Arc::new(Barrier::new(numthreads + 1));
//!
//! for _ in (0..numthreads)
//! {
//!     let my_barrier = barrier.clone();
//!     let my_lock = spinlock.clone();
//!     std::thread::Thread::spawn(move||
//!     {
//!         let mut guard = my_lock.lock();
//!         *guard += 1;
//!
//!         // Release the lock to prevent a deadlock
//!         drop(guard);
//!         my_barrier.wait();
//!     });
//! }
//!
//! barrier.wait();
//!
//! let answer = { *spinlock.lock() };
//! assert_eq!(answer, numthreads);
//! ```

use std::sync::atomic::{AtomicUint, Ordering, ATOMIC_UINT_INIT};
use std::cell::UnsafeCell;
use std::ops::{Drop, Deref, DerefMut};
use thread_local;

/// A wrapper for the data giving access in a thread-safe manner
pub struct Spinlock<T>
{
    lock: AtomicUint,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
pub struct SpinlockGuard<'a, T:'a>
{
    lock: &'a AtomicUint,
    data: &'a mut T,
}

#[allow(unstable)]
unsafe impl<T> Sync for Spinlock<T> {}

/// A Spinlock which may be used statically.
///
/// ```
/// use spinlock::{StaticSpinlock, STATIC_SPINLOCK_INIT};
///
/// static SPLCK: StaticSpinlock = STATIC_SPINLOCK_INIT;
///
/// fn demo() {
///     let lock = SPLCK.lock();
///     // do something with lock
///     drop(lock);
/// }
/// ```
pub type StaticSpinlock = Spinlock<()>;

/// A initializer for StaticSpinlock, containing no data.
pub const STATIC_SPINLOCK_INIT: StaticSpinlock = Spinlock {
    lock: ATOMIC_UINT_INIT,
    data: UnsafeCell { value: () },
};

#[deprecated = "renamed to STATIC_SPINLOCK_INIT"]
pub const INIT_STATIC_SPINLOCK: StaticSpinlock = STATIC_SPINLOCK_INIT;

impl<T> Spinlock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    pub fn new(user_data: T) -> Spinlock<T>
    {
        Spinlock
        {
            lock: ATOMIC_UINT_INIT,
            data: UnsafeCell::new(user_data),
        }
    }

    fn obtain_lock(&self)
    {
        let current_id = thread_local::data().borrow().current_thread.id.as_usize();
        while self.lock.compare_and_swap(0, current_id, Ordering::SeqCst) != 0
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spinlock::Spinlock::new(0);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    /// }
    /// // The lock is dropped
    /// ```
    pub fn lock(&self) -> SpinlockGuard<T>
    {
        self.obtain_lock();
        SpinlockGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }

    pub fn held_by_current_thread(&self) -> bool {
        let current_thread_id = thread_local::data().borrow().current_thread.id.as_usize();
        self.lock.load(Ordering::Relaxed) == current_thread_id
    }
}

impl<'a, T> Deref for SpinlockGuard<'a, T>
{
    type Target = T;
    fn deref<'b>(&'b self) -> &'b T { &*self.data }
}

impl<'a, T> DerefMut for SpinlockGuard<'a, T>
{
    fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T> Drop for SpinlockGuard<'a, T>
{
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(0, Ordering::SeqCst);
    }
}<|endoftext|>


<commit_before>//! Rust entry point
//!
//! Boot is split into two parts
//!
//! + Early boot where we walk hardware data structures and setup initial
//!   machine state before
//! + Late boot where we are operating in the final kernel window and can
//!   setup the initial user environment
//!
//! Early boot is extremely architecture specific, late boot is mostly
//! generic.

use plat::*;
use vspace::*;
use panic::*;
use steal_mem::*;
use types::*;
use ::config::BootConfig;
use ::core::fmt::Write;
use ::core::marker::PhantomData;
use ::core::cmp;
use super::halt::halt;
use super::vspace::*;
extern crate multiboot;

extern {
    /// Represent the start of the kernel image region. The type is not
    /// correct as there is no way to properly represent the type we want
    /// in Rust
    static kernel_image_start: u8;
    static kernel_image_end: u8;
}

/// Package of state that is passed to the early boot function
struct EarlyBootState<'a, 'h, 'l> where 'h: 'a, 'l: 'a {
    /// Referenece to the high window. Objects created from here can
    /// persist forever, and as such references to them can be returned
    /// in `PostEarlyBootState`
    high_window : &'a BootHighWindow<'h>,
    /// Reference to the low window. References to objects from here
    /// cannot be returned in `PostEarlyBootState`
    low_window : &'a BootLowWindow<'l>,
    /// The value of EAX passed from the assembly entry. This is checked
    /// to ensure we were multiboot loaded
    mbi_magic: usize,
    /// Raw physical pointer that should point to the multiboot structure
    mbi: *const usize,
}

/// Package of state that is returned as a result of early boot
struct PostEarlyBootState<'a> {
    /// An initialized platform interface
    plat: PlatInterfaceType,
    /// Currently the lifetime 'a is unused, so have some `PhantomData` to get
    /// around that
    phantom: PhantomData<&'a usize>,
}

/// Debug function to print out the contents of the multiboot information
fn display_multiboot<'a, F: Fn(u64, usize) -> Option<&'a [u8]>>(plat: &mut PlatInterfaceType, mbi: &'a multiboot::Multiboot<'a, F>) {
    write!(plat, "Multiboot information:\n").unwrap();
    if let Some(low) = mbi.lower_memory_bound() {
        write!(plat,"\t{}kb of low memory\n", low).unwrap();
    }
    if let Some(high) = mbi.upper_memory_bound() {
        write!(plat,"\t{}mb of high memory\n", high / 1024).unwrap();
    }
    if let Some(boot) = mbi.boot_device() {
        write!(plat,"\tBoot device {:?}\n", boot).unwrap();
    }
    if let Some(line) = mbi.command_line() {
        write!(plat,"\tCommand line \"{}\"\n", line).unwrap();
    }
    if let Some(modules) = mbi.modules() {
        write!(plat,"Multiboot modules:\n").unwrap();
        for m in modules {
            write!(plat,"\t{:?}\n", m).unwrap();
        }
    }
    if let Some(memory) = mbi.memory_regions() {
        write!(plat,"Memory regions:\n").unwrap();
        for m in memory {
            write!(plat,"\t{:?}\n", m).unwrap();
        }
    }
}

/// Convert the kernel image start and end variables from the linker script
/// into useful values
fn get_kernel_image_region<'a>(window: &BootHighWindow<'a>) -> (HighWindowAddr, HighWindowAddr) {
    let start = &kernel_image_start as *const u8 as usize;
    let end = &kernel_image_end as *const u8 as usize;
    return unsafe{(window.to_addr(start), window.to_addr(end))};
}

/// Small wrapper around the boot info memory map iterator to only return
/// usable RAM regions
struct BIMemIterator<'a, F> where F: Fn(u64, usize) -> Option<&'a [u8]> + 'a {
    /// Iterator over the raw multiboot memory regions
    iter: multiboot::MemoryMapIter<'a, F>,
    /// Physical memory above which we actually consider usable. This allows
    /// for a coarse grained way of skipping the memory that is currently
    /// used by the kernel image
    start: PAddr,
}

impl<'a, F: Fn(u64, usize) -> Option<&'a [u8]>> Iterator for BIMemIterator<'a, F> {
    type Item=(PAddr, PAddr);
    fn next(&mut self) -> Option<Self::Item> {
        let mem = match self.iter.next() {
            None => return None,
            Some(m) => m,
        };
        if mem.memory_type() == multiboot::MemoryType::RAM {
            let base = mem.base_address() as usize;
            let len = mem.length() as usize;
            let end = PAddr(base + len);
            if end > self.start {
                let ret = (cmp::max(PAddr(base), self.start), end);
                return Some(ret);
            }
        }
        self.next()
    }
}

/// Try and boot the system, potentially returning an error.
/// Since if we fail there is no way to display or do anything
/// with the error we do do not bother to have an error type
/// This is specifically the 'early' boot as it happens before
/// we switch to the final kernel address space
///
/// # Safety
///
/// Should only be called once during bootup with the correct
/// initial state
unsafe fn try_early_boot_system<'a, 'h, 'l>(init: EarlyBootState<'a, 'h, 'l>) -> Result<PostEarlyBootState<'h>, ()> {
    /* check that we are multi-booted */
    if init.mbi_magic as u64 != multiboot::SIGNATURE_RAX {
        return Err(());
    }
    /* construct a reference to the mbi to get all of our boot information */
    let mbi = match multiboot::Multiboot::new(init.mbi as multiboot::PAddr,
            |p, s| init.low_window.make_slice(
                init.low_window.from_paddr(PAddr(p as usize)),
                s)) {
        Some(mbi) => mbi,
        None => {
                return Err(());
            }
        };
    let bootconfig = BootConfig::new(mbi.command_line().unwrap_or(""));
    /* Initial the serial output of our platform first so that
     * we can get debugging output. */
    let mut plat = get_platform(&bootconfig);
    plat.init_serial();
    write!(plat, "R4: In early setup\n").unwrap();
    let (ki_start, ki_end) = get_kernel_image_region(init.high_window);
    write!(plat, "Kernel imagine region {:?} {:?}\n", ki_start, ki_end).unwrap();
    /* Initialize the panic function so we can see anything
     * really bad that happens */
    panic_set_plat(&mut plat);
    /* Now we can continue with the rest of init */
    display_multiboot(&mut plat, &mbi);
    /* Construct early kernel allocator for memory stealing. For simplicity
     * we just ignore any memory that occurs before the end of the kernel
     * image. */
    let regions = match mbi.memory_regions() {
        None => {
            write!(plat, "No memory regions found in multiboot\n").unwrap();
            return Err(());
            }
        Some(reg) => reg,
    };
    let mut early_alloc = StealMem::new(
        BIMemIterator{
            iter: regions,
            start: init.high_window.to_paddr(ki_end),
        },
        init.high_window);
    /* Perform early platform specific system initialization */
    try!(plat.early_init());
    /* Do any platform device discovery */
    try!(plat.early_device_discovery(init.low_window));
    /* Construct kernel window */
    Ok(PostEarlyBootState{ plat: plat, phantom: PhantomData })
}

/// Perform the rest of the system boot in the final kernel Window.
///
/// # Safety
///
/// Should only be called oncce during bootup. Assumes that the kernel
/// address space has been loaded and is currently active
unsafe fn try_boot_system() {
    /* Initialize CPU */
    /* Initialize other system state? */
    /* Perform any post cpu platform init */
    /* Load initial user thread. Part of this will have to be
     * moved earlier as the data for this is in the early boot
     * window :(. Worry about this later */
}

/// Rust entry point for the kernel. This expects two parameters, one the
/// boot info magic, and the other a raw pointer to the boot info structure.
/// Additionally it expects that both the boot kernel windows are configured
/// correctly in the active address space root
#[no_mangle]
pub extern fn boot_system(magic: usize, mbi: *const usize) -> ! {
    /* This *will* be our final kernel window, but it is not our window
     * yet. We create it here so that our temporary high kernel window,
     * which is a subset of the final kernel window, can be constructed
     * from it as having the same lifetime. This allows any references
     * created from the boot high kernel window being able to live on
     * into the final kernel window */
    let final_window = unsafe{KernelWindow::new(())};
    /* this variable will hold our system state as returned by early boot */
    let mut boot;
    {
        /* Construct our system state for boot */
        let boot_high_window = final_window.subwindow(()).unwrap();
        /* whilst doing early boot we can also access things in low memory */
        let boot_low_window = unsafe {BootLowWindow::new(())};
        let boot_state = EarlyBootState {
            high_window: &boot_high_window,
            low_window: &boot_low_window,
            mbi_magic: magic,
            mbi: mbi,
        };
        boot = match unsafe{try_early_boot_system(boot_state)} {
            Err(_) => halt(),
            Ok(b) => b,
        };
    }
    /* The 'plat' definition got moved into boot. Reset the panic location */
    panic_set_plat(&mut boot.plat);
    /* Switch to kernel address space for this cluster */
    /* Now we can perform the rest of the system boot */
    unsafe{try_boot_system();}
    unimplemented!()
}
<commit_msg>Move initial panic setup earlier<commit_after>//! Rust entry point
//!
//! Boot is split into two parts
//!
//! + Early boot where we walk hardware data structures and setup initial
//!   machine state before
//! + Late boot where we are operating in the final kernel window and can
//!   setup the initial user environment
//!
//! Early boot is extremely architecture specific, late boot is mostly
//! generic.

use plat::*;
use vspace::*;
use panic::*;
use steal_mem::*;
use types::*;
use ::config::BootConfig;
use ::core::fmt::Write;
use ::core::marker::PhantomData;
use ::core::cmp;
use super::halt::halt;
use super::vspace::*;
extern crate multiboot;

extern {
    /// Represent the start of the kernel image region. The type is not
    /// correct as there is no way to properly represent the type we want
    /// in Rust
    static kernel_image_start: u8;
    static kernel_image_end: u8;
}

/// Package of state that is passed to the early boot function
struct EarlyBootState<'a, 'h, 'l> where 'h: 'a, 'l: 'a {
    /// Referenece to the high window. Objects created from here can
    /// persist forever, and as such references to them can be returned
    /// in `PostEarlyBootState`
    high_window : &'a BootHighWindow<'h>,
    /// Reference to the low window. References to objects from here
    /// cannot be returned in `PostEarlyBootState`
    low_window : &'a BootLowWindow<'l>,
    /// The value of EAX passed from the assembly entry. This is checked
    /// to ensure we were multiboot loaded
    mbi_magic: usize,
    /// Raw physical pointer that should point to the multiboot structure
    mbi: *const usize,
}

/// Package of state that is returned as a result of early boot
struct PostEarlyBootState<'a> {
    /// An initialized platform interface
    plat: PlatInterfaceType,
    /// Currently the lifetime 'a is unused, so have some `PhantomData` to get
    /// around that
    phantom: PhantomData<&'a usize>,
}

/// Debug function to print out the contents of the multiboot information
fn display_multiboot<'a, F: Fn(u64, usize) -> Option<&'a [u8]>>(plat: &mut PlatInterfaceType, mbi: &'a multiboot::Multiboot<'a, F>) {
    write!(plat, "Multiboot information:\n").unwrap();
    if let Some(low) = mbi.lower_memory_bound() {
        write!(plat,"\t{}kb of low memory\n", low).unwrap();
    }
    if let Some(high) = mbi.upper_memory_bound() {
        write!(plat,"\t{}mb of high memory\n", high / 1024).unwrap();
    }
    if let Some(boot) = mbi.boot_device() {
        write!(plat,"\tBoot device {:?}\n", boot).unwrap();
    }
    if let Some(line) = mbi.command_line() {
        write!(plat,"\tCommand line \"{}\"\n", line).unwrap();
    }
    if let Some(modules) = mbi.modules() {
        write!(plat,"Multiboot modules:\n").unwrap();
        for m in modules {
            write!(plat,"\t{:?}\n", m).unwrap();
        }
    }
    if let Some(memory) = mbi.memory_regions() {
        write!(plat,"Memory regions:\n").unwrap();
        for m in memory {
            write!(plat,"\t{:?}\n", m).unwrap();
        }
    }
}

/// Convert the kernel image start and end variables from the linker script
/// into useful values
fn get_kernel_image_region<'a>(window: &BootHighWindow<'a>) -> (HighWindowAddr, HighWindowAddr) {
    let start = &kernel_image_start as *const u8 as usize;
    let end = &kernel_image_end as *const u8 as usize;
    return unsafe{(window.to_addr(start), window.to_addr(end))};
}

/// Small wrapper around the boot info memory map iterator to only return
/// usable RAM regions
struct BIMemIterator<'a, F> where F: Fn(u64, usize) -> Option<&'a [u8]> + 'a {
    /// Iterator over the raw multiboot memory regions
    iter: multiboot::MemoryMapIter<'a, F>,
    /// Physical memory above which we actually consider usable. This allows
    /// for a coarse grained way of skipping the memory that is currently
    /// used by the kernel image
    start: PAddr,
}

impl<'a, F: Fn(u64, usize) -> Option<&'a [u8]>> Iterator for BIMemIterator<'a, F> {
    type Item=(PAddr, PAddr);
    fn next(&mut self) -> Option<Self::Item> {
        let mem = match self.iter.next() {
            None => return None,
            Some(m) => m,
        };
        if mem.memory_type() == multiboot::MemoryType::RAM {
            let base = mem.base_address() as usize;
            let len = mem.length() as usize;
            let end = PAddr(base + len);
            if end > self.start {
                let ret = (cmp::max(PAddr(base), self.start), end);
                return Some(ret);
            }
        }
        self.next()
    }
}

/// Try and boot the system, potentially returning an error.
/// Since if we fail there is no way to display or do anything
/// with the error we do do not bother to have an error type
/// This is specifically the 'early' boot as it happens before
/// we switch to the final kernel address space
///
/// # Safety
///
/// Should only be called once during bootup with the correct
/// initial state
unsafe fn try_early_boot_system<'a, 'h, 'l>(init: EarlyBootState<'a, 'h, 'l>) -> Result<PostEarlyBootState<'h>, ()> {
    /* check that we are multi-booted */
    if init.mbi_magic as u64 != multiboot::SIGNATURE_RAX {
        return Err(());
    }
    /* construct a reference to the mbi to get all of our boot information */
    let mbi = match multiboot::Multiboot::new(init.mbi as multiboot::PAddr,
            |p, s| init.low_window.make_slice(
                init.low_window.from_paddr(PAddr(p as usize)),
                s)) {
        Some(mbi) => mbi,
        None => {
                return Err(());
            }
        };
    let bootconfig = BootConfig::new(mbi.command_line().unwrap_or(""));
    /* Initial the serial output of our platform first so that
     * we can get debugging output. */
    let mut plat = get_platform(&bootconfig);
    plat.init_serial();
    /* Initialize the panic function so we can see anything
     * really bad that happens */
    panic_set_plat(&mut plat);
    write!(plat, "R4: In early setup\n").unwrap();
    let (ki_start, ki_end) = get_kernel_image_region(init.high_window);
    write!(plat, "Kernel imagine region {:?} {:?}\n", ki_start, ki_end).unwrap();
    /* Now we can continue with the rest of init */
    display_multiboot(&mut plat, &mbi);
    /* Construct early kernel allocator for memory stealing. For simplicity
     * we just ignore any memory that occurs before the end of the kernel
     * image. */
    let regions = match mbi.memory_regions() {
        None => {
            write!(plat, "No memory regions found in multiboot\n").unwrap();
            return Err(());
            }
        Some(reg) => reg,
    };
    let mut early_alloc = StealMem::new(
        BIMemIterator{
            iter: regions,
            start: init.high_window.to_paddr(ki_end),
        },
        init.high_window);
    /* Perform early platform specific system initialization */
    try!(plat.early_init());
    /* Do any platform device discovery */
    try!(plat.early_device_discovery(init.low_window));
    /* Construct kernel window */
    Ok(PostEarlyBootState{ plat: plat, phantom: PhantomData })
}

/// Perform the rest of the system boot in the final kernel Window.
///
/// # Safety
///
/// Should only be called oncce during bootup. Assumes that the kernel
/// address space has been loaded and is currently active
unsafe fn try_boot_system() {
    /* Initialize CPU */
    /* Initialize other system state? */
    /* Perform any post cpu platform init */
    /* Load initial user thread. Part of this will have to be
     * moved earlier as the data for this is in the early boot
     * window :(. Worry about this later */
}

/// Rust entry point for the kernel. This expects two parameters, one the
/// boot info magic, and the other a raw pointer to the boot info structure.
/// Additionally it expects that both the boot kernel windows are configured
/// correctly in the active address space root
#[no_mangle]
pub extern fn boot_system(magic: usize, mbi: *const usize) -> ! {
    /* This *will* be our final kernel window, but it is not our window
     * yet. We create it here so that our temporary high kernel window,
     * which is a subset of the final kernel window, can be constructed
     * from it as having the same lifetime. This allows any references
     * created from the boot high kernel window being able to live on
     * into the final kernel window */
    let final_window = unsafe{KernelWindow::new(())};
    /* this variable will hold our system state as returned by early boot */
    let mut boot;
    {
        /* Construct our system state for boot */
        let boot_high_window = final_window.subwindow(()).unwrap();
        /* whilst doing early boot we can also access things in low memory */
        let boot_low_window = unsafe {BootLowWindow::new(())};
        let boot_state = EarlyBootState {
            high_window: &boot_high_window,
            low_window: &boot_low_window,
            mbi_magic: magic,
            mbi: mbi,
        };
        boot = match unsafe{try_early_boot_system(boot_state)} {
            Err(_) => halt(),
            Ok(b) => b,
        };
    }
    /* The 'plat' definition got moved into boot. Reset the panic location */
    panic_set_plat(&mut boot.plat);
    /* Switch to kernel address space for this cluster */
    /* Now we can perform the rest of the system boot */
    unsafe{try_boot_system();}
    unimplemented!()
}
<|endoftext|>


<commit_before>extern crate glutin;

#[macro_use]
extern crate glium;

use glium::Surface;

mod support;

fn main() {
    use glium::DisplayBuild;

    // building the display, ie. the main object
    let display = glutin::WindowBuilder::new()
        .with_depth_buffer(24)
        .build_glium()
        .unwrap();

    // building the vertex and index buffers
    let vertex_buffer = support::load_wavefront(&display, include_bytes!("support/teapot.obj"));

    // the program
    let program = program!(&display,
        140 => {
            vertex: "
                #version 140

                uniform mat4 persp_matrix;
                uniform mat4 view_matrix;

                in vec3 position;
                in vec3 normal;
                out vec3 v_position;
                out vec3 v_normal;

                void main() {
                    v_position = position;
                    v_normal = normal;
                    gl_Position = persp_matrix * view_matrix * vec4(v_position * 0.005, 1.0);
                }
            ",

            fragment: "
                #version 140

                in vec3 v_normal;
                out vec4 f_color;

                const vec3 LIGHT = vec3(-0.2, 0.8, 0.1);

                void main() {
                    float lum = max(dot(normalize(v_normal), normalize(LIGHT)), 0.0);
                    vec3 color = (0.3 + 0.7 * lum) * vec3(1.0, 1.0, 1.0);
                    f_color = vec4(color, 1.0);
                }
            ",
        },

        110 => {
            vertex: "
                #version 110

                uniform mat4 persp_matrix;
                uniform mat4 view_matrix;

                attribute vec3 position;
                attribute vec3 normal;
                varying vec3 v_position;
                varying vec3 v_normal;

                void main() {
                    v_position = position;
                    v_normal = normal;
                    gl_Position = persp_matrix * view_matrix * vec4(v_position * 0.005, 1.0);
                }
            ",

            fragment: "
                #version 110

                varying vec3 v_normal;

                const vec3 LIGHT = vec3(-0.2, 0.8, 0.1);

                void main() {
                    float lum = max(dot(normalize(v_normal), normalize(LIGHT)), 0.0);
                    vec3 color = (0.3 + 0.7 * lum) * vec3(1.0, 1.0, 1.0);
                    gl_FragColor = vec4(color, 1.0);
                }
            ",
        }
    ).unwrap();

    //
    let mut camera = support::camera::CameraState::new();

    // the main loop
    support::start_loop(|| {
        camera.update();

        // building the uniforms
        let uniforms = uniform! {
            persp_matrix: camera.get_perspective(),
            view_matrix: camera.get_view(),
        };

        // draw parameters
        let params = glium::DrawParameters {
            depth_test: glium::DepthTest::IfLess,
            depth_write: true,
            .. std::default::Default::default()
        };

        // drawing a frame
        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.0, 0.0, 0.0), 1.0);
        target.draw(&vertex_buffer,
                    &glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList),
                    &program, &uniforms, &params).unwrap();
        target.finish();

        // polling and handling the events received by the window
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return support::Action::Stop,
                ev => camera.process_input(&ev),
            }
        }

        support::Action::Continue
    });
}
<commit_msg>Write shaders in the teapot example for GLES2<commit_after>extern crate glutin;

#[macro_use]
extern crate glium;

use glium::Surface;

mod support;

fn main() {
    use glium::DisplayBuild;

    // building the display, ie. the main object
    let display = glutin::WindowBuilder::new()
        .with_depth_buffer(24)
        .build_glium()
        .unwrap();

    // building the vertex and index buffers
    let vertex_buffer = support::load_wavefront(&display, include_bytes!("support/teapot.obj"));

    // the program
    let program = program!(&display,
        140 => {
            vertex: "
                #version 140

                uniform mat4 persp_matrix;
                uniform mat4 view_matrix;

                in vec3 position;
                in vec3 normal;
                out vec3 v_position;
                out vec3 v_normal;

                void main() {
                    v_position = position;
                    v_normal = normal;
                    gl_Position = persp_matrix * view_matrix * vec4(v_position * 0.005, 1.0);
                }
            ",

            fragment: "
                #version 140

                in vec3 v_normal;
                out vec4 f_color;

                const vec3 LIGHT = vec3(-0.2, 0.8, 0.1);

                void main() {
                    float lum = max(dot(normalize(v_normal), normalize(LIGHT)), 0.0);
                    vec3 color = (0.3 + 0.7 * lum) * vec3(1.0, 1.0, 1.0);
                    f_color = vec4(color, 1.0);
                }
            ",
        },

        110 => {
            vertex: "
                #version 110

                uniform mat4 persp_matrix;
                uniform mat4 view_matrix;

                attribute vec3 position;
                attribute vec3 normal;
                varying vec3 v_position;
                varying vec3 v_normal;

                void main() {
                    v_position = position;
                    v_normal = normal;
                    gl_Position = persp_matrix * view_matrix * vec4(v_position * 0.005, 1.0);
                }
            ",

            fragment: "
                #version 110

                varying vec3 v_normal;

                const vec3 LIGHT = vec3(-0.2, 0.8, 0.1);

                void main() {
                    float lum = max(dot(normalize(v_normal), normalize(LIGHT)), 0.0);
                    vec3 color = (0.3 + 0.7 * lum) * vec3(1.0, 1.0, 1.0);
                    gl_FragColor = vec4(color, 1.0);
                }
            ",
        },

        100 => {
            vertex: "
                #version 100

                uniform lowp mat4 persp_matrix;
                uniform lowp mat4 view_matrix;

                attribute lowp vec3 position;
                attribute lowp vec3 normal;
                varying lowp vec3 v_position;
                varying lowp vec3 v_normal;

                void main() {
                    v_position = position;
                    v_normal = normal;
                    gl_Position = persp_matrix * view_matrix * vec4(v_position * 0.005, 1.0);
                }
            ",

            fragment: "
                #version 100

                varying lowp vec3 v_normal;

                const lowp vec3 LIGHT = vec3(-0.2, 0.8, 0.1);

                void main() {
                    lowp float lum = max(dot(normalize(v_normal), normalize(LIGHT)), 0.0);
                    lowp vec3 color = (0.3 + 0.7 * lum) * vec3(1.0, 1.0, 1.0);
                    gl_FragColor = vec4(color, 1.0);
                }
            ",
        },
    ).unwrap();

    //
    let mut camera = support::camera::CameraState::new();

    // the main loop
    support::start_loop(|| {
        camera.update();

        // building the uniforms
        let uniforms = uniform! {
            persp_matrix: camera.get_perspective(),
            view_matrix: camera.get_view(),
        };

        // draw parameters
        let params = glium::DrawParameters {
            depth_test: glium::DepthTest::IfLess,
            depth_write: true,
            .. std::default::Default::default()
        };

        // drawing a frame
        let mut target = display.draw();
        target.clear_color_and_depth((0.0, 0.0, 0.0, 0.0), 1.0);
        target.draw(&vertex_buffer,
                    &glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList),
                    &program, &uniforms, &params).unwrap();
        target.finish();

        // polling and handling the events received by the window
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return support::Action::Stop,
                ev => camera.process_input(&ev),
            }
        }

        support::Action::Continue
    });
}
<|endoftext|>