<commit_before>use redox::{self, cmp, env};
use redox::collections::BTreeMap;
use redox::fs::{self, File};
use redox::io::{Read, Seek, SeekFrom};
use redox::time::{self, Duration};
use redox::vec::Vec;
use redox::string::{String, ToString};

use orbital::{event, BmpFile, Color, EventOption, MouseEvent, Window};

pub struct FileType {
    description: String,
    icon: BmpFile,
}

impl FileType {
    pub fn new(desc: &str, icon: &str) -> FileType {
        FileType { description: desc.to_string(), icon: load_icon(icon) }
    }

}

pub struct FileManager {
    file_types: BTreeMap<String, FileType>,
    files: Vec<String>,
    file_sizes: Vec<String>,
    selected: isize,
    last_mouse_event: MouseEvent,
    click_time: Duration,
}

fn load_icon(path: &str) -> BmpFile {
    let mut vec: Vec<u8> = Vec::new();
    if let Some(mut file) = File::open(&("file:///ui/mimetypes/".to_string() + path + ".bmp")) {
        file.read_to_end(&mut vec);
    }
    BmpFile::from_data(&vec)
}

impl FileManager {
    pub fn new() -> Self {
        FileManager {
            file_types: {
                let mut file_types = BTreeMap::<String, FileType>::new();
                file_types.insert("/".to_string(),
                                  FileType::new("Folder", "inode-directory"));
                file_types.insert("wav".to_string(),
                                  FileType::new("WAV audio", "audio-x-wav"));
                file_types.insert("bin".to_string(),
                                  FileType::new("Executable", "application-x-executable"));
                file_types.insert("bmp".to_string(),
                                  FileType::new("Bitmap Image", "image-x-generic"));
                file_types.insert("rs".to_string(),
                                  FileType::new("Rust source code", "text-x-makefile"));
                file_types.insert("crate".to_string(),
                                  FileType::new("Rust crate", "application-x-archive"));
                file_types.insert("rlib".to_string(),
                                  FileType::new("Static Rust library", "application-x-object"));
                file_types.insert("asm".to_string(),
                                  FileType::new("Assembly source", "text-x-makefile"));
                file_types.insert("list".to_string(),
                                  FileType::new("Disassembly source", "text-x-makefile"));
                file_types.insert("c".to_string(),
                                  FileType::new("C source code", "text-x-csrc"));
                file_types.insert("cpp".to_string(),
                                  FileType::new("C++ source code", "text-x-c++src"));
                file_types.insert("h".to_string(),
                                  FileType::new("C header", "text-x-chdr"));
                file_types.insert("sh".to_string(),
                                  FileType::new("Shell script", "text-x-script"));
                file_types.insert("lua".to_string(),
                                  FileType::new("Lua script", "text-x-script"));
                file_types.insert("txt".to_string(),
                                  FileType::new("Plain text document", "text-x-generic"));
                file_types.insert("md".to_string(),
                                  FileType::new("Markdown document", "text-x-generic"));
                file_types.insert("toml".to_string(),
                                  FileType::new("TOML document", "text-x-generic"));
                file_types.insert("json".to_string(),
                                  FileType::new("JSON document", "text-x-generic"));
                file_types.insert("REDOX".to_string(),
                                  FileType::new("Redox package", "text-x-generic"));
                file_types.insert(String::new(),
                                  FileType::new("Unknown file", "unknown"));
                file_types
            },
            files: Vec::new(),
            file_sizes: Vec::new(),
            selected: -1,
            last_mouse_event: MouseEvent {
                x: 0,
                y: 0,
                left_button: false,
                middle_button: false,
                right_button: false,
            },
            click_time: Duration::new(0, 0),
        }
    }

    fn load_icon_with(&self, file_name: &str, row: isize, window: &mut Window) {
        if file_name.ends_with('/') {
            window.image(0,
                         32 * row as isize,
                         self.file_types["/"].icon.width(),
                         self.file_types["/"].icon.height(),
                         self.file_types["/"].icon.as_slice());
        } else {
            let pos = file_name.rfind('.').unwrap_or(0) + 1;
            match self.file_types.get(&file_name[pos..]) {
                Some(file_type) => {
                    window.image(0,
                                 32 * row,
                                 file_type.icon.width(),
                                 file_type.icon.height(),
                                 file_type.icon.as_slice());
                }
                None => {
                    window.image(0,
                                 32 * row,
                                 self.file_types[""].icon.width(),
                                 self.file_types[""].icon.height(),
                                 self.file_types[""].icon.as_slice());
                }
            }
        }
    }

    fn get_description(&self, file_name: &str) -> String {
        if file_name.ends_with('/') {
            self.file_types["/"].description.clone()
        } else {
            let pos = file_name.rfind('.').unwrap_or(0) + 1;
            match self.file_types.get(&file_name[pos..]) {
                Some(file_type) => file_type.description.clone(),
                None => self.file_types[""].description.clone(),
            }
        }
    }

    fn draw_content(&mut self, window: &mut Window) {
        window.set(Color::WHITE);

        let mut i = 0;
        let mut row = 0;
        let column = {
            let mut tmp = [0, 0];
            for string in self.files.iter() {
                if tmp[0] < string.len() {
                    tmp[0] = string.len();
                }
            }

            tmp[0] += 1;

            for file_size in self.file_sizes.iter() {
                if tmp[1] < file_size.len() {
                    tmp[1] = file_size.len();
                }
            }

            tmp[1] += tmp[0] + 1;
            tmp
        };
        for (file_name, file_size) in self.files.iter().zip(self.file_sizes.iter()) {
            if i == self.selected {
                let width = window.width();
                window.rect(0, 32 * row as isize, width, 32, Color::rgba(224, 224, 224, 255));
            }

            self.load_icon_with(&file_name, row as isize, window);

            let mut col = 0;
            for c in file_name.chars() {
                if c == '\n' {
                    col = 0;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col < window.width() / 8 && row < window.height() / 32 {
                        window.char(8 * col as isize + 40,
                                    32 * row as isize + 8,
                                    c,
                                    Color::BLACK);
                        col += 1;
                    }
                }
                if col >= window.width() / 8 {
                    col = 0;
                    row += 1;
                }
            }

            col = column[0];

            for c in file_size.chars() {
                if c == '\n' {
                    col = 0;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col < window.width() / 8 && row < window.height() / 32 {
                        window.char(8 * col as isize + 40,
                                    32 * row as isize + 8,
                                    c,
                                    Color::BLACK);
                        col += 1;
                    }
                }
                if col >= window.width() / 8 {
                    col = 0;
                    row += 1;
                }
            }

            col = column[1];

            for c in self.get_description(file_name).chars() {
                if c == '\n' {
                    col = 0;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col < window.width() / 8 && row < window.height() / 32 {
                        window.char(8 * col as isize + 40,
                                    32 * row as isize + 8,
                                    c,
                                    Color::BLACK);
                        col += 1;
                    }
                }
                if col >= window.width() / 8 {
                    col = 0;
                    row += 1;
                }
            }

            row += 1;
            i += 1;
        }

        window.sync();
    }

    fn main(&mut self, path: &str) {
        let mut width = [48, 48, 48];
        let mut height = 0;
        if let Some(readdir) = fs::read_dir(path) {
            for entry in readdir {
                self.files.push(entry.path().to_string());
                self.file_sizes.push(
                    // When the entry is a folder
                    if entry.path().ends_with('/') {
                        let count = match fs::read_dir(&(path.to_string() + entry.path())) {
                            Some(entry_readdir) => entry_readdir.count(),
                            None => 0
                        };

                        if count == 1 {
                            "1 entry".to_string()
                        } else {
                            format!("{} entries", count)
                        }
                    } else {
                        match File::open(&(path.to_string() + entry.path())) {
                            Some(mut file) => match file.seek(SeekFrom::End(0)) {
                                Some(size) => {
                                    if size >= 1_000_000_000 {
                                        format!("{:.1} GB", (size as f64)/1_000_000_000.0)
                                    } else if size >= 1_000_000 {
                                        format!("{:.1} MB", (size as f64)/1_000_000.0)
                                    } else if size >= 1_000 {
                                        format!("{:.1} KB", (size as f64)/1_000.0)
                                    } else {
                                        format!("{:.1} bytes", size)
                                    }
                                }
                                None => "Failed to seek".to_string()
                            },
                            None => "Failed to open".to_string()
                        }
                    }
                );
                // Unwrapping the last file size will not panic since it has
                // been at least pushed once in the vector
                width[0] = cmp::max(width[0], 48 + (entry.path().len()) * 8);
                width[1] = cmp::max(width[1], 8 + (self.file_sizes.last().unwrap().len()) * 8);
                width[2] = cmp::max(width[2], 8 + (self.get_description(entry.path()).len()) * 8);
            }

            if height < self.files.len() * 32 {
                height = self.files.len() * 32;
            }
        }

        let mut window = Window::new(-1,
                                     -1,
                                     width.iter().sum(),
                                     height,
                                     &path).unwrap();

        self.draw_content(&mut window);

        while let Some(event) = window.poll() {
            match event.to_option() {
                EventOption::Key(key_event) => {
                    if key_event.pressed {
                        match key_event.scancode {
                            event::K_ESC => break,
                            event::K_HOME => self.selected = 0,
                            event::K_UP => if self.selected > 0 {
                                self.selected -= 1;
                            },
                            event::K_END => self.selected = self.files.len() as isize - 1,
                            event::K_DOWN => if self.selected < self.files.len() as isize - 1 {
                                self.selected += 1;
                            },
                            _ => match key_event.character {
                                '\0' => (),
                                '\n' => {
                                    if self.selected >= 0 &&
                                       self.selected < self.files.len() as isize {
                                        match self.files.get(self.selected as usize) {
                                            Some(file) => {
                                                File::exec(&(path.to_string() + &file));
                                            },
                                            None => (),
                                        }
                                    }
                                }
                                _ => {
                                    let mut i = 0;
                                    for file in self.files.iter() {
                                        if file.starts_with(key_event.character) {
                                            self.selected = i;
                                            break;
                                        }
                                        i += 1;
                                    }
                                }
                            },
                        }

                        self.draw_content(&mut window);
                    }
                }
                EventOption::Mouse(mouse_event) => {
                    let mut redraw = false;
                    let mut i = 0;
                    let mut row = 0;
                    for file in self.files.iter() {
                        let mut col = 0;
                        for c in file.chars() {
                            if mouse_event.y >= 32 * row as isize &&
                               mouse_event.y < 32 * row as isize + 32 {
                                self.selected = i;
                                redraw = true;
                            }

                            if c == '\n' {
                                col = 0;
                                row += 1;
                            } else if c == '\t' {
                                col += 8 - col % 8;
                            } else {
                                if col < window.width() / 8 && row < window.height() / 32 {
                                    col += 1;
                                }
                            }
                            if col >= window.width() / 8 {
                                col = 0;
                                row += 1;
                            }
                        }
                        row += 1;
                        i += 1;
                    }

                    if redraw {
                        self.draw_content(&mut window);
                    }

                    //Check for double click
                    if mouse_event.left_button {
                        let click_time = Duration::realtime();

                        if click_time - self.click_time < Duration::new(0, 500 * time::NANOS_PER_MILLI)
                            && self.last_mouse_event.x == mouse_event.x
                            && self.last_mouse_event.y == mouse_event.y {
                            if self.selected >= 0 && self.selected < self.files.len() as isize {
                                if let Some(file) = self.files.get(self.selected as usize) {
                                    File::exec(&(path.to_string() + &file));
                                }
                            }
                            self.click_time = Duration::new(0, 0);
                        } else {
                            self.click_time = click_time;
                        }
                    }
                    self.last_mouse_event = mouse_event;
                }
                EventOption::Quit(quit_event) => break,
                _ => (),
            }
        }
    }
}

pub fn main() {
    match env::args().get(1) {
        Some(arg) => FileManager::new().main(arg),
        None => FileManager::new().main("file:///"),
    }
}
<commit_msg>Make navigation work again<commit_after>use redox::Box;
use redox::{self, cmp, env};
use redox::collections::BTreeMap;
use redox::fs::{self, File};
use redox::io::{Read, Seek, SeekFrom};
use redox::time::{self, Duration};
use redox::vec::Vec;
use redox::string::{String, ToString};

use orbital::{event, BmpFile, Color, EventOption, MouseEvent, Window};

struct FileType {
    description: String,
    icon: BmpFile,
}

impl FileType {
    fn new(desc: &str, icon: &str) -> FileType {
        FileType { description: desc.to_string(), icon: load_icon(icon) }
    }

}

struct FileTypesInfo {
    file_types: BTreeMap<String, FileType>,
}

impl FileTypesInfo {
    pub fn new () -> FileTypesInfo {
        let mut file_types = BTreeMap::<String, FileType>::new();
        file_types.insert("/".to_string(),
                          FileType::new("Folder", "inode-directory"));
        file_types.insert("wav".to_string(),
                          FileType::new("WAV audio", "audio-x-wav"));
        file_types.insert("bin".to_string(),
                          FileType::new("Executable", "application-x-executable"));
        file_types.insert("bmp".to_string(),
                          FileType::new("Bitmap Image", "image-x-generic"));
        file_types.insert("rs".to_string(),
                          FileType::new("Rust source code", "text-x-makefile"));
        file_types.insert("crate".to_string(),
                          FileType::new("Rust crate", "application-x-archive"));
        file_types.insert("rlib".to_string(),
                          FileType::new("Static Rust library", "application-x-object"));
        file_types.insert("asm".to_string(),
                          FileType::new("Assembly source", "text-x-makefile"));
        file_types.insert("list".to_string(),
                          FileType::new("Disassembly source", "text-x-makefile"));
        file_types.insert("c".to_string(),
                          FileType::new("C source code", "text-x-csrc"));
        file_types.insert("cpp".to_string(),
                          FileType::new("C++ source code", "text-x-c++src"));
        file_types.insert("h".to_string(),
                          FileType::new("C header", "text-x-chdr"));
        file_types.insert("sh".to_string(),
                          FileType::new("Shell script", "text-x-script"));
        file_types.insert("lua".to_string(),
                          FileType::new("Lua script", "text-x-script"));
        file_types.insert("txt".to_string(),
                          FileType::new("Plain text document", "text-x-generic"));
        file_types.insert("md".to_string(),
                          FileType::new("Markdown document", "text-x-generic"));
        file_types.insert("toml".to_string(),
                          FileType::new("TOML document", "text-x-generic"));
        file_types.insert("json".to_string(),
                          FileType::new("JSON document", "text-x-generic"));
        file_types.insert("REDOX".to_string(),
                          FileType::new("Redox package", "text-x-generic"));
        file_types.insert("".to_string(),
                          FileType::new("Unknown file", "unknown"));
        FileTypesInfo { file_types: file_types }
    }

    pub fn description_for(&self, file_name: &str) -> String {
        if file_name.ends_with('/') {
            self.file_types["/"].description.clone()
        } else {
            let pos = file_name.rfind('.').unwrap_or(0) + 1;
            let ext = &file_name[pos..];
            if self.file_types.contains_key(ext) {
                self.file_types[ext].description.clone()
            } else {
                self.file_types[""].description.clone()
            }
        }
    }

    pub fn icon_for(&self, file_name: &str) -> &BmpFile {
        if file_name.ends_with('/') {
            &self.file_types["/"].icon
        } else {
            let pos = file_name.rfind('.').unwrap_or(0) + 1;
            let ext = &file_name[pos..];
            if self.file_types.contains_key(ext) {
                &self.file_types[ext].icon
            } else {
                &self.file_types[""].icon
            }
        }
    }
}

enum FileManagerCommand {
    ChangeDir(String),
    Execute(String),
    Redraw,
    Quit,
}

pub struct FileManager {
    file_types_info: FileTypesInfo,
    files: Vec<String>,
    file_sizes: Vec<String>,
    selected: isize,
    last_mouse_event: MouseEvent,
    click_time: Duration,
    window: Box<Window>,
}

fn load_icon(path: &str) -> BmpFile {
    let mut vec: Vec<u8> = Vec::new();
    if let Some(mut file) = File::open(&("file:///ui/mimetypes/".to_string() + path + ".bmp")) {
        file.read_to_end(&mut vec);
    }
    BmpFile::from_data(&vec)
}

impl FileManager {
    pub fn new() -> Self {
        FileManager {
            file_types_info: FileTypesInfo::new(),
            files: Vec::new(),
            file_sizes: Vec::new(),
            selected: -1,
            last_mouse_event: MouseEvent {
                x: 0,
                y: 0,
                left_button: false,
                middle_button: false,
                right_button: false,
            },
            click_time: Duration::new(0, 0),
            window: Window::new(-1,-1,0,0,"").unwrap(),
        }
    }

    fn draw_content(&mut self) {
        self.window.set(Color::WHITE);

        let mut i = 0;
        let mut row = 0;
        let column = {
            let mut tmp = [0, 0];
            for string in self.files.iter() {
                if tmp[0] < string.len() {
                    tmp[0] = string.len();
                }
            }

            tmp[0] += 1;

            for file_size in self.file_sizes.iter() {
                if tmp[1] < file_size.len() {
                    tmp[1] = file_size.len();
                }
            }

            tmp[1] += tmp[0] + 1;
            tmp
        };
        for (file_name, file_size) in self.files.iter().zip(self.file_sizes.iter()) {
            if i == self.selected {
                let width = self.window.width();
                self.window.rect(0, 32 * row as isize, width, 32, Color::rgba(224, 224, 224, 255));
            }

            let icon = self.file_types_info.icon_for(&file_name);
            self.window.image(0,
                              32 * row as isize,
                              icon.width(),
                              icon.height(),
                              icon.as_slice());

            let mut col = 0;
            for c in file_name.chars() {
                if c == '\n' {
                    col = 0;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col < self.window.width() / 8 && row < self.window.height() / 32 {
                        self.window.char(8 * col as isize + 40,
                                    32 * row as isize + 8,
                                    c,
                                    Color::BLACK);
                        col += 1;
                    }
                }
                if col >= self.window.width() / 8 {
                    col = 0;
                    row += 1;
                }
            }

            col = column[0];

            for c in file_size.chars() {
                if c == '\n' {
                    col = 0;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col < self.window.width() / 8 && row < self.window.height() / 32 {
                        self.window.char(8 * col as isize + 40,
                                    32 * row as isize + 8,
                                    c,
                                    Color::BLACK);
                        col += 1;
                    }
                }
                if col >= self.window.width() / 8 {
                    col = 0;
                    row += 1;
                }
            }

            col = column[1];

            let description = self.file_types_info.description_for(&file_name);
            for c in description.chars() {
                if c == '\n' {
                    col = 0;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col < self.window.width() / 8 && row < self.window.height() / 32 {
                        self.window.char(8 * col as isize + 40,
                                    32 * row as isize + 8,
                                    c,
                                    Color::BLACK);
                        col += 1;
                    }
                }
                if col >= self.window.width() / 8 {
                    col = 0;
                    row += 1;
                }
            }

            row += 1;
            i += 1;
        }

        self.window.sync();
    }

    fn set_path(&mut self, path: &str) {
        let mut width = [48, 48, 48];
        let mut height = 0;
        if let Some(readdir) = fs::read_dir(path) {
            self.files.clear();
            for entry in readdir {
                self.files.push(entry.path().to_string());
                self.file_sizes.push(
                    // When the entry is a folder
                    if entry.path().ends_with('/') {
                        let count = match fs::read_dir(&(path.to_string() + entry.path())) {
                            Some(entry_readdir) => entry_readdir.count(),
                            None => 0
                        };

                        if count == 1 {
                            "1 entry".to_string()
                        } else {
                            format!("{} entries", count)
                        }
                    } else {
                        match File::open(&(path.to_string() + entry.path())) {
                            Some(mut file) => match file.seek(SeekFrom::End(0)) {
                                Some(size) => {
                                    if size >= 1_000_000_000 {
                                        format!("{:.1} GB", (size as f64)/1_000_000_000.0)
                                    } else if size >= 1_000_000 {
                                        format!("{:.1} MB", (size as f64)/1_000_000.0)
                                    } else if size >= 1_000 {
                                        format!("{:.1} KB", (size as f64)/1_000.0)
                                    } else {
                                        format!("{:.1} bytes", size)
                                    }
                                }
                                None => "Failed to seek".to_string()
                            },
                            None => "Failed to open".to_string()
                        }
                    }
                );
                // Unwrapping the last file size will not panic since it has
                // been at least pushed once in the vector
                let description = self.file_types_info.description_for(entry.path());
                width[0] = cmp::max(width[0], 48 + (entry.path().len()) * 8);
                width[1] = cmp::max(width[1], 8 + (self.file_sizes.last().unwrap().len()) * 8);
                width[2] = cmp::max(width[2], 8 + (description.len()) * 8);
            }

            if height < self.files.len() * 32 {
                height = self.files.len() * 32;
            }
        }
        self.window = Window::new(self.window.x(),
                                  self.window.y(),
                                  width.iter().sum(),
                                  height,
                                  &path).unwrap();
        self.draw_content();
    }

    fn event_loop(&mut self) -> Option<FileManagerCommand> {
        let mut redraw = false;
        let mut command = None;
        if let Some(event) = self.window.poll() {
            match event.to_option() {
                EventOption::Key(key_event) => {
                    if key_event.pressed {
                        match key_event.scancode {
                            event::K_ESC => return Some(FileManagerCommand::Quit),
                            event::K_HOME => self.selected = 0,
                            event::K_UP => if self.selected > 0 {
                                self.selected -= 1;
                                redraw = true
                            },
                            event::K_END => self.selected = self.files.len() as isize - 1,
                            event::K_DOWN => if self.selected < self.files.len() as isize - 1 {
                                self.selected += 1;
                            },
                            _ => match key_event.character {
                                '\0' => (),
                                '\n' => {
                                    if self.selected >= 0 &&
                                       self.selected < self.files.len() as isize {
                                        match self.files.get(self.selected as usize) {
                                            Some(file) => {
                                                if file.ends_with('/') {
                                                    command = Some(FileManagerCommand::ChangeDir(file.clone()));
                                                } else {
                                                    command = Some(FileManagerCommand::Execute(file.clone()));
                                                }
                                            },
                                            None => (),
                                        }
                                    }
                                }
                                _ => {
                                    let mut i = 0;
                                    for file in self.files.iter() {
                                        if file.starts_with(key_event.character) {
                                            self.selected = i;
                                            break;
                                        }
                                        i += 1;
                                    }
                                }
                            },
                        }
                        if command.is_none() && redraw {
                            command = Some(FileManagerCommand::Redraw);
                        }
                    }
                }
                EventOption::Mouse(mouse_event) => {
                    let mut redraw = false;
                    let mut i = 0;
                    let mut row = 0;
                    for file in self.files.iter() {
                        let mut col = 0;
                        for c in file.chars() {
                            if mouse_event.y >= 32 * row as isize &&
                               mouse_event.y < 32 * row as isize + 32 {
                                self.selected = i;
                            }

                            if c == '\n' {
                                col = 0;
                                row += 1;
                            } else if c == '\t' {
                                col += 8 - col % 8;
                            } else {
                                if col < self.window.width() / 8 && row < self.window.height() / 32 {
                                    col += 1;
                                }
                            }
                            if col >= self.window.width() / 8 {
                                col = 0;
                                row += 1;
                            }
                        }
                        row += 1;
                        i += 1; }

                    //Check for double click
                    if mouse_event.left_button {
                        let click_time = Duration::realtime();

                        if click_time - self.click_time < Duration::new(0, 500 * time::NANOS_PER_MILLI)
                            && self.last_mouse_event.x == mouse_event.x
                            && self.last_mouse_event.y == mouse_event.y {
                            if self.selected >= 0 && self.selected < self.files.len() as isize {
                                if let Some(file) = self.files.get(self.selected as usize) {
                                    if file.ends_with('/') {
                                        command = Some(FileManagerCommand::ChangeDir(file.clone()));
                                    } else {
                                        command = Some(FileManagerCommand::Execute(file.clone()));
                                    }
                                }
                            }
                            self.click_time = Duration::new(0, 0);
                        } else {
                            self.click_time = click_time;
                        }
                    }
                    self.last_mouse_event = mouse_event;
                }
                EventOption::Quit(quit_event) => command = Some(FileManagerCommand::Quit),
                _ => (),
            }
        }
        command
    }

    fn main(&mut self, path: &str) {
        let mut current_path = path.to_string();
        self.set_path(path);
        while true {
            match self.event_loop() {
                Some(event) => {
                    match event {
                        FileManagerCommand::ChangeDir(dir) => {
                            current_path = current_path + &dir;
                            self.set_path(&current_path);
                        },
                        FileManagerCommand::Execute(cmd) => { File::exec(&(current_path.clone() + &cmd)); } ,
                        FileManagerCommand::Redraw => (),
                        FileManagerCommand::Quit => break,
                    };
                    self.draw_content();
                },
                None => (),
            };
        }

    }
}

pub fn main() {
    match env::args().get(1) {
        Some(arg) => FileManager::new().main(arg),
        None => FileManager::new().main("file:///"),
    }
}
<|endoftext|>


<commit_before>use alloc::boxed::Box;

use arch::context::context_switch;
use arch::memory;

use core::{cmp, mem};

use common::time::{self, Duration};

use drivers::pci::config::PciConfig;
use drivers::io::{Io, Mmio, Pio, PhysAddr};

use fs::{KScheme, Resource, Url};

use syscall;

#[repr(packed)]
struct Bd {
    ptr: PhysAddr<Mmio<u32>>,
    samples: Mmio<u32>,
}

struct Ac97Resource {
    audio: usize,
    bus_master: usize,
    bdl: *mut Bd,
}

impl Resource for Ac97Resource {
    fn dup(&self) -> syscall::Result<Box<Resource>> {
        Ok(box Ac97Resource {
            audio: self.audio,
            bus_master: self.bus_master,
            bdl: self.bdl
        })
    }

    fn path(&self, buf: &mut [u8]) -> syscall::Result <usize> {
        let path = b"audio:";

        let mut i = 0;
        while i < buf.len() && i < path.len() {
            buf[i] = path[i];
            i += 1;
        }

        Ok(i)
    }

    fn write(&mut self, buf: &[u8]) -> syscall::Result<usize> {
        unsafe {
            let audio = self.audio as u16;

            let mut master_volume = Pio::<u16>::new(audio + 2);
            let mut pcm_volume = Pio::<u16>::new(audio + 0x18);

            debugln!("MASTER {:X} PCM {:X}", master_volume.read(), pcm_volume.read());

            master_volume.write(0);
            pcm_volume.write(0);

            debugln!("MASTER {:X} PCM {:X}", master_volume.read(), pcm_volume.read());

            let bus_master = self.bus_master as u16;

            let po_civ = Pio::<u8>::new(bus_master + 0x14);
            let mut po_lvi = Pio::<u8>::new(bus_master + 0x15);
            let mut po_cr = Pio::<u8>::new(bus_master + 0x1B);

            loop {
                if po_cr.read() & 1 == 0 {
                    break;
                }
                context_switch();
            }

            po_cr.write(0);

            for i in 0..32 {
                (*self.bdl.offset(i)).ptr.write(0);
                (*self.bdl.offset(i)).samples.write(0);
            }

            let mut wait = false;
            let mut position = 0;

            let mut lvi = po_lvi.read();

            let start_lvi;
            if lvi == 0 {
                start_lvi = 31;
            } else {
                start_lvi = lvi - 1;
            }

            lvi += 1;
            if lvi >= 32 {
                lvi = 0;
            }
            loop {
                while wait {
                    if po_civ.read() != lvi as u8 {
                        break;
                    }

                    {
                        let contexts = &mut *::env().contexts.get();
                        if let Ok(mut current) = contexts.current_mut() {
                            current.wake = Some(Duration::monotonic() + Duration::new(0, 10 * time::NANOS_PER_MILLI));
                            current.block("AC97 sleep 1");
                        }
                    }

                    context_switch();
                }

                debugln!("AC97 {} / {}: {} / {}",
                       po_civ.read(),
                       lvi as usize,
                       position,
                       buf.len());

                let bytes = cmp::min(65534 * 2, (buf.len() - position + 1));
                let samples = bytes / 2;

                (*self.bdl.offset(lvi as isize)).ptr.write(buf.as_ptr().offset(position as isize) as u32);
                (*self.bdl.offset(lvi as isize)).samples.write((samples & 0xFFFF) as u32);

                position += bytes;

                if position >= buf.len() {
                    break;
                }

                lvi += 1;

                if lvi >= 32 {
                    lvi = 0;
                }

                if lvi == start_lvi {
                    po_lvi.write(start_lvi);
                    po_cr.write(1);
                    wait = true;
                }
            }

            po_lvi.write(lvi);
            po_cr.write(1);

            loop {
                if po_civ.read() == lvi {
                    po_cr.write(0);
                    break;
                }

                {
                    let contexts = &mut *::env().contexts.get();
                    if let Ok(mut current) = contexts.current_mut() {
                        current.wake = Some(Duration::monotonic() + Duration::new(0, 10 * time::NANOS_PER_MILLI));
                        current.block("AC97 sleep 2");
                    }
                }

                context_switch();
            }

            debug!("AC97 Finished {} / {}\n", po_civ.read(), lvi);
        }

        Ok(buf.len())
    }
}

pub struct Ac97 {
    audio: usize,
    bus_master: usize,
    irq: u8,
    bdl: *mut Bd,
}

impl KScheme for Ac97 {
    fn scheme(&self) -> &str {
        "audio"
    }

    fn open(&mut self, _: Url, _: usize) -> syscall::Result<Box<Resource>> {
        Ok(box Ac97Resource {
            audio: self.audio,
            bus_master: self.bus_master,
            bdl: self.bdl
        })
    }

    fn on_irq(&mut self, irq: u8) {
        if irq == self.irq {
            // d("AC97 IRQ\n");
        }
    }
}

impl Ac97 {
    pub unsafe fn new(mut pci: PciConfig) -> Box<Ac97> {
        pci.flag(4, 4, true); // Bus mastering

        let module = box Ac97 {
            audio: pci.read(0x10) as usize & 0xFFFFFFF0,
            bus_master: pci.read(0x14) as usize & 0xFFFFFFF0,
            irq: pci.read(0x3C) as u8 & 0xF,
            bdl: memory::alloc(32 * mem::size_of::<Bd>()) as *mut Bd,
        };

        debug!(" + AC97 on: {:X}, {:X}, IRQ: {:X}\n", module.audio, module.bus_master, module.irq);

        let mut po_bdbar = PhysAddr::new(Pio::<u32>::new(module.bus_master as u16 + 0x10));
        po_bdbar.write(module.bdl as u32);

        module
    }
}
<commit_msg>Find physical address of userspace audio buffer<commit_after>use alloc::boxed::Box;

use arch::context::context_switch;
use arch::memory;

use core::{cmp, mem};

use common::time::{self, Duration};

use drivers::pci::config::PciConfig;
use drivers::io::{Io, Mmio, Pio, PhysAddr};

use fs::{KScheme, Resource, Url};

use syscall;

#[repr(packed)]
struct Bd {
    ptr: PhysAddr<Mmio<u32>>,
    samples: Mmio<u32>,
}

struct Ac97Resource {
    audio: usize,
    bus_master: usize,
    bdl: *mut Bd,
}

impl Resource for Ac97Resource {
    fn dup(&self) -> syscall::Result<Box<Resource>> {
        Ok(box Ac97Resource {
            audio: self.audio,
            bus_master: self.bus_master,
            bdl: self.bdl
        })
    }

    fn path(&self, buf: &mut [u8]) -> syscall::Result <usize> {
        let path = b"audio:";

        let mut i = 0;
        while i < buf.len() && i < path.len() {
            buf[i] = path[i];
            i += 1;
        }

        Ok(i)
    }

    fn write(&mut self, buf: &[u8]) -> syscall::Result<usize> {
        unsafe {
            let audio = self.audio as u16;

            let mut master_volume = Pio::<u16>::new(audio + 2);
            let mut pcm_volume = Pio::<u16>::new(audio + 0x18);

            debugln!("MASTER {:X} PCM {:X}", master_volume.read(), pcm_volume.read());

            master_volume.write(0);
            pcm_volume.write(0x808);

            debugln!("MASTER {:X} PCM {:X}", master_volume.read(), pcm_volume.read());

            let bus_master = self.bus_master as u16;

            let po_civ = Pio::<u8>::new(bus_master + 0x14);
            let mut po_lvi = Pio::<u8>::new(bus_master + 0x15);
            let mut po_cr = Pio::<u8>::new(bus_master + 0x1B);

            loop {
                if po_cr.read() & 1 == 0 {
                    break;
                }
                context_switch();
            }

            po_cr.write(0);

            for i in 0..32 {
                (*self.bdl.offset(i)).ptr.write(0);
                (*self.bdl.offset(i)).samples.write(0);
            }

            let mut wait = false;
            let mut position = 0;

            let mut lvi = po_lvi.read();

            let start_lvi;
            if lvi == 0 {
                start_lvi = 31;
            } else {
                start_lvi = lvi - 1;
            }

            lvi += 1;
            if lvi >= 32 {
                lvi = 0;
            }
            loop {
                while wait {
                    if po_civ.read() != lvi as u8 {
                        break;
                    }

                    {
                        let contexts = &mut *::env().contexts.get();
                        if let Ok(mut current) = contexts.current_mut() {
                            current.wake = Some(Duration::monotonic() + Duration::new(0, 10 * time::NANOS_PER_MILLI));
                            current.block("AC97 sleep 1");
                        }
                    }

                    context_switch();
                }

                debugln!("AC97 {} / {}: {} / {}",
                       po_civ.read(),
                       lvi as usize,
                       position,
                       buf.len());

                let bytes = cmp::min(65534 * 2, (buf.len() - position + 1));
                let samples = bytes / 2;

                let mut phys_buf = buf.as_ptr() as usize;
                {
                    let contexts = &mut *::env().contexts.get();
                    if let Ok(current) = contexts.current() {
                        if let Ok(phys) = current.translate(buf.as_ptr().offset(position as isize) as usize, bytes) {
                            debugln!("logical {:#X} -> physical {:#X}", &(buf.as_ptr() as usize), &phys);
                            phys_buf = phys;
                        }
                    }
                }

                (*self.bdl.offset(lvi as isize)).ptr.write(phys_buf as u32);
                (*self.bdl.offset(lvi as isize)).samples.write((samples & 0xFFFF) as u32);

                position += bytes;

                if position >= buf.len() {
                    break;
                }

                lvi += 1;

                if lvi >= 32 {
                    lvi = 0;
                }

                if lvi == start_lvi {
                    po_lvi.write(start_lvi);
                    po_cr.write(1);
                    wait = true;
                }
            }

            po_lvi.write(lvi);
            po_cr.write(1);

            loop {
                if po_civ.read() == lvi {
                    po_cr.write(0);
                    break;
                }

                {
                    let contexts = &mut *::env().contexts.get();
                    if let Ok(mut current) = contexts.current_mut() {
                        current.wake = Some(Duration::monotonic() + Duration::new(0, 10 * time::NANOS_PER_MILLI));
                        current.block("AC97 sleep 2");
                    }
                }

                context_switch();
            }

            debug!("AC97 Finished {} / {}\n", po_civ.read(), lvi);
        }

        Ok(buf.len())
    }
}

pub struct Ac97 {
    audio: usize,
    bus_master: usize,
    irq: u8,
    bdl: *mut Bd,
}

impl KScheme for Ac97 {
    fn scheme(&self) -> &str {
        "audio"
    }

    fn open(&mut self, _: Url, _: usize) -> syscall::Result<Box<Resource>> {
        Ok(box Ac97Resource {
            audio: self.audio,
            bus_master: self.bus_master,
            bdl: self.bdl
        })
    }

    fn on_irq(&mut self, irq: u8) {
        if irq == self.irq {
            // d("AC97 IRQ\n");
        }
    }
}

impl Ac97 {
    pub unsafe fn new(mut pci: PciConfig) -> Box<Ac97> {
        pci.flag(4, 4, true); // Bus mastering

        let module = box Ac97 {
            audio: pci.read(0x10) as usize & 0xFFFFFFF0,
            bus_master: pci.read(0x14) as usize & 0xFFFFFFF0,
            irq: pci.read(0x3C) as u8 & 0xF,
            bdl: memory::alloc(32 * mem::size_of::<Bd>()) as *mut Bd,
        };

        debug!(" + AC97 on: {:X}, {:X}, IRQ: {:X}\n", module.audio, module.bus_master, module.irq);

        let mut po_bdbar = PhysAddr::new(Pio::<u32>::new(module.bus_master as u16 + 0x10));
        po_bdbar.write(module.bdl as u32);

        module
    }
}
<|endoftext|>


<commit_before><commit_msg>fix mac build<commit_after><|endoftext|>


<commit_before>
/// Get the port from a string (ip)
pub fn parse_port(string: &str) -> &str {
    let mut a = 0;
    let mut b = 0;

    for (n, c) in string.chars().enumerate() {
        match c {
            '0' | '1' |
            '2' | '3' |
            '4' | '5' |
            '6' | '7' |
            '8' | '9' => b += 1,
            ':' => a = n + 1,
            _ => break,
        }
    }

    &string[a..b + 1]

}

/// Get the host from a string (ip)
pub fn parse_host(string: &str) -> &str {
    let mut b = 0;

    // TODO: Username/Password syntax
    for (n, c) in string.chars().enumerate() {
        match c {
            ':' | '/' => break,
            _ => b += 1,
        }
    }

    &string[..b + 1]

}
<commit_msg>Unpanickify any possible panics in `parse_host()`<commit_after>
/// Get the port from a string (ip)
pub fn parse_port(string: &str) -> &str {
    let mut a = 0;
    let mut b = 0;

    for (n, c) in string.chars().enumerate() {
        match c {
            '0' | '1' |
            '2' | '3' |
            '4' | '5' |
            '6' | '7' |
            '8' | '9' => b += 1,
            ':' => a = n + 1,
            _ => break,
        }
    }

    &string[a..b + 1]
}

/// Get the host from a string (ip)
pub fn parse_host(string: &str) -> &str {
    // TODO: Username/Password syntax
    let pos = match string.find(':') {
        Some(pos) => pos + 1,
        None => match string.find('/') {
            Some(pos) => pos + 1,
            None => string.len(),
        },
    };

    &string[..pos]
}
<|endoftext|>


<commit_before>import libc::c_double;
import azure::*;
import azure::bindgen::*;
import azure::cairo;
import azure::cairo::bindgen::*;

// FIXME: Busy wait hack
fn sleep() {
    iter::repeat(100000u) {||
        task::yield();
    }
}

fn main() {
    // The platform event handler thread
    let osmain_ch = osmain::osmain();

    // The drawing task
    let draw_ch = gfx::compositor::compositor(osmain_ch);

    // The model
    let model_ch = task::spawn_listener {|po|
        let mut x1 = 100;
        let mut y1 = 100;
        let mut w1 = 200;
        let mut h1 = 200;
        let mut x2 = 200;
        let mut y2 = 200;
        let mut w2 = 300;
        let mut h2 = 300;

        while !comm::peek(po) {
            let model = {
                x1: x1, y1: y1, w1: w1, h1: h1,
                x2: x2, y2: y2, w2: w2, h2: h2
            };
            comm::send(draw_ch, gfx::compositor::draw(model));

            sleep();

            x1 += 1;
            y1 += 1;
            x2 -= 1;
            y2 -= 1;
            if x1 > 800 { x1 = 0 }
            if y1 > 600 { y1 = 0 }
            if x2 < 0 { x2 = 800 }
            if y2 < 0 { y2 = 600 }
        }
    };

    // The keyboard handler
    input::input(osmain_ch, draw_ch, model_ch);
}<commit_msg>Cleanup<commit_after>import libc::c_double;
import azure::*;
import azure::bindgen::*;
import azure::cairo;
import azure::cairo::bindgen::*;

// FIXME: Busy wait hack
fn sleep() {
    iter::repeat(100000u) {||
        task::yield();
    }
}

fn main() {
    // The platform event handler thread
    let osmain_ch = osmain::osmain();

    // The compositor
    let draw_ch = gfx::compositor::compositor(osmain_ch);

    // Not sure what this is but it decides what to draw
    let model_ch = task::spawn_listener {|po|
        let mut x1 = 100;
        let mut y1 = 100;
        let mut w1 = 200;
        let mut h1 = 200;
        let mut x2 = 200;
        let mut y2 = 200;
        let mut w2 = 300;
        let mut h2 = 300;

        while !comm::peek(po) {
            let model = {
                x1: x1, y1: y1, w1: w1, h1: h1,
                x2: x2, y2: y2, w2: w2, h2: h2
            };
            comm::send(draw_ch, gfx::compositor::draw(model));

            sleep();

            x1 += 1;
            y1 += 1;
            x2 -= 1;
            y2 -= 1;
            if x1 > 800 { x1 = 0 }
            if y1 > 600 { y1 = 0 }
            if x2 < 0 { x2 = 800 }
            if y2 < 0 { y2 = 600 }
        }
    };

    // The keyboard handler
    input::input(osmain_ch, draw_ch, model_ch);
}<|endoftext|>


<commit_before>#![crate_type="staticlib"]
#![feature(alloc)]
#![feature(allocator)]
#![feature(arc_counts)]
#![feature(asm)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(core_str_ext)]
#![feature(core_slice_ext)]
#![feature(fnbox)]
#![feature(fundamental)]
#![feature(lang_items)]
#![feature(no_std)]
#![feature(unboxed_closures)]
#![feature(unsafe_no_drop_flag)]
#![feature(unwind_attributes)]
#![feature(vec_push_all)]
#![no_std]

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate collections;

use alloc::boxed::Box;

use collections::string::{String, ToString};
use collections::vec::Vec;

use core::cell::UnsafeCell;
use core::{ptr, mem, usize};
use core::slice::SliceExt;

use common::debug;
use common::event::{self, EVENT_KEY, EventOption};
use common::memory;
use common::paging::Page;
use common::time::Duration;

use drivers::pci::*;
use drivers::pio::*;
use drivers::ps2::*;
use drivers::rtc::*;
use drivers::serial::*;

use env::Environment;

pub use externs::*;

use graphics::display;

use programs::executor::execute;
use programs::scheme::*;

use scheduler::{Context, Regs, TSS};
use scheduler::context::{context_enabled, context_switch, context_i, context_pid};

use schemes::Url;
use schemes::arp::*;
use schemes::context::*;
use schemes::debug::*;
use schemes::ethernet::*;
use schemes::icmp::*;
use schemes::ip::*;
use schemes::memory::*;
// use schemes::display::*;

use syscall::handle::*;

/// Common std-like functionality
#[macro_use]
pub mod common;
/// Allocation
pub mod alloc_system;
/// Audio
pub mod audio;
/// Various drivers
/// TODO: Move out of kernel space (like other microkernels)
pub mod drivers;
/// Environment
pub mod env;
/// Externs
pub mod externs;
/// Various graphical methods
pub mod graphics;
/// Network
pub mod network;
/// Panic
pub mod panic;
/// Programs
pub mod programs;
/// Schemes
pub mod schemes;
/// Scheduling
pub mod scheduler;
/// Sync primatives
pub mod sync;
/// System calls
pub mod syscall;
/// USB input/output
pub mod usb;

pub static mut TSS_PTR: Option<&'static mut TSS> = None;
pub static mut ENV_PTR: Option<&'static mut Environment> = None;

pub fn env() -> &'static Environment {
    unsafe {
        match ENV_PTR {
            Some(&mut ref p) => p,
            None => unreachable!(),
        }
    }
}

/// Pit duration
static PIT_DURATION: Duration = Duration {
    secs: 0,
    nanos: 2250286,
};

/// Idle loop (active while idle)
unsafe fn idle_loop() -> ! {
    loop {
        asm!("cli" : : : : "intel", "volatile");

        let mut halt = true;

        {
            let contexts = ::env().contexts.lock();
            for i in 1..contexts.len() {
                if let Some(context) = contexts.get(i) {
                    if context.interrupted {
                        halt = false;
                        break;
                    }
                }
            }
        }

        if halt {
            asm!("sti" : : : : "intel", "volatile");
            asm!("hlt" : : : : "intel", "volatile");
        } else {
            asm!("sti" : : : : "intel", "volatile");
        }

        context_switch(false);
    }
}

/// Event poll loop
fn poll_loop() -> ! {
    loop {
        env().on_poll();

        unsafe { context_switch(false) };
    }
}

/// Event loop
fn event_loop() -> ! {
    let mut cmd = String::new();
    loop {
        loop {
            let mut console = env().console.lock();
            match env().events.lock().pop_front() {
                Some(event) => {
                    if console.draw {
                        match event.to_option() {
                            EventOption::Key(key_event) => {
                                if key_event.pressed {
                                    match key_event.scancode {
                                        event::K_F2 => {
                                            console.draw = false;
                                        }
                                        event::K_BKSP => if !cmd.is_empty() {
                                            console.write(&[8]);
                                            cmd.pop();
                                        },
                                        _ => match key_event.character {
                                            '\0' => (),
                                            '\n' => {
                                                console.command = Some(cmd.clone());

                                                cmd.clear();
                                                console.write(&[10]);
                                            }
                                            _ => {
                                                cmd.push(key_event.character);
                                                console.write(&[key_event.character as u8]);
                                            }
                                        },
                                    }
                                }
                            }
                            _ => (),
                        }
                    } else {
                        if event.code == EVENT_KEY && event.b as u8 == event::K_F1 && event.c > 0 {
                            console.draw = true;
                            console.redraw = true;
                        } else {
                            // TODO: Magical orbital hack
                            unsafe {
                                for scheme in env().schemes.iter() {
                                    if (*scheme.get()).scheme() == "orbital" {
                                        (*scheme.get()).event(&event);
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
                None => break,
            }
        }

        {
            let mut console = env().console.lock();
            if console.draw && console.redraw {
                console.redraw = false;
                console.display.flip();
            }
        }

        unsafe { context_switch(false) };
    }
}

/// Initialize kernel
unsafe fn init(font_data: usize, tss_data: usize) {
    Page::init();
    memory::cluster_init();
    // Unmap first page to catch null pointer errors (after reading memory map)
    Page::new(0).unmap();

    sync::intex::intex_count = 0;

    display::fonts = font_data;
    TSS_PTR = Some(&mut *(tss_data as *mut TSS));
    ENV_PTR = Some(&mut *Box::into_raw(Environment::new()));

    context_pid = 1;
    context_i = 0;
    context_enabled = false;

    match ENV_PTR {
        Some(ref mut env) => {
            env.contexts.lock().push(Context::root());
            env.console.lock().draw = true;

            debug!("Redox ");
            debug::dd(mem::size_of::<usize>() * 8);
            debug!(" bits");
            debug::dl();

            env.clock_realtime = Rtc::new().time();

            env.schemes.push(UnsafeCell::new(Ps2::new()));
            env.schemes.push(UnsafeCell::new(Serial::new(0x3F8, 0x4)));

            pci_init(env);

            env.schemes.push(UnsafeCell::new(DebugScheme::new()));
            env.schemes.push(UnsafeCell::new(box ContextScheme));
            env.schemes.push(UnsafeCell::new(box MemoryScheme));
            // session.items.push(box RandomScheme);
            // session.items.push(box TimeScheme);

            env.schemes.push(UnsafeCell::new(box EthernetScheme));
            env.schemes.push(UnsafeCell::new(box ArpScheme));
            env.schemes.push(UnsafeCell::new(box IcmpScheme));
            env.schemes.push(UnsafeCell::new(box IpScheme { arp: Vec::new() }));
            // session.items.push(box DisplayScheme);

            Context::spawn("kpoll".to_string(),
            box move || {
                poll_loop();
            });

            Context::spawn("kevent".to_string(),
            box move || {
                event_loop();
            });

            Context::spawn("karp".to_string(),
            box move || {
                ArpScheme::reply_loop();
            });

            Context::spawn("kicmp".to_string(),
            box move || {
                IcmpScheme::reply_loop();
            });

            context_enabled = true;

            if let Ok(mut resource) = Url::from_str("file:/schemes/").open() {
                let mut vec: Vec<u8> = Vec::new();
                resource.read_to_end(&mut vec);

                for folder in String::from_utf8_unchecked(vec).lines() {
                    if folder.ends_with('/') {
                        let scheme_item = SchemeItem::from_url(&Url::from_string("file:/schemes/"
                                                                                .to_string() +
                                                                                &folder));

                        env.schemes.push(UnsafeCell::new(scheme_item));
                    }
                }
            }

            Context::spawn("kinit".to_string(),
            box move || {
                let wd_c = "file:/\0";
                do_sys_chdir(wd_c.as_ptr());

                let stdio_c = "debug:\0";
                do_sys_open(stdio_c.as_ptr(), 0);
                do_sys_open(stdio_c.as_ptr(), 0);
                do_sys_open(stdio_c.as_ptr(), 0);

                let path_string = "file:/apps/login/main.bin";
                let path = Url::from_str(path_string);

                debug!("INIT: Executing {}\n", path_string);
                execute(path, Vec::new());
                debug!("INIT: Failed to execute\n");

                loop {
                    context_switch(false);
                }
            });
        },
        None => unreachable!(),
    }
}

#[cold]
#[inline(never)]
#[no_mangle]
/// Take regs for kernel calls and exceptions
pub extern "cdecl" fn kernel(interrupt: usize, mut regs: &mut Regs) {
    macro_rules! exception_inner {
        ($name:expr) => ({
            {
                let contexts = ::env().contexts.lock();
                if let Some(context) = contexts.get(Context::current_i()) {
                    debugln!("PID {}: {}", context.pid, context.name);
                }
            }

            debugln!("  INT {:X}: {}", interrupt, $name);
            debugln!("    CS:  {:08X}    IP:  {:08X}    FLG: {:08X}", regs.cs, regs.ip, regs.flags);
            debugln!("    SS:  {:08X}    SP:  {:08X}    BP:  {:08X}", regs.ss, regs.sp, regs.bp);
            debugln!("    AX:  {:08X}    BX:  {:08X}    CX:  {:08X}    DX:  {:08X}", regs.ax, regs.bx, regs.cx, regs.dx);
            debugln!("    DI:  {:08X}    SI:  {:08X}", regs.di, regs.di);

            let cr0: usize;
            let cr2: usize;
            let cr3: usize;
            let cr4: usize;
            unsafe {
                asm!("mov $0, cr0" : "=r"(cr0) : : : "intel", "volatile");
                asm!("mov $0, cr2" : "=r"(cr2) : : : "intel", "volatile");
                asm!("mov $0, cr3" : "=r"(cr3) : : : "intel", "volatile");
                asm!("mov $0, cr4" : "=r"(cr4) : : : "intel", "volatile");
            }
            debugln!("    CR0: {:08X}    CR2: {:08X}    CR3: {:08X}    CR4: {:08X}", cr0, cr2, cr3, cr4);

            let sp = regs.sp as *const u32;
            for y in 0..8 {
                debug!("    {:02X}:", y * 8);
                for x in 0..8 {
                    debug!("  {:08X}", unsafe { ptr::read(sp.offset(-(x + y * 8))) });
                }
                debug!("\n");
            }
        })
    };

    macro_rules! exception {
        ($name:expr) => ({
            exception_inner!($name);

            loop {
                unsafe { do_sys_exit(usize::MAX) };
            }
        })
    };

    macro_rules! exception_error {
        ($name:expr) => ({
            let error = regs.ip;
            regs.ip = regs.cs;
            regs.cs = regs.flags;
            regs.flags = regs.sp;
            regs.sp = regs.ss;
            regs.ss = 0;
            //regs.ss = regs.error;

            exception_inner!($name);
            debugln!("    ERR: {:08X}", error);

            loop {
                unsafe { do_sys_exit(usize::MAX) };
            }
        })
    };

    if interrupt >= 0x20 && interrupt < 0x30 {
        if interrupt >= 0x28 {
            unsafe { Pio8::new(0xA0).write(0x20) };
        }

        unsafe { Pio8::new(0x20).write(0x20) };
    }

    match interrupt {
        0x20 => {
            unsafe {
                match ENV_PTR {
                    Some(ref mut env) => {
                        env.clock_realtime = env.clock_realtime + PIT_DURATION;
                        env.clock_monotonic = env.clock_monotonic + PIT_DURATION;

                        let switch = {
                            let mut contexts = ::env().contexts.lock();
                            if let Some(mut context) = contexts.get_mut(Context::current_i()) {
                                context.slices -= 1;
                                context.slice_total += 1;
                                context.slices == 0
                            } else {
                                false
                            }
                        };

                        if switch {
                            context_switch(true);
                        }
                    },
                    None => unreachable!(),
                }
            }
        }
        0x21 => env().on_irq(0x1), // keyboard
        0x23 => env().on_irq(0x3), // serial 2 and 4
        0x24 => env().on_irq(0x4), // serial 1 and 3
        0x25 => env().on_irq(0x5), //parallel 2
        0x26 => env().on_irq(0x6), //floppy
        0x27 => env().on_irq(0x7), //parallel 1 or spurious
        0x28 => env().on_irq(0x8), //RTC
        0x29 => env().on_irq(0x9), //pci
        0x2A => env().on_irq(0xA), //pci
        0x2B => env().on_irq(0xB), //pci
        0x2C => env().on_irq(0xC), //mouse
        0x2D => env().on_irq(0xD), //coprocessor
        0x2E => env().on_irq(0xE), //disk
        0x2F => env().on_irq(0xF), //disk
        0x80 => if !unsafe { syscall_handle(regs) } {
            exception!("Unknown Syscall");
        },
        0xFF => {
            unsafe {
                init(regs.ax, regs.bx);
                idle_loop();
            }
        },
        0x0 => exception!("Divide by zero exception"),
        0x1 => exception!("Debug exception"),
        0x2 => exception!("Non-maskable interrupt"),
        0x3 => exception!("Breakpoint exception"),
        0x4 => exception!("Overflow exception"),
        0x5 => exception!("Bound range exceeded exception"),
        0x6 => exception!("Invalid opcode exception"),
        0x7 => exception!("Device not available exception"),
        0x8 => exception_error!("Double fault"),
        0xA => exception_error!("Invalid TSS exception"),
        0xB => exception_error!("Segment not present exception"),
        0xC => exception_error!("Stack-segment fault"),
        0xD => exception_error!("General protection fault"),
        0xE => exception_error!("Page fault"),
        0x10 => exception!("x87 floating-point exception"),
        0x11 => exception_error!("Alignment check exception"),
        0x12 => exception!("Machine check exception"),
        0x13 => exception!("SIMD floating-point exception"),
        0x14 => exception!("Virtualization exception"),
        0x1E => exception_error!("Security exception"),
        _ => exception!("Unknown Interrupt"),
    }
}
<commit_msg>Add stack dump to output<commit_after>#![crate_type="staticlib"]
#![feature(alloc)]
#![feature(allocator)]
#![feature(arc_counts)]
#![feature(asm)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(core_str_ext)]
#![feature(core_slice_ext)]
#![feature(fnbox)]
#![feature(fundamental)]
#![feature(lang_items)]
#![feature(no_std)]
#![feature(unboxed_closures)]
#![feature(unsafe_no_drop_flag)]
#![feature(unwind_attributes)]
#![feature(vec_push_all)]
#![no_std]

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate collections;

use alloc::boxed::Box;

use collections::string::{String, ToString};
use collections::vec::Vec;

use core::cell::UnsafeCell;
use core::{ptr, mem, usize};
use core::slice::SliceExt;

use common::debug;
use common::event::{self, EVENT_KEY, EventOption};
use common::memory;
use common::paging::Page;
use common::time::Duration;

use drivers::pci::*;
use drivers::pio::*;
use drivers::ps2::*;
use drivers::rtc::*;
use drivers::serial::*;

use env::Environment;

pub use externs::*;

use graphics::display;

use programs::executor::execute;
use programs::scheme::*;

use scheduler::{Context, Regs, TSS};
use scheduler::context::{context_enabled, context_switch, context_i, context_pid};

use schemes::Url;
use schemes::arp::*;
use schemes::context::*;
use schemes::debug::*;
use schemes::ethernet::*;
use schemes::icmp::*;
use schemes::ip::*;
use schemes::memory::*;
// use schemes::display::*;

use syscall::handle::*;

/// Common std-like functionality
#[macro_use]
pub mod common;
/// Allocation
pub mod alloc_system;
/// Audio
pub mod audio;
/// Various drivers
/// TODO: Move out of kernel space (like other microkernels)
pub mod drivers;
/// Environment
pub mod env;
/// Externs
pub mod externs;
/// Various graphical methods
pub mod graphics;
/// Network
pub mod network;
/// Panic
pub mod panic;
/// Programs
pub mod programs;
/// Schemes
pub mod schemes;
/// Scheduling
pub mod scheduler;
/// Sync primatives
pub mod sync;
/// System calls
pub mod syscall;
/// USB input/output
pub mod usb;

pub static mut TSS_PTR: Option<&'static mut TSS> = None;
pub static mut ENV_PTR: Option<&'static mut Environment> = None;

pub fn env() -> &'static Environment {
    unsafe {
        match ENV_PTR {
            Some(&mut ref p) => p,
            None => unreachable!(),
        }
    }
}

/// Pit duration
static PIT_DURATION: Duration = Duration {
    secs: 0,
    nanos: 2250286,
};

/// Idle loop (active while idle)
unsafe fn idle_loop() -> ! {
    loop {
        asm!("cli" : : : : "intel", "volatile");

        let mut halt = true;

        {
            let contexts = ::env().contexts.lock();
            for i in 1..contexts.len() {
                if let Some(context) = contexts.get(i) {
                    if context.interrupted {
                        halt = false;
                        break;
                    }
                }
            }
        }

        if halt {
            asm!("sti" : : : : "intel", "volatile");
            asm!("hlt" : : : : "intel", "volatile");
        } else {
            asm!("sti" : : : : "intel", "volatile");
        }

        context_switch(false);
    }
}

/// Event poll loop
fn poll_loop() -> ! {
    loop {
        env().on_poll();

        unsafe { context_switch(false) };
    }
}

/// Event loop
fn event_loop() -> ! {
    let mut cmd = String::new();
    loop {
        loop {
            let mut console = env().console.lock();
            match env().events.lock().pop_front() {
                Some(event) => {
                    if console.draw {
                        match event.to_option() {
                            EventOption::Key(key_event) => {
                                if key_event.pressed {
                                    match key_event.scancode {
                                        event::K_F2 => {
                                            console.draw = false;
                                        }
                                        event::K_BKSP => if !cmd.is_empty() {
                                            console.write(&[8]);
                                            cmd.pop();
                                        },
                                        _ => match key_event.character {
                                            '\0' => (),
                                            '\n' => {
                                                console.command = Some(cmd.clone());

                                                cmd.clear();
                                                console.write(&[10]);
                                            }
                                            _ => {
                                                cmd.push(key_event.character);
                                                console.write(&[key_event.character as u8]);
                                            }
                                        },
                                    }
                                }
                            }
                            _ => (),
                        }
                    } else {
                        if event.code == EVENT_KEY && event.b as u8 == event::K_F1 && event.c > 0 {
                            console.draw = true;
                            console.redraw = true;
                        } else {
                            // TODO: Magical orbital hack
                            unsafe {
                                for scheme in env().schemes.iter() {
                                    if (*scheme.get()).scheme() == "orbital" {
                                        (*scheme.get()).event(&event);
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
                None => break,
            }
        }

        {
            let mut console = env().console.lock();
            if console.draw && console.redraw {
                console.redraw = false;
                console.display.flip();
            }
        }

        unsafe { context_switch(false) };
    }
}

/// Initialize kernel
unsafe fn init(font_data: usize, tss_data: usize) {
    Page::init();
    memory::cluster_init();
    // Unmap first page to catch null pointer errors (after reading memory map)
    Page::new(0).unmap();

    sync::intex::intex_count = 0;

    display::fonts = font_data;
    TSS_PTR = Some(&mut *(tss_data as *mut TSS));
    ENV_PTR = Some(&mut *Box::into_raw(Environment::new()));

    context_pid = 1;
    context_i = 0;
    context_enabled = false;

    match ENV_PTR {
        Some(ref mut env) => {
            env.contexts.lock().push(Context::root());
            env.console.lock().draw = true;

            debug!("Redox ");
            debug::dd(mem::size_of::<usize>() * 8);
            debug!(" bits");
            debug::dl();

            env.clock_realtime = Rtc::new().time();

            env.schemes.push(UnsafeCell::new(Ps2::new()));
            env.schemes.push(UnsafeCell::new(Serial::new(0x3F8, 0x4)));

            pci_init(env);

            env.schemes.push(UnsafeCell::new(DebugScheme::new()));
            env.schemes.push(UnsafeCell::new(box ContextScheme));
            env.schemes.push(UnsafeCell::new(box MemoryScheme));
            // session.items.push(box RandomScheme);
            // session.items.push(box TimeScheme);

            env.schemes.push(UnsafeCell::new(box EthernetScheme));
            env.schemes.push(UnsafeCell::new(box ArpScheme));
            env.schemes.push(UnsafeCell::new(box IcmpScheme));
            env.schemes.push(UnsafeCell::new(box IpScheme { arp: Vec::new() }));
            // session.items.push(box DisplayScheme);

            Context::spawn("kpoll".to_string(),
            box move || {
                poll_loop();
            });

            Context::spawn("kevent".to_string(),
            box move || {
                event_loop();
            });

            Context::spawn("karp".to_string(),
            box move || {
                ArpScheme::reply_loop();
            });

            Context::spawn("kicmp".to_string(),
            box move || {
                IcmpScheme::reply_loop();
            });

            context_enabled = true;

            if let Ok(mut resource) = Url::from_str("file:/schemes/").open() {
                let mut vec: Vec<u8> = Vec::new();
                resource.read_to_end(&mut vec);

                for folder in String::from_utf8_unchecked(vec).lines() {
                    if folder.ends_with('/') {
                        let scheme_item = SchemeItem::from_url(&Url::from_string("file:/schemes/"
                                                                                .to_string() +
                                                                                &folder));

                        env.schemes.push(UnsafeCell::new(scheme_item));
                    }
                }
            }

            Context::spawn("kinit".to_string(),
            box move || {
                let wd_c = "file:/\0";
                do_sys_chdir(wd_c.as_ptr());

                let stdio_c = "debug:\0";
                do_sys_open(stdio_c.as_ptr(), 0);
                do_sys_open(stdio_c.as_ptr(), 0);
                do_sys_open(stdio_c.as_ptr(), 0);

                let path_string = "file:/apps/login/main.bin";
                let path = Url::from_str(path_string);

                debug!("INIT: Executing {}\n", path_string);
                execute(path, Vec::new());
                debug!("INIT: Failed to execute\n");

                loop {
                    context_switch(false);
                }
            });
        },
        None => unreachable!(),
    }
}

#[cold]
#[inline(never)]
#[no_mangle]
/// Take regs for kernel calls and exceptions
pub extern "cdecl" fn kernel(interrupt: usize, mut regs: &mut Regs) {
    macro_rules! exception_inner {
        ($name:expr) => ({
            {
                let contexts = ::env().contexts.lock();
                if let Some(context) = contexts.get(Context::current_i()) {
                    debugln!("PID {}: {}", context.pid, context.name);
                }
            }

            debugln!("  INT {:X}: {}", interrupt, $name);
            debugln!("    CS:  {:08X}    IP:  {:08X}    FLG: {:08X}", regs.cs, regs.ip, regs.flags);
            debugln!("    SS:  {:08X}    SP:  {:08X}    BP:  {:08X}", regs.ss, regs.sp, regs.bp);
            debugln!("    AX:  {:08X}    BX:  {:08X}    CX:  {:08X}    DX:  {:08X}", regs.ax, regs.bx, regs.cx, regs.dx);
            debugln!("    DI:  {:08X}    SI:  {:08X}", regs.di, regs.di);

            let cr0: usize;
            let cr2: usize;
            let cr3: usize;
            let cr4: usize;
            unsafe {
                asm!("mov $0, cr0" : "=r"(cr0) : : : "intel", "volatile");
                asm!("mov $0, cr2" : "=r"(cr2) : : : "intel", "volatile");
                asm!("mov $0, cr3" : "=r"(cr3) : : : "intel", "volatile");
                asm!("mov $0, cr4" : "=r"(cr4) : : : "intel", "volatile");
            }
            debugln!("    CR0: {:08X}    CR2: {:08X}    CR3: {:08X}    CR4: {:08X}", cr0, cr2, cr3, cr4);

            let sp = regs.sp as *const u32;
            for y in -3..4 {
                debug!("    {:>3}:", y * 8 * 4);
                for x in 0..8 {
                    debug!(" {:08X}", unsafe { ptr::read(sp.offset(-(x + y * 8))) });
                }
                debug!("\n");
            }
        })
    };

    macro_rules! exception {
        ($name:expr) => ({
            exception_inner!($name);

            loop {
                unsafe { do_sys_exit(usize::MAX) };
            }
        })
    };

    macro_rules! exception_error {
        ($name:expr) => ({
            let error = regs.ip;
            regs.ip = regs.cs;
            regs.cs = regs.flags;
            regs.flags = regs.sp;
            regs.sp = regs.ss;
            regs.ss = 0;
            //regs.ss = regs.error;

            exception_inner!($name);
            debugln!("    ERR: {:08X}", error);

            loop {
                unsafe { do_sys_exit(usize::MAX) };
            }
        })
    };

    if interrupt >= 0x20 && interrupt < 0x30 {
        if interrupt >= 0x28 {
            unsafe { Pio8::new(0xA0).write(0x20) };
        }

        unsafe { Pio8::new(0x20).write(0x20) };
    }

    match interrupt {
        0x20 => {
            unsafe {
                match ENV_PTR {
                    Some(ref mut env) => {
                        env.clock_realtime = env.clock_realtime + PIT_DURATION;
                        env.clock_monotonic = env.clock_monotonic + PIT_DURATION;

                        let switch = {
                            let mut contexts = ::env().contexts.lock();
                            if let Some(mut context) = contexts.get_mut(Context::current_i()) {
                                context.slices -= 1;
                                context.slice_total += 1;
                                context.slices == 0
                            } else {
                                false
                            }
                        };

                        if switch {
                            context_switch(true);
                        }
                    },
                    None => unreachable!(),
                }
            }
        }
        0x21 => env().on_irq(0x1), // keyboard
        0x23 => env().on_irq(0x3), // serial 2 and 4
        0x24 => env().on_irq(0x4), // serial 1 and 3
        0x25 => env().on_irq(0x5), //parallel 2
        0x26 => env().on_irq(0x6), //floppy
        0x27 => env().on_irq(0x7), //parallel 1 or spurious
        0x28 => env().on_irq(0x8), //RTC
        0x29 => env().on_irq(0x9), //pci
        0x2A => env().on_irq(0xA), //pci
        0x2B => env().on_irq(0xB), //pci
        0x2C => env().on_irq(0xC), //mouse
        0x2D => env().on_irq(0xD), //coprocessor
        0x2E => env().on_irq(0xE), //disk
        0x2F => env().on_irq(0xF), //disk
        0x80 => if !unsafe { syscall_handle(regs) } {
            exception!("Unknown Syscall");
        },
        0xFF => {
            unsafe {
                init(regs.ax, regs.bx);
                idle_loop();
            }
        },
        0x0 => exception!("Divide by zero exception"),
        0x1 => exception!("Debug exception"),
        0x2 => exception!("Non-maskable interrupt"),
        0x3 => exception!("Breakpoint exception"),
        0x4 => exception!("Overflow exception"),
        0x5 => exception!("Bound range exceeded exception"),
        0x6 => exception!("Invalid opcode exception"),
        0x7 => exception!("Device not available exception"),
        0x8 => exception_error!("Double fault"),
        0xA => exception_error!("Invalid TSS exception"),
        0xB => exception_error!("Segment not present exception"),
        0xC => exception_error!("Stack-segment fault"),
        0xD => exception_error!("General protection fault"),
        0xE => exception_error!("Page fault"),
        0x10 => exception!("x87 floating-point exception"),
        0x11 => exception_error!("Alignment check exception"),
        0x12 => exception!("Machine check exception"),
        0x13 => exception!("SIMD floating-point exception"),
        0x14 => exception!("Virtualization exception"),
        0x1E => exception_error!("Security exception"),
        _ => exception!("Unknown Interrupt"),
    }
}
<|endoftext|>


<commit_before>use redox::*;

pub struct Editor {
    url: String,
    string: String,
    offset: usize,
    scroll: Point
}

impl Editor {
    #[inline(never)]
    pub fn new() -> Editor {
        Editor {
            url: String::new(),
            string: String::new(),
            offset: 0,
            scroll: Point::new(0, 0)
        }
    }

    fn reload(&mut self, window: &mut Window){
        window.title = "Editor (".to_string() + &self.url + ")";
        self.offset = 0;
        self.scroll = Point::new(0, 0);

        let mut resource = File::open(&self.url);

        let mut vec: Vec<u8> = Vec::new();
        resource.read_to_end(&mut vec);

        self.string = String::from_utf8(&vec);
    }

    fn save(&mut self, window: &mut Window){
        window.title = "Editor (".to_string() + &self.url + ") Saved";

        let mut resource = File::open(&self.url);
        resource.seek(Seek::Start(0));
        resource.write(&self.string.to_utf8().as_slice());
    }

    fn draw_content(&mut self, window: &mut Window){
        let mut redraw = false;

        {
            let content = &window.content;

            content.set(Color::alpha(0, 0, 0, 196));

            let scroll = self.scroll;

            let mut offset = 0;

            let mut col = -scroll.x;
            let cols = content.width as isize / 8;

            let mut row = -scroll.y;
            let rows = content.height as isize / 16;

            for c in self.string.chars() {
                if offset == self.offset{
                    if col >= 0 && col < cols && row >= 0 && row < rows{
                        content.char(Point::new(8 * col, 16 * row), '_', Color::new(128, 128, 128));
                    }else{
                        if col < 0 { //Too far to the left
                            self.scroll.x += col;
                        }else if col >= cols{ //Too far to the right
                            self.scroll.x += cols - col + 1;
                        }
                        if row < 0 { //Too far up
                            self.scroll.y += row;
                        }else if row >= rows{ //Too far down
                            self.scroll.y += rows - row + 1;
                        }

                        redraw = true;
                    }
                }

                if c == '\n' {
                    col = -scroll.x;
                    row += 1;
                }else if c == '\t' {
                    col += 8 - col % 8;
                }else{
                    if col >= 0 && col < cols && row >= 0 && row < rows{
                        content.char(Point::new(8 * col, 16 * row), c, Color::new(255, 255, 255));
                    }
                    col += 1;
                }

                offset += 1;
            }

            if offset == self.offset {
                if col >= 0 && col < cols && row >= 0 && row < rows{
                    content.char(Point::new(8 * col, 16 * row), '_', Color::new(128, 128, 128));
                }else{
                    if col < 0 { //Too far to the left
                        self.scroll.x += col;
                    }else if col >= cols{ //Too far to the right
                        self.scroll.x += cols - col + 1;
                    }
                    if row < 0 { //Too far up
                        self.scroll.y += row;
                    }else if row >= rows{ //Too far down
                        self.scroll.y += rows - row + 1;
                    }

                    redraw = true;
                }
            }

            content.flip();

            RedrawEvent {
                redraw: REDRAW_ALL
            }.to_event().trigger();
        }

        if redraw {
            self.draw_content(window);
        }
    }

    fn main(&mut self, url: String){
        let mut window = Window::new(Point::new((rand() % 400 + 50) as isize, (rand() % 300 + 50) as isize), Size::new(576, 400), "Editor (Loading)".to_string());

        self.url = url;

        self.reload(&mut window);
        self.draw_content(&mut window);

        loop {
            match window.poll() {
                EventOption::Key(key_event) => {
                    if key_event.pressed {
                        match key_event.scancode {
                            K_ESC => break,
                            K_BKSP => if self.offset > 0 {
                                window.title = "Editor (".to_string() + &self.url + ") Changed";
                                self.string = self.string.substr(0, self.offset - 1) + self.string.substr(self.offset, self.string.len() - self.offset);
                                self.offset -= 1;
                            },
                            K_DEL => if self.offset < self.string.len() {
                                window.title = "Editor (".to_string() + &self.url + ") Changed";
                                self.string = self.string.substr(0, self.offset) + self.string.substr(self.offset + 1, self.string.len() - self.offset - 1);
                            },
                            K_F5 => self.reload(&mut window),
                            K_F6 => self.save(&mut window),
                            K_HOME => self.offset = 0,
                            K_UP => {
                                let mut new_offset = 0;
                                for i in 2..self.offset {
                                    match self.string[self.offset - i] {
                                        '\0' => break,
                                        '\n' => {
                                            new_offset = self.offset - i + 1;
                                            break;
                                        },
                                        _ => ()
                                    }
                                }
                                self.offset = new_offset;
                            },
                            K_LEFT => if self.offset > 0 {
                                self.offset -= 1;
                            },
                            K_RIGHT => if self.offset < self.string.len() {
                                self.offset += 1;
                            },
                            K_END => self.offset = self.string.len(),
                            K_DOWN => {
                                let mut new_offset = self.string.len();
                                for i in self.offset..self.string.len() {
                                    match self.string[i] {
                                        '\0' => break,
                                        '\n' => {
                                            new_offset = i + 1;
                                            break;
                                        },
                                        _ => ()
                                    }
                                }
                                self.offset = new_offset;
                            },
                            _ => match key_event.character {
                                '\0' => (),
                                _ => {
                                    window.title = "Editor (".to_string() + &self.url + ") Changed";
                                    self.string = self.string.substr(0, self.offset) + key_event.character + self.string.substr(self.offset, self.string.len() - self.offset);
                                    self.offset += 1;
                                }
                            }
                        }

                        self.draw_content(&mut window);
                    }
                },
                EventOption::None => sys_yield(),
                _ => ()
            }
        }
    }
}

pub fn main(){
    match args().get(1) {
        Option::Some(arg) => Editor::new().main(arg.clone()),
        Option::None => Editor::new().main("none://".to_string())
    }
}
<commit_msg>FileSystem is now writable... it just writes corrupted data<commit_after>use redox::*;

pub struct Editor {
    url: String,
    string: String,
    offset: usize,
    scroll: Point
}

impl Editor {
    #[inline(never)]
    pub fn new() -> Editor {
        Editor {
            url: String::new(),
            string: String::new(),
            offset: 0,
            scroll: Point::new(0, 0)
        }
    }

    fn reload(&mut self, window: &mut Window){
        window.title = "Editor (".to_string() + &self.url + ")";
        self.offset = 0;
        self.scroll = Point::new(0, 0);

        let mut resource = File::open(&self.url);

        let mut vec: Vec<u8> = Vec::new();
        resource.read_to_end(&mut vec);

        self.string = String::from_utf8(&vec);
    }

    fn save(&mut self, window: &mut Window){
        window.title = "Editor (".to_string() + &self.url + ") Saved";

        let mut resource = File::open(&self.url);
        resource.seek(Seek::Start(0));
        resource.write(&self.string.to_utf8().as_slice());
        resource.flush();
    }

    fn draw_content(&mut self, window: &mut Window){
        let mut redraw = false;

        {
            let content = &window.content;

            content.set(Color::alpha(0, 0, 0, 196));

            let scroll = self.scroll;

            let mut offset = 0;

            let mut col = -scroll.x;
            let cols = content.width as isize / 8;

            let mut row = -scroll.y;
            let rows = content.height as isize / 16;

            for c in self.string.chars() {
                if offset == self.offset{
                    if col >= 0 && col < cols && row >= 0 && row < rows{
                        content.char(Point::new(8 * col, 16 * row), '_', Color::new(128, 128, 128));
                    }else{
                        if col < 0 { //Too far to the left
                            self.scroll.x += col;
                        }else if col >= cols{ //Too far to the right
                            self.scroll.x += cols - col + 1;
                        }
                        if row < 0 { //Too far up
                            self.scroll.y += row;
                        }else if row >= rows{ //Too far down
                            self.scroll.y += rows - row + 1;
                        }

                        redraw = true;
                    }
                }

                if c == '\n' {
                    col = -scroll.x;
                    row += 1;
                }else if c == '\t' {
                    col += 8 - col % 8;
                }else{
                    if col >= 0 && col < cols && row >= 0 && row < rows{
                        content.char(Point::new(8 * col, 16 * row), c, Color::new(255, 255, 255));
                    }
                    col += 1;
                }

                offset += 1;
            }

            if offset == self.offset {
                if col >= 0 && col < cols && row >= 0 && row < rows{
                    content.char(Point::new(8 * col, 16 * row), '_', Color::new(128, 128, 128));
                }else{
                    if col < 0 { //Too far to the left
                        self.scroll.x += col;
                    }else if col >= cols{ //Too far to the right
                        self.scroll.x += cols - col + 1;
                    }
                    if row < 0 { //Too far up
                        self.scroll.y += row;
                    }else if row >= rows{ //Too far down
                        self.scroll.y += rows - row + 1;
                    }

                    redraw = true;
                }
            }

            content.flip();

            RedrawEvent {
                redraw: REDRAW_ALL
            }.to_event().trigger();
        }

        if redraw {
            self.draw_content(window);
        }
    }

    fn main(&mut self, url: String){
        let mut window = Window::new(Point::new((rand() % 400 + 50) as isize, (rand() % 300 + 50) as isize), Size::new(576, 400), "Editor (Loading)".to_string());

        self.url = url;

        self.reload(&mut window);
        self.draw_content(&mut window);

        loop {
            match window.poll() {
                EventOption::Key(key_event) => {
                    if key_event.pressed {
                        match key_event.scancode {
                            K_ESC => break,
                            K_BKSP => if self.offset > 0 {
                                window.title = "Editor (".to_string() + &self.url + ") Changed";
                                self.string = self.string.substr(0, self.offset - 1) + self.string.substr(self.offset, self.string.len() - self.offset);
                                self.offset -= 1;
                            },
                            K_DEL => if self.offset < self.string.len() {
                                window.title = "Editor (".to_string() + &self.url + ") Changed";
                                self.string = self.string.substr(0, self.offset) + self.string.substr(self.offset + 1, self.string.len() - self.offset - 1);
                            },
                            K_F5 => self.reload(&mut window),
                            K_F6 => self.save(&mut window),
                            K_HOME => self.offset = 0,
                            K_UP => {
                                let mut new_offset = 0;
                                for i in 2..self.offset {
                                    match self.string[self.offset - i] {
                                        '\0' => break,
                                        '\n' => {
                                            new_offset = self.offset - i + 1;
                                            break;
                                        },
                                        _ => ()
                                    }
                                }
                                self.offset = new_offset;
                            },
                            K_LEFT => if self.offset > 0 {
                                self.offset -= 1;
                            },
                            K_RIGHT => if self.offset < self.string.len() {
                                self.offset += 1;
                            },
                            K_END => self.offset = self.string.len(),
                            K_DOWN => {
                                let mut new_offset = self.string.len();
                                for i in self.offset..self.string.len() {
                                    match self.string[i] {
                                        '\0' => break,
                                        '\n' => {
                                            new_offset = i + 1;
                                            break;
                                        },
                                        _ => ()
                                    }
                                }
                                self.offset = new_offset;
                            },
                            _ => match key_event.character {
                                '\0' => (),
                                _ => {
                                    window.title = "Editor (".to_string() + &self.url + ") Changed";
                                    self.string = self.string.substr(0, self.offset) + key_event.character + self.string.substr(self.offset, self.string.len() - self.offset);
                                    self.offset += 1;
                                }
                            }
                        }

                        self.draw_content(&mut window);
                    }
                },
                EventOption::None => sys_yield(),
                _ => ()
            }
        }
    }
}

pub fn main(){
    match args().get(1) {
        Option::Some(arg) => Editor::new().main(arg.clone()),
        Option::None => Editor::new().main("none://".to_string())
    }
}
<|endoftext|>


<commit_before><commit_msg>Include version on pg-to-tar startup.<commit_after><|endoftext|>


<commit_before><commit_msg>Refactor libimagtimetrack to fit new store iterator interface<commit_after><|endoftext|>