<commit_before>#![cfg_attr(test, feature(test))]
#![allow(clippy::too_many_arguments)]
#![allow(clippy::cognitive_complexity)]
#![feature(track_caller, or_patterns)]

mod config;
mod editor;
mod exit_dialogue;
mod input_area;
mod line_split;
mod messaging;
#[doc(hidden)]
// FIXME: This is "pub" to be able to use in an example
pub mod msg_area;
mod notifier;
mod statusline;
mod tab;
mod termbox;
mod trie;
mod tui;
mod utils;
mod widget;

#[cfg(test)]
mod tests;

pub use crate::tab::TabStyle;
use crate::tui::TUIRet;
pub use libtiny_ui::*;

use futures::select;
use futures::stream::StreamExt;
use std::cell::RefCell;
use std::path::PathBuf;
use std::rc::{Rc, Weak};
use term_input::Input;
use time::Tm;
use tokio::signal::unix::{signal, SignalKind};
use tokio::sync::mpsc;
use tokio::task::spawn_local;

#[macro_use]
extern crate log;

#[derive(Clone)]
pub struct TUI {
    inner: Weak<RefCell<tui::TUI>>,
}

impl TUI {
    pub fn run(config_path: PathBuf) -> (TUI, mpsc::Receiver<Event>) {
        let tui = Rc::new(RefCell::new(tui::TUI::new(config_path)));
        let inner = Rc::downgrade(&tui);

        let (snd_ev, rcv_ev) = mpsc::channel(10);

        // For SIGWINCH handler
        let (snd_abort, rcv_abort) = mpsc::channel::<()>(1);

        // Spawn SIGWINCH handler
        spawn_local(sigwinch_handler(inner.clone(), rcv_abort));

        // Spawn input handler task
        spawn_local(input_handler(tui, snd_ev, snd_abort));

        (TUI { inner }, rcv_ev)
    }
}

async fn sigwinch_handler(tui: Weak<RefCell<tui::TUI>>, rcv_abort: mpsc::Receiver<()>) {
    let stream = match signal(SignalKind::window_change()) {
        Err(err) => {
            debug!("Can't install SIGWINCH handler: {:?}", err);
            return;
        }
        Ok(stream) => stream,
    };

    let mut stream_fused = stream.fuse();
    let mut rcv_abort_fused = rcv_abort.fuse();

    loop {
        select! {
            _ = stream_fused.next() => {
                match tui.upgrade() {
                    None => {
                        return;
                    }
                    Some(tui) => {
                        tui.borrow_mut().resize();
                    }
                }
            },
            _ = rcv_abort_fused.next() => {
                return;
            }
        }
    }
}

async fn input_handler(
    tui: Rc<RefCell<tui::TUI>>,
    mut snd_ev: mpsc::Sender<Event>,
    mut snd_abort: mpsc::Sender<()>,
) {
    let mut input = Input::new();

    // See module documentation of `editor` for how editor stuff works
    let mut rcv_editor_ret: Option<editor::ResultReceiver> = None;

    loop {
        if let Some(editor_ret) = rcv_editor_ret.take() {
            // $EDITOR running, don't read stdin, wait for $EDITOR to finish
            match editor_ret.await {
                Err(recv_error) => {
                    debug!("RecvError while waiting editor response: {:?}", recv_error);
                }
                Ok(editor_ret) => {
                    if let Some((lines, from)) = tui.borrow_mut().handle_editor_result(editor_ret) {
                        debug!("editor ret: {:?}", lines);
                        snd_ev
                            .try_send(Event::Lines {
                                lines,
                                source: from,
                            })
                            .unwrap();
                    }
                }
            }

            tui.borrow_mut().activate();
            tui.borrow_mut().draw();
        }

        match input.next().await {
            None => {
                break;
            }
            Some(Err(io_err)) => {
                debug!("term_input error: {:?}", io_err);
                break;
            }
            Some(Ok(ev)) => {
                let tui_ret = tui.borrow_mut().handle_input_event(ev, &mut rcv_editor_ret);
                match tui_ret {
                    TUIRet::Abort => {
                        snd_ev.try_send(Event::Abort).unwrap();
                        let _ = snd_abort.try_send(());
                        return;
                    }
                    TUIRet::KeyHandled | TUIRet::KeyIgnored(_) | TUIRet::EventIgnored(_) => {}
                    TUIRet::Input { msg, from } => {
                        if msg[0] == '/' {
                            // Handle TUI commands, send others to downstream
                            let cmd: String = (&msg[1..]).iter().collect();
                            let handled = tui.borrow_mut().try_handle_cmd(&cmd, &from);
                            if !handled {
                                snd_ev.try_send(Event::Cmd { cmd, source: from }).unwrap();
                            }
                        } else {
                            snd_ev
                                .try_send(Event::Msg {
                                    msg: msg.into_iter().collect(),
                                    source: from,
                                })
                                .unwrap();
                        }
                    }
                }
            }
        }

        tui.borrow_mut().draw();
    }
}

macro_rules! delegate {
    ( $name:ident ( $( $x:ident: $t:ty, )* ) ) => {
        fn $name(&self, $($x: $t,)*) {
            if let Some(inner) = self.inner.upgrade() {
                inner.borrow_mut().$name( $( $x, )* );
            }
        }
    }
}

impl UI for TUI {
    delegate!(draw());
    delegate!(new_server_tab(serv_name: &str, alias: Option<String>,));
    delegate!(close_server_tab(serv_name: &str,));
    delegate!(new_chan_tab(serv_name: &str, chan: &str,));
    delegate!(close_chan_tab(serv_name: &str, chan: &str,));
    delegate!(close_user_tab(serv_name: &str, nick: &str,));
    delegate!(add_client_msg(msg: &str, target: &MsgTarget,));
    delegate!(add_msg(msg: &str, ts: Tm, target: &MsgTarget,));
    delegate!(add_err_msg(msg: &str, ts: Tm, target: &MsgTarget,));
    delegate!(add_client_err_msg(msg: &str, target: &MsgTarget,));
    delegate!(clear_nicks(serv_name: &str,));
    delegate!(set_nick(serv_name: &str, new_nick: &str,));
    delegate!(add_privmsg(
        sender: &str,
        msg: &str,
        ts: Tm,
        target: &MsgTarget,
        highlight: bool,
        is_action: bool,
    ));
    delegate!(add_nick(nick: &str, ts: Option<Tm>, target: &MsgTarget,));
    delegate!(remove_nick(nick: &str, ts: Option<Tm>, target: &MsgTarget,));
    delegate!(rename_nick(
        old_nick: &str,
        new_nick: &str,
        ts: Tm,
        target: &MsgTarget,
    ));
    delegate!(set_topic(
        topic: &str,
        ts: Tm,
        serv_name: &str,
        chan_name: &str,
    ));
    delegate!(set_tab_style(style: TabStyle, target: &MsgTarget,));

    fn user_tab_exists(&self, serv_name: &str, nick: &str) -> bool {
        match self.inner.upgrade() {
            Some(tui) => tui.borrow().user_tab_exists(serv_name, nick),
            None => false,
        }
    }
}
<commit_msg>Remove track_caller feature as it's stable now<commit_after>#![cfg_attr(test, feature(test))]
#![allow(clippy::too_many_arguments)]
#![allow(clippy::cognitive_complexity)]
#![feature(or_patterns)]

mod config;
mod editor;
mod exit_dialogue;
mod input_area;
mod line_split;
mod messaging;
#[doc(hidden)]
// FIXME: This is "pub" to be able to use in an example
pub mod msg_area;
mod notifier;
mod statusline;
mod tab;
mod termbox;
mod trie;
mod tui;
mod utils;
mod widget;

#[cfg(test)]
mod tests;

pub use crate::tab::TabStyle;
use crate::tui::TUIRet;
pub use libtiny_ui::*;

use futures::select;
use futures::stream::StreamExt;
use std::cell::RefCell;
use std::path::PathBuf;
use std::rc::{Rc, Weak};
use term_input::Input;
use time::Tm;
use tokio::signal::unix::{signal, SignalKind};
use tokio::sync::mpsc;
use tokio::task::spawn_local;

#[macro_use]
extern crate log;

#[derive(Clone)]
pub struct TUI {
    inner: Weak<RefCell<tui::TUI>>,
}

impl TUI {
    pub fn run(config_path: PathBuf) -> (TUI, mpsc::Receiver<Event>) {
        let tui = Rc::new(RefCell::new(tui::TUI::new(config_path)));
        let inner = Rc::downgrade(&tui);

        let (snd_ev, rcv_ev) = mpsc::channel(10);

        // For SIGWINCH handler
        let (snd_abort, rcv_abort) = mpsc::channel::<()>(1);

        // Spawn SIGWINCH handler
        spawn_local(sigwinch_handler(inner.clone(), rcv_abort));

        // Spawn input handler task
        spawn_local(input_handler(tui, snd_ev, snd_abort));

        (TUI { inner }, rcv_ev)
    }
}

async fn sigwinch_handler(tui: Weak<RefCell<tui::TUI>>, rcv_abort: mpsc::Receiver<()>) {
    let stream = match signal(SignalKind::window_change()) {
        Err(err) => {
            debug!("Can't install SIGWINCH handler: {:?}", err);
            return;
        }
        Ok(stream) => stream,
    };

    let mut stream_fused = stream.fuse();
    let mut rcv_abort_fused = rcv_abort.fuse();

    loop {
        select! {
            _ = stream_fused.next() => {
                match tui.upgrade() {
                    None => {
                        return;
                    }
                    Some(tui) => {
                        tui.borrow_mut().resize();
                    }
                }
            },
            _ = rcv_abort_fused.next() => {
                return;
            }
        }
    }
}

async fn input_handler(
    tui: Rc<RefCell<tui::TUI>>,
    mut snd_ev: mpsc::Sender<Event>,
    mut snd_abort: mpsc::Sender<()>,
) {
    let mut input = Input::new();

    // See module documentation of `editor` for how editor stuff works
    let mut rcv_editor_ret: Option<editor::ResultReceiver> = None;

    loop {
        if let Some(editor_ret) = rcv_editor_ret.take() {
            // $EDITOR running, don't read stdin, wait for $EDITOR to finish
            match editor_ret.await {
                Err(recv_error) => {
                    debug!("RecvError while waiting editor response: {:?}", recv_error);
                }
                Ok(editor_ret) => {
                    if let Some((lines, from)) = tui.borrow_mut().handle_editor_result(editor_ret) {
                        debug!("editor ret: {:?}", lines);
                        snd_ev
                            .try_send(Event::Lines {
                                lines,
                                source: from,
                            })
                            .unwrap();
                    }
                }
            }

            tui.borrow_mut().activate();
            tui.borrow_mut().draw();
        }

        match input.next().await {
            None => {
                break;
            }
            Some(Err(io_err)) => {
                debug!("term_input error: {:?}", io_err);
                break;
            }
            Some(Ok(ev)) => {
                let tui_ret = tui.borrow_mut().handle_input_event(ev, &mut rcv_editor_ret);
                match tui_ret {
                    TUIRet::Abort => {
                        snd_ev.try_send(Event::Abort).unwrap();
                        let _ = snd_abort.try_send(());
                        return;
                    }
                    TUIRet::KeyHandled | TUIRet::KeyIgnored(_) | TUIRet::EventIgnored(_) => {}
                    TUIRet::Input { msg, from } => {
                        if msg[0] == '/' {
                            // Handle TUI commands, send others to downstream
                            let cmd: String = (&msg[1..]).iter().collect();
                            let handled = tui.borrow_mut().try_handle_cmd(&cmd, &from);
                            if !handled {
                                snd_ev.try_send(Event::Cmd { cmd, source: from }).unwrap();
                            }
                        } else {
                            snd_ev
                                .try_send(Event::Msg {
                                    msg: msg.into_iter().collect(),
                                    source: from,
                                })
                                .unwrap();
                        }
                    }
                }
            }
        }

        tui.borrow_mut().draw();
    }
}

macro_rules! delegate {
    ( $name:ident ( $( $x:ident: $t:ty, )* ) ) => {
        fn $name(&self, $($x: $t,)*) {
            if let Some(inner) = self.inner.upgrade() {
                inner.borrow_mut().$name( $( $x, )* );
            }
        }
    }
}

impl UI for TUI {
    delegate!(draw());
    delegate!(new_server_tab(serv_name: &str, alias: Option<String>,));
    delegate!(close_server_tab(serv_name: &str,));
    delegate!(new_chan_tab(serv_name: &str, chan: &str,));
    delegate!(close_chan_tab(serv_name: &str, chan: &str,));
    delegate!(close_user_tab(serv_name: &str, nick: &str,));
    delegate!(add_client_msg(msg: &str, target: &MsgTarget,));
    delegate!(add_msg(msg: &str, ts: Tm, target: &MsgTarget,));
    delegate!(add_err_msg(msg: &str, ts: Tm, target: &MsgTarget,));
    delegate!(add_client_err_msg(msg: &str, target: &MsgTarget,));
    delegate!(clear_nicks(serv_name: &str,));
    delegate!(set_nick(serv_name: &str, new_nick: &str,));
    delegate!(add_privmsg(
        sender: &str,
        msg: &str,
        ts: Tm,
        target: &MsgTarget,
        highlight: bool,
        is_action: bool,
    ));
    delegate!(add_nick(nick: &str, ts: Option<Tm>, target: &MsgTarget,));
    delegate!(remove_nick(nick: &str, ts: Option<Tm>, target: &MsgTarget,));
    delegate!(rename_nick(
        old_nick: &str,
        new_nick: &str,
        ts: Tm,
        target: &MsgTarget,
    ));
    delegate!(set_topic(
        topic: &str,
        ts: Tm,
        serv_name: &str,
        chan_name: &str,
    ));
    delegate!(set_tab_style(style: TabStyle, target: &MsgTarget,));

    fn user_tab_exists(&self, serv_name: &str, nick: &str) -> bool {
        match self.inner.upgrade() {
            Some(tui) => tui.borrow().user_tab_exists(serv_name, nick),
            None => false,
        }
    }
}
<|endoftext|>


<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match (self.instruction_pointer, self.status) {
            (Some(mut index), ProgramStatus::Seeking(_)) => {
                self.handle_jump_forward(vm, &mut index);
                self.instruction_pointer = Some(index);
                if index < self.instructions.len() { self.execute(vm); }
            }

            (Some(mut index), ProgramStatus::Normal) => {
                while index < self.instructions.len() {
                    match self.instructions[index] {
                        Command::JumpForward => self.handle_jump_forward(vm, &mut index),
                        Command::JumpBackward => self.handle_jump_backward(vm, &mut index),
                        command => {
                            vm.apply(command);
                            index += 1;
                        }
                    }
                }

                self.instruction_pointer = Some(index);
            }

            _ => {}
        }
    }

    fn handle_jump_backward(&mut self, vm: &VM, index_ref: &mut usize) {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.current_depth -= 1;
                *index_ref += 1;
            }

            _ => {
                let goal_depth = self.current_depth;
                for index in (0..*index_ref).rev() {
                    match self.instructions[index] {
                        Command::JumpBackward => self.current_depth += 1,
                        Command::JumpForward => {
                            if self.current_depth == goal_depth {
                                *index_ref = index + 1;
                                return;
                            }
                            self.current_depth -= 1;
                        }
                        _ => {}
                    }
                }
                panic!("No starting brace found!");
            }
        }
    }

    fn seek_forward(&self, starting_index: usize) -> (usize, u64, ProgramStatus) {
        match self.status {
            ProgramStatus::Seeking(goal_depth) => {
                for index in starting_index..self.instructions.len() {
                    match self.instructions[index] {
                        Command::JumpForward => self.current_depth += 1,
                        Command::JumpBackward => self.current_depth -= 1,
                        _ => {}
                    }
                    if self.current_depth == goal_depth {
                        return (index + 1, self.current_depth, ProgramStatus::Normal);
                    }
                }

                return (self.instructions.len()
                       , self.current_depth
                       , ProgramStatus::Seeking(goal_depth));
            }

            ProgramStatus::Normal => return (starting_index, self.current_depth, self.status)
        }
    }

    fn handle_jump_forward(&self, vm: &VM, index: usize) -> (usize, u64, ProgramStatus){
        match (vm.cells[vm.data_pointer], self.status) {
            (0, ProgramStatus::Normal) => return self.seek_forward(index),
            (_, ProgramStatus::Normal) => return (index + 1, self.current_depth + 1, ProgramStatus::Normal),
            (_, ProgramStatus::Seeking(_)) => self.seek_forward(index),

        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    pub fn test_seek_forward_normal() {
        let mut program = Program {
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Seeking(0),
            instructions: vec![
                Command::JumpForward,
                Command::JumpForward,
                Command::JumpBackward,
                Command::JumpBackward,
            ],
        };
        let mut index = 0;
        program.seek_forward(&mut index);
        assert_eq!(index, 4);
        assert_eq!(program.status, ProgramStatus::Normal);
    }

    #[test]
    pub fn test_seek_forward_seeking() {
        let mut program = Program {
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Seeking(0),
            instructions: vec![
                Command::JumpForward,
                Command::JumpForward,
                Command::JumpBackward,
            ],
        };
        let mut index = 0;
        program.seek_forward(&mut index);
        assert_eq!(index, 3);
        assert_eq!(program.status, ProgramStatus::Seeking(0));
    }
}
<commit_msg>Modify execute function to mutate Program instance<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match (self.instruction_pointer, self.status) {
            (Some(mut index), ProgramStatus::Seeking(_)) => {
                let (new_index, new_depth, new_status) = self.handle_jump_forward(vm, index);
                self.instruction_pointer = Some(new_index);
                self.current_depth = new_depth;
                self.status = new_status;
                if new_index < self.instructions.len() { self.execute(vm); }
            }

            (Some(mut index), ProgramStatus::Normal) => {
                while index < self.instructions.len() {
                    match self.instructions[index] {
                        Command::JumpBackward => self.handle_jump_backward(vm, &mut index),

                        Command::JumpForward => {
                            let (new_index, new_depth, new_status) = self.handle_jump_forward(vm, index);
                            index = new_index;
                            self.current_depth = new_depth;
                            self.status = new_status;
                        }

                        command => {
                            vm.apply(command);
                            index += 1;
                        }
                    }
                }

                self.instruction_pointer = Some(index);
            }

            _ => {}
        }
    }

    fn handle_jump_backward(&mut self, vm: &VM, index_ref: &mut usize) {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.current_depth -= 1;
                *index_ref += 1;
            }

            _ => {
                let goal_depth = self.current_depth;
                for index in (0..*index_ref).rev() {
                    match self.instructions[index] {
                        Command::JumpBackward => self.current_depth += 1,
                        Command::JumpForward => {
                            if self.current_depth == goal_depth {
                                *index_ref = index + 1;
                                return;
                            }
                            self.current_depth -= 1;
                        }
                        _ => {}
                    }
                }
                panic!("No starting brace found!");
            }
        }
    }

    fn seek_forward(&self, starting_index: usize) -> (usize, u64, ProgramStatus) {
        match self.status {
            ProgramStatus::Seeking(goal_depth) => {
                for index in starting_index..self.instructions.len() {
                    match self.instructions[index] {
                        Command::JumpForward => self.current_depth += 1,
                        Command::JumpBackward => self.current_depth -= 1,
                        _ => {}
                    }
                    if self.current_depth == goal_depth {
                        return (index + 1, self.current_depth, ProgramStatus::Normal);
                    }
                }

                return (self.instructions.len()
                       , self.current_depth
                       , ProgramStatus::Seeking(goal_depth));
            }

            ProgramStatus::Normal => return (starting_index, self.current_depth, self.status)
        }
    }

    fn handle_jump_forward(&self, vm: &VM, index: usize) -> (usize, u64, ProgramStatus){
        match (vm.cells[vm.data_pointer], self.status) {
            (0, ProgramStatus::Normal) => return self.seek_forward(index),
            (_, ProgramStatus::Normal) => return (index + 1, self.current_depth + 1, ProgramStatus::Normal),
            (_, ProgramStatus::Seeking(_)) => self.seek_forward(index),

        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    pub fn test_seek_forward_normal() {
        let mut program = Program {
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Seeking(0),
            instructions: vec![
                Command::JumpForward,
                Command::JumpForward,
                Command::JumpBackward,
                Command::JumpBackward,
            ],
        };
        let mut index = 0;
        program.seek_forward(&mut index);
        assert_eq!(index, 4);
        assert_eq!(program.status, ProgramStatus::Normal);
    }

    #[test]
    pub fn test_seek_forward_seeking() {
        let mut program = Program {
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Seeking(0),
            instructions: vec![
                Command::JumpForward,
                Command::JumpForward,
                Command::JumpBackward,
            ],
        };
        let mut index = 0;
        program.seek_forward(&mut index);
        assert_eq!(index, 3);
        assert_eq!(program.status, ProgramStatus::Seeking(0));
    }
}
<|endoftext|>


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

use cell::Cell;
use result::{Result, Ok, Err};
use super::io::net::ip::{IpAddr, Ipv4};
use rt::local_services::LocalServices;

/// Creates a new scheduler in a new thread and runs a task in it,
/// then waits for the scheduler to exit. Failure of the task
/// will abort the process.
pub fn run_in_newsched_task(f: ~fn()) {
    use unstable::run_in_bare_thread;
    use super::sched::Task;
    use super::uvio::UvEventLoop;

    let f = Cell(f);

    do run_in_bare_thread {
        let mut sched = ~UvEventLoop::new_scheduler();
        let task = ~Task::with_local(&mut sched.stack_pool,
                                     LocalServices::without_unwinding(),
                                     f.take());
        sched.task_queue.push_back(task);
        sched.run();
    }
}

/// Test tasks will abort on failure instead of unwinding
pub fn spawntask(f: ~fn()) {
    use super::sched::*;

    let mut sched = local_sched::take();
    let task = ~Task::with_local(&mut sched.stack_pool,
                                 LocalServices::without_unwinding(),
                                 f);
    do sched.switch_running_tasks_and_then(task) |task| {
        let task = Cell(task);
        let sched = local_sched::take();
        sched.schedule_new_task(task.take());
    }
}

/// Create a new task and run it right now. Aborts on failure
pub fn spawntask_immediately(f: ~fn()) {
    use super::sched::*;

    let mut sched = local_sched::take();
    let task = ~Task::with_local(&mut sched.stack_pool,
                                 LocalServices::without_unwinding(),
                                 f);
    do sched.switch_running_tasks_and_then(task) |task| {
        let task = Cell(task);
        do local_sched::borrow |sched| {
            sched.task_queue.push_front(task.take());
        }
    }
}

/// Spawn a task and wait for it to finish, returning whether it completed successfully or failed
pub fn spawntask_try(f: ~fn()) -> Result<(), ()> {
    use cell::Cell;
    use super::sched::*;
    use task;
    use unstable::finally::Finally;

    // Our status variables will be filled in from the scheduler context
    let mut failed = false;
    let failed_ptr: *mut bool = &mut failed;

    // Switch to the scheduler
    let f = Cell(Cell(f));
    let mut sched = local_sched::take();
    do sched.deschedule_running_task_and_then() |old_task| {
        let old_task = Cell(old_task);
        let f = f.take();
        let mut sched = local_sched::take();
        let new_task = ~do Task::new(&mut sched.stack_pool) {
            do (|| {
                (f.take())()
            }).finally {
                // Check for failure then resume the parent task
                unsafe { *failed_ptr = task::failing(); }
                let sched = local_sched::take();
                do sched.switch_running_tasks_and_then(old_task.take()) |new_task| {
                    let new_task = Cell(new_task);
                    do local_sched::borrow |sched| {
                        sched.task_queue.push_front(new_task.take());
                    }
                }
            }
        };

        sched.resume_task_immediately(new_task);
    }

    if !failed { Ok(()) } else { Err(()) }
}

/// Get a port number, starting at 9600, for use in tests
pub fn next_test_port() -> u16 {
    unsafe {
        return rust_dbg_next_port() as u16;
    }
    extern {
        fn rust_dbg_next_port() -> ::libc::uintptr_t;
    }
}

/// Get a unique localhost:port pair starting at 9600
pub fn next_test_ip4() -> IpAddr {
    Ipv4(127, 0, 0, 1, next_test_port())
}
<commit_msg>core::rt: Fix a warning about unnecessary mutable variable<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use cell::Cell;
use result::{Result, Ok, Err};
use super::io::net::ip::{IpAddr, Ipv4};
use rt::local_services::LocalServices;

/// Creates a new scheduler in a new thread and runs a task in it,
/// then waits for the scheduler to exit. Failure of the task
/// will abort the process.
pub fn run_in_newsched_task(f: ~fn()) {
    use unstable::run_in_bare_thread;
    use super::sched::Task;
    use super::uvio::UvEventLoop;

    let f = Cell(f);

    do run_in_bare_thread {
        let mut sched = ~UvEventLoop::new_scheduler();
        let task = ~Task::with_local(&mut sched.stack_pool,
                                     LocalServices::without_unwinding(),
                                     f.take());
        sched.task_queue.push_back(task);
        sched.run();
    }
}

/// Test tasks will abort on failure instead of unwinding
pub fn spawntask(f: ~fn()) {
    use super::sched::*;

    let mut sched = local_sched::take();
    let task = ~Task::with_local(&mut sched.stack_pool,
                                 LocalServices::without_unwinding(),
                                 f);
    do sched.switch_running_tasks_and_then(task) |task| {
        let task = Cell(task);
        let sched = local_sched::take();
        sched.schedule_new_task(task.take());
    }
}

/// Create a new task and run it right now. Aborts on failure
pub fn spawntask_immediately(f: ~fn()) {
    use super::sched::*;

    let mut sched = local_sched::take();
    let task = ~Task::with_local(&mut sched.stack_pool,
                                 LocalServices::without_unwinding(),
                                 f);
    do sched.switch_running_tasks_and_then(task) |task| {
        let task = Cell(task);
        do local_sched::borrow |sched| {
            sched.task_queue.push_front(task.take());
        }
    }
}

/// Spawn a task and wait for it to finish, returning whether it completed successfully or failed
pub fn spawntask_try(f: ~fn()) -> Result<(), ()> {
    use cell::Cell;
    use super::sched::*;
    use task;
    use unstable::finally::Finally;

    // Our status variables will be filled in from the scheduler context
    let mut failed = false;
    let failed_ptr: *mut bool = &mut failed;

    // Switch to the scheduler
    let f = Cell(Cell(f));
    let sched = local_sched::take();
    do sched.deschedule_running_task_and_then() |old_task| {
        let old_task = Cell(old_task);
        let f = f.take();
        let mut sched = local_sched::take();
        let new_task = ~do Task::new(&mut sched.stack_pool) {
            do (|| {
                (f.take())()
            }).finally {
                // Check for failure then resume the parent task
                unsafe { *failed_ptr = task::failing(); }
                let sched = local_sched::take();
                do sched.switch_running_tasks_and_then(old_task.take()) |new_task| {
                    let new_task = Cell(new_task);
                    do local_sched::borrow |sched| {
                        sched.task_queue.push_front(new_task.take());
                    }
                }
            }
        };

        sched.resume_task_immediately(new_task);
    }

    if !failed { Ok(()) } else { Err(()) }
}

/// Get a port number, starting at 9600, for use in tests
pub fn next_test_port() -> u16 {
    unsafe {
        return rust_dbg_next_port() as u16;
    }
    extern {
        fn rust_dbg_next_port() -> ::libc::uintptr_t;
    }
}

/// Get a unique localhost:port pair starting at 9600
pub fn next_test_ip4() -> IpAddr {
    Ipv4(127, 0, 0, 1, next_test_port())
}
<|endoftext|>


<commit_before>use std::io::net::ip::{Ipv4Addr, SocketAddr};

mod libtorresmo {
    extern crate time;

    use std::io::net::udp::UdpSocket;
    use std::io::net::ip::SocketAddr;
    use std::io::IoResult;
    use std::mem::{to_be32, to_be16, transmute};
    use std::rand::random;

    #[allow(dead_code,non_camel_case_types)]
    enum UtpPacketType {
        ST_DATA  = 0,
        ST_FIN   = 1,
        ST_STATE = 2,
        ST_RESET = 3,
        ST_SYN   = 4,
    }

    #[allow(dead_code)]
    struct UtpPacketHeader {
        type_ver: u8, // type: u4, ver: u4
        extension: u8,
        connection_id: u16,
        timestamp_microseconds: u32,
        timestamp_difference_microseconds: u32,
        wnd_size: u32,
        seq_nr: u16,
        ack_nr: u16,
    }

    impl UtpPacketHeader {
        fn bytes(&self) -> &[u8] {
            unsafe {
                let buf: &[u8, ..20] = transmute(self);
                return buf.as_slice();
            }
        }

        fn len(&self) -> uint {
            static HEADER_SIZE: uint = 20;
            return HEADER_SIZE;
        }
    }

    #[allow(dead_code)]
    struct UtpPacket {
        header: UtpPacketHeader,
        payload: Vec<u8>,
    }

    impl UtpPacket {
        /// Constructs a new, empty UtpPacket.
        fn new() -> UtpPacket {
            UtpPacket {
                header: UtpPacketHeader {
                    type_ver: ST_DATA as u8 << 4 | 1,
                    extension: 0,
                    connection_id: 0,
                    timestamp_microseconds: 0,
                    timestamp_difference_microseconds: 0,
                    wnd_size: 0,
                    seq_nr: 0,
                    ack_nr: 0,
                },
                payload: Vec::new(),
            }
        }

        fn bytes(&self) -> Vec<u8> {
            let mut buf: Vec<u8> = Vec::with_capacity(self.len());
            buf.push_all(self.header.bytes());
            buf.push_all(self.payload.as_slice());
            return buf;
        }

        fn len(&self) -> uint {
            self.header.len() + self.payload.len()
        }
    }

    pub struct UtpSocket {
        socket: UdpSocket,
    }

    impl UtpSocket {
        pub fn bind(addr: SocketAddr) -> IoResult<UtpSocket> {
            let skt = UdpSocket::bind(addr);
            match skt {
                Ok(x)  => Ok(UtpSocket { socket: x }),
                Err(e) => Err(e)
            }
        }

        pub fn connect(self, other: SocketAddr) -> UtpStream {
            UtpStream::new(self.socket, other)
        }

        pub fn recvfrom(&mut self, buf: &mut[u8]) -> IoResult<(uint,SocketAddr)> {
            self.socket.recvfrom(buf)
        }
    }

    impl Clone for UtpSocket {
        fn clone(&self) -> UtpSocket {
            UtpSocket {
                socket: self.socket.clone(),
            }
        }
    }

    #[allow(dead_code)]
    pub struct UtpStream {
        socket: UdpSocket,
        connected_to: SocketAddr,
        seq_nr: u16,
        ack_nr: u16,
    }

    #[allow(dead_code)]
    impl UtpStream {
        pub fn new(socket: UdpSocket, conn: SocketAddr) -> UtpStream {
            UtpStream {
                socket: socket,
                connected_to: conn,
                seq_nr: 0,
                ack_nr: 0,
            }
        }

        pub fn disconnect(self) -> UdpSocket {
            self.socket
        }
    }

    impl Reader for UtpStream {
        fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
            match self.socket.recvfrom(buf) {
                Ok((_nread, src)) if src != self.connected_to => Ok(0),
                Ok((nread, _src)) => Ok(nread),
                Err(e) => Err(e),
            }
        }
    }
    impl Writer for UtpStream {
        fn write(&mut self, buf: &[u8]) -> IoResult<()> {
            let mut packet = UtpPacket::new();
            packet.payload = Vec::from_slice(buf);
            packet.header.seq_nr = to_be16(self.seq_nr);
            packet.header.connection_id = to_be16(random());
            let t = time::get_time();
            packet.header.timestamp_microseconds = to_be32((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32);

            // Send packet
            let result = self.socket.sendto(packet.bytes().as_slice(), self.connected_to);

            self.seq_nr += 1;
            result
        }
    }
}

fn usage() {
    println!("Usage: torresmo [-s|-c] <address> <port>");
}

fn main() {
    use libtorresmo::{UtpSocket, UtpStream};
    use std::from_str::FromStr;

    // Defaults
    let mut addr = SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 };

    let args = std::os::args();

    if args.len() == 4 {
        let ip = FromStr::from_str(args.get(2).as_slice()).unwrap();
        let port = FromStr::from_str(args.get(3).as_slice()).unwrap();
        addr = SocketAddr { ip: ip, port: port };
    }

    match args.get(1).as_slice() {
        "-s" => {
            let mut buf = [0, ..512];
            let sock = UtpSocket::bind(addr).unwrap();
            println!("Serving on {}", addr);

            loop {
                let mut sock = sock.clone();
                match sock.recvfrom(buf) {
                    Ok((_, src)) => {
                        spawn(proc() {
                            let mut stream = sock.connect(src);
                            let payload = String::from_str("Hello\n").into_bytes();

                            // Send uTP packet
                            let _ = stream.write(payload.as_slice());
                        })
                    }
                    Err(_) => {}
                }
            }
        }
        "-c" => {
            let sock = UtpSocket::bind(SocketAddr { ip: Ipv4Addr(127,0,0,1), port: std::rand::random() }).unwrap();
            let mut stream = sock.connect(addr);
            let _ = stream.write([0]);
            drop(stream);
        }
        _ => usage(),
    }
}
<commit_msg>Add packet type setter.<commit_after>use std::io::net::ip::{Ipv4Addr, SocketAddr};

mod libtorresmo {
    extern crate time;

    use std::io::net::udp::UdpSocket;
    use std::io::net::ip::SocketAddr;
    use std::io::IoResult;
    use std::mem::{to_be32, to_be16, transmute};
    use std::rand::random;

    #[allow(dead_code,non_camel_case_types)]
    enum UtpPacketType {
        ST_DATA  = 0,
        ST_FIN   = 1,
        ST_STATE = 2,
        ST_RESET = 3,
        ST_SYN   = 4,
    }

    #[allow(dead_code)]
    struct UtpPacketHeader {
        type_ver: u8, // type: u4, ver: u4
        extension: u8,
        connection_id: u16,
        timestamp_microseconds: u32,
        timestamp_difference_microseconds: u32,
        wnd_size: u32,
        seq_nr: u16,
        ack_nr: u16,
    }

    impl UtpPacketHeader {
        fn bytes(&self) -> &[u8] {
            unsafe {
                let buf: &[u8, ..20] = transmute(self);
                return buf.as_slice();
            }
        }

        fn len(&self) -> uint {
            static HEADER_SIZE: uint = 20;
            return HEADER_SIZE;
        }
    }

    #[allow(dead_code)]
    struct UtpPacket {
        header: UtpPacketHeader,
        payload: Vec<u8>,
    }

    impl UtpPacket {
        /// Constructs a new, empty UtpPacket.
        fn new() -> UtpPacket {
            UtpPacket {
                header: UtpPacketHeader {
                    type_ver: ST_DATA as u8 << 4 | 1,
                    extension: 0,
                    connection_id: 0,
                    timestamp_microseconds: 0,
                    timestamp_difference_microseconds: 0,
                    wnd_size: 0,
                    seq_nr: 0,
                    ack_nr: 0,
                },
                payload: Vec::new(),
            }
        }

        fn set_type(&mut self, t: UtpPacketType) {
            let version = 0x0F & self.header.type_ver;
            self.header.type_ver = t as u8 << 4 | version;
        }

        fn bytes(&self) -> Vec<u8> {
            let mut buf: Vec<u8> = Vec::with_capacity(self.len());
            buf.push_all(self.header.bytes());
            buf.push_all(self.payload.as_slice());
            return buf;
        }

        fn len(&self) -> uint {
            self.header.len() + self.payload.len()
        }
    }

    pub struct UtpSocket {
        socket: UdpSocket,
    }

    impl UtpSocket {
        pub fn bind(addr: SocketAddr) -> IoResult<UtpSocket> {
            let skt = UdpSocket::bind(addr);
            match skt {
                Ok(x)  => Ok(UtpSocket { socket: x }),
                Err(e) => Err(e)
            }
        }

        pub fn connect(self, other: SocketAddr) -> UtpStream {
            UtpStream::new(self.socket, other)
        }

        pub fn recvfrom(&mut self, buf: &mut[u8]) -> IoResult<(uint,SocketAddr)> {
            self.socket.recvfrom(buf)
        }
    }

    impl Clone for UtpSocket {
        fn clone(&self) -> UtpSocket {
            UtpSocket {
                socket: self.socket.clone(),
            }
        }
    }

    #[allow(dead_code)]
    pub struct UtpStream {
        socket: UdpSocket,
        connected_to: SocketAddr,
        seq_nr: u16,
        ack_nr: u16,
    }

    #[allow(dead_code)]
    impl UtpStream {
        pub fn new(socket: UdpSocket, conn: SocketAddr) -> UtpStream {
            UtpStream {
                socket: socket,
                connected_to: conn,
                seq_nr: 0,
                ack_nr: 0,
            }
        }

        pub fn disconnect(self) -> UdpSocket {
            self.socket
        }
    }

    impl Reader for UtpStream {
        fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
            match self.socket.recvfrom(buf) {
                Ok((_nread, src)) if src != self.connected_to => Ok(0),
                Ok((nread, _src)) => Ok(nread),
                Err(e) => Err(e),
            }
        }
    }
    impl Writer for UtpStream {
        fn write(&mut self, buf: &[u8]) -> IoResult<()> {
            let mut packet = UtpPacket::new();
            packet.payload = Vec::from_slice(buf);
            packet.header.seq_nr = to_be16(self.seq_nr);
            packet.header.connection_id = to_be16(random());
            let t = time::get_time();
            packet.header.timestamp_microseconds = to_be32((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32);

            // Send packet
            let result = self.socket.sendto(packet.bytes().as_slice(), self.connected_to);

            self.seq_nr += 1;
            result
        }
    }
}

fn usage() {
    println!("Usage: torresmo [-s|-c] <address> <port>");
}

fn main() {
    use libtorresmo::{UtpSocket, UtpStream};
    use std::from_str::FromStr;

    // Defaults
    let mut addr = SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 };

    let args = std::os::args();

    if args.len() == 4 {
        let ip = FromStr::from_str(args.get(2).as_slice()).unwrap();
        let port = FromStr::from_str(args.get(3).as_slice()).unwrap();
        addr = SocketAddr { ip: ip, port: port };
    }

    match args.get(1).as_slice() {
        "-s" => {
            let mut buf = [0, ..512];
            let sock = UtpSocket::bind(addr).unwrap();
            println!("Serving on {}", addr);

            loop {
                let mut sock = sock.clone();
                match sock.recvfrom(buf) {
                    Ok((_, src)) => {
                        spawn(proc() {
                            let mut stream = sock.connect(src);
                            let payload = String::from_str("Hello\n").into_bytes();

                            // Send uTP packet
                            let _ = stream.write(payload.as_slice());
                        })
                    }
                    Err(_) => {}
                }
            }
        }
        "-c" => {
            let sock = UtpSocket::bind(SocketAddr { ip: Ipv4Addr(127,0,0,1), port: std::rand::random() }).unwrap();
            let mut stream = sock.connect(addr);
            let _ = stream.write([0]);
            drop(stream);
        }
        _ => usage(),
    }
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2018 Guillaume Gomez
//

use ComponentExt;

use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs::{metadata, read_dir, File};
use std::io::Read;
use std::path::{Path, PathBuf};

/// More information can be found at [kernel.org][k].
///
/// Note: these may not be present on virtual Linux systems, such as **Docker**
/// or **Windows Subsystem for Linux**. These hosts do not expose this information
/// and therefore `Component` elements may be missing or not as expected.
///
/// [k]: https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface
pub struct Component {
    temperature: f32,
    max: f32,
    critical: Option<f32>,
    label: String,
    input_file: PathBuf,
}

fn get_file_line(file: &Path, capacity: usize) -> Option<String> {
    let mut reader = String::with_capacity(capacity);
    if let Ok(mut f) = File::open(file) {
        if f.read_to_string(&mut reader).is_ok() {
            Some(reader)
        } else {
            None
        }
    } else {
        None
    }
}

fn is_file<T: AsRef<Path>>(path: T) -> bool {
    metadata(path)
        .ok()
        .map(|m| m.is_file())
        .unwrap_or_else(|| false)
}

fn append_files(components: &mut Vec<Component>, folder: &Path) {
    let mut matchings: HashMap<u32, Vec<String>> = HashMap::with_capacity(10);

    if let Ok(dir) = read_dir(folder) {
        for entry in dir {
            if let Ok(entry) = entry {
                let entry = entry.path();
                if entry.is_dir()
                    || !entry
                        .file_name()
                        .unwrap_or_else(|| OsStr::new("/"))
                        .to_str()
                        .unwrap_or("")
                        .starts_with("temp")
                {
                    continue;
                }
                if let Some(entry) = entry.file_name() {
                    if let Some(entry) = entry.to_str() {
                        let mut parts = entry.split('_');
                        if let Some(Some(id)) = parts.next().map(|s| s[4..].parse::<u32>().ok()) {
                            matchings
                                .entry(id)
                                .or_insert_with(|| Vec::with_capacity(5))
                                .push(
                                    parts
                                        .next()
                                        .map(|s| format!("_{}", s))
                                        .unwrap_or_else(String::new),
                                );
                        }
                    }
                }
            }
        }
        for (key, val) in &matchings {
            let mut found_input = None;
            let mut found_label = None;
            for (pos, v) in val.iter().enumerate() {
                match v.as_str() {
                    // raspberry has empty string for temperature input
                    "_input" | "" => {
                        found_input = Some(pos);
                    }
                    "_label" => {
                        found_label = Some(pos);
                    }
                    _ => {}
                }
            }
            if let (Some(_), Some(found_input)) = (found_label, found_input) {
                let mut p_label = folder.to_path_buf();
                let mut p_input = folder.to_path_buf();
                let mut p_crit = folder.to_path_buf();
                let mut p_max = folder.to_path_buf();

                p_label.push(&format!("temp{}_label", key));
                p_input.push(&format!("temp{}{}", key, val[found_input]));
                p_max.push(&format!("temp{}_max", key));
                p_crit.push(&format!("temp{}_crit", key));
                if is_file(&p_input) {
                    let label = get_file_line(p_label.as_path(), 10)
                        .unwrap_or_else(|| format!("Component {}", key)) // needed for raspberry pi
                        .replace("\n", "");
                    let max = if let Some(max) = get_file_line(p_max.as_path(), 10) {
                        Some(max.replace("\n", "").parse::<f32>().unwrap_or(100_000f32) / 1000f32)
                    } else {
                        None
                    };
                    let crit = if let Some(crit) = get_file_line(p_crit.as_path(), 10) {
                        Some(crit.replace("\n", "").parse::<f32>().unwrap_or(100_000f32) / 1000f32)
                    } else {
                        None
                    };
                    components.push(Component::new(label, p_input.as_path(), max, crit));
                }
            }
        }
    }
}

impl Component {
    /// Creates a new component with the given information.
    pub(crate) fn new(
        label: String,
        input_path: &Path,
        max: Option<f32>,
        critical: Option<f32>,
    ) -> Component {
        let mut c = Component {
            temperature: 0f32,
            label,
            input_file: input_path.to_path_buf(),
            max: max.unwrap_or(0.0),
            critical,
        };
        c.refresh();
        c
    }
}

impl ComponentExt for Component {
    fn get_temperature(&self) -> f32 {
        self.temperature
    }

    fn get_max(&self) -> f32 {
        self.max
    }

    fn get_critical(&self) -> Option<f32> {
        self.critical
    }

    fn get_label(&self) -> &str {
        &self.label
    }

    fn refresh(&mut self) {
        if let Some(content) = get_file_line(self.input_file.as_path(), 10) {
            self.temperature = content
                .replace("\n", "")
                .parse::<f32>()
                .unwrap_or(100_000f32)
                / 1000f32;
            if self.temperature > self.max {
                self.max = self.temperature;
            }
        }
    }
}

pub fn get_components() -> Vec<Component> {
    let mut components = Vec::with_capacity(10);
    if let Ok(dir) = read_dir(&Path::new("/sys/class/hwmon/")) {
        for entry in dir {
            if let Ok(entry) = entry {
                let entry = entry.path();
                if !entry.is_dir()
                    || !entry
                        .file_name()
                        .unwrap_or_else(|| OsStr::new("/"))
                        .to_str()
                        .unwrap_or("")
                        .starts_with("hwmon")
                {
                    continue;
                }
                append_files(&mut components, &entry);
            }
        }
        components.sort_by(|c1, c2| c1.label.to_lowercase().cmp(&c2.label.to_lowercase()));
    }
    if is_file("/sys/class/thermal/thermal_zone0/temp") {
        // Specfic to raspberry pi.
        components.push(Component::new(
            "CPU".to_owned(),
            Path::new("/sys/class/thermal/thermal_zone0/temp"),
            None,
            None,
        ));
    }
    if components.len() != 0 {
        components
    } else {
        Vec::new()
    }
}
<commit_msg>Removed unnecessary check<commit_after>//
// Sysinfo
//
// Copyright (c) 2018 Guillaume Gomez
//

use ComponentExt;

use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs::{metadata, read_dir, File};
use std::io::Read;
use std::path::{Path, PathBuf};

/// More information can be found at [kernel.org][k].
///
/// Note: these may not be present on virtual Linux systems, such as **Docker**
/// or **Windows Subsystem for Linux**. These hosts do not expose this information
/// and therefore `Component` elements may be missing or not as expected.
///
/// [k]: https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface
pub struct Component {
    temperature: f32,
    max: f32,
    critical: Option<f32>,
    label: String,
    input_file: PathBuf,
}

fn get_file_line(file: &Path, capacity: usize) -> Option<String> {
    let mut reader = String::with_capacity(capacity);
    if let Ok(mut f) = File::open(file) {
        if f.read_to_string(&mut reader).is_ok() {
            Some(reader)
        } else {
            None
        }
    } else {
        None
    }
}

fn is_file<T: AsRef<Path>>(path: T) -> bool {
    metadata(path)
        .ok()
        .map(|m| m.is_file())
        .unwrap_or_else(|| false)
}

fn append_files(components: &mut Vec<Component>, folder: &Path) {
    let mut matchings: HashMap<u32, Vec<String>> = HashMap::with_capacity(10);

    if let Ok(dir) = read_dir(folder) {
        for entry in dir {
            if let Ok(entry) = entry {
                let entry = entry.path();
                if entry.is_dir()
                    || !entry
                        .file_name()
                        .unwrap_or_else(|| OsStr::new("/"))
                        .to_str()
                        .unwrap_or("")
                        .starts_with("temp")
                {
                    continue;
                }
                if let Some(entry) = entry.file_name() {
                    if let Some(entry) = entry.to_str() {
                        let mut parts = entry.split('_');
                        if let Some(Some(id)) = parts.next().map(|s| s[4..].parse::<u32>().ok()) {
                            matchings
                                .entry(id)
                                .or_insert_with(|| Vec::with_capacity(5))
                                .push(
                                    parts
                                        .next()
                                        .map(|s| format!("_{}", s))
                                        .unwrap_or_else(String::new),
                                );
                        }
                    }
                }
            }
        }
        for (key, val) in &matchings {
            let mut found_input = None;
            let mut found_label = None;
            for (pos, v) in val.iter().enumerate() {
                match v.as_str() {
                    // raspberry has empty string for temperature input
                    "_input" | "" => {
                        found_input = Some(pos);
                    }
                    "_label" => {
                        found_label = Some(pos);
                    }
                    _ => {}
                }
            }
            if let (Some(_), Some(found_input)) = (found_label, found_input) {
                let mut p_label = folder.to_path_buf();
                let mut p_input = folder.to_path_buf();
                let mut p_crit = folder.to_path_buf();
                let mut p_max = folder.to_path_buf();

                p_label.push(&format!("temp{}_label", key));
                p_input.push(&format!("temp{}{}", key, val[found_input]));
                p_max.push(&format!("temp{}_max", key));
                p_crit.push(&format!("temp{}_crit", key));
                if is_file(&p_input) {
                    let label = get_file_line(p_label.as_path(), 10)
                        .unwrap_or_else(|| format!("Component {}", key)) // needed for raspberry pi
                        .replace("\n", "");
                    let max = if let Some(max) = get_file_line(p_max.as_path(), 10) {
                        Some(max.replace("\n", "").parse::<f32>().unwrap_or(100_000f32) / 1000f32)
                    } else {
                        None
                    };
                    let crit = if let Some(crit) = get_file_line(p_crit.as_path(), 10) {
                        Some(crit.replace("\n", "").parse::<f32>().unwrap_or(100_000f32) / 1000f32)
                    } else {
                        None
                    };
                    components.push(Component::new(label, p_input.as_path(), max, crit));
                }
            }
        }
    }
}

impl Component {
    /// Creates a new component with the given information.
    pub(crate) fn new(
        label: String,
        input_path: &Path,
        max: Option<f32>,
        critical: Option<f32>,
    ) -> Component {
        let mut c = Component {
            temperature: 0f32,
            label,
            input_file: input_path.to_path_buf(),
            max: max.unwrap_or(0.0),
            critical,
        };
        c.refresh();
        c
    }
}

impl ComponentExt for Component {
    fn get_temperature(&self) -> f32 {
        self.temperature
    }

    fn get_max(&self) -> f32 {
        self.max
    }

    fn get_critical(&self) -> Option<f32> {
        self.critical
    }

    fn get_label(&self) -> &str {
        &self.label
    }

    fn refresh(&mut self) {
        if let Some(content) = get_file_line(self.input_file.as_path(), 10) {
            self.temperature = content
                .replace("\n", "")
                .parse::<f32>()
                .unwrap_or(100_000f32)
                / 1000f32;
            if self.temperature > self.max {
                self.max = self.temperature;
            }
        }
    }
}

pub fn get_components() -> Vec<Component> {
    let mut components = Vec::with_capacity(10);
    if let Ok(dir) = read_dir(&Path::new("/sys/class/hwmon/")) {
        for entry in dir {
            if let Ok(entry) = entry {
                let entry = entry.path();
                if !entry.is_dir()
                    || !entry
                        .file_name()
                        .unwrap_or_else(|| OsStr::new("/"))
                        .to_str()
                        .unwrap_or("")
                        .starts_with("hwmon")
                {
                    continue;
                }
                append_files(&mut components, &entry);
            }
        }
        components.sort_by(|c1, c2| c1.label.to_lowercase().cmp(&c2.label.to_lowercase()));
    }
    if is_file("/sys/class/thermal/thermal_zone0/temp") {
        // Specfic to raspberry pi.
        components.push(Component::new(
            "CPU".to_owned(),
            Path::new("/sys/class/thermal/thermal_zone0/temp"),
            None,
            None,
        ));
    }
    components
}
<|endoftext|>


<commit_before>#![cfg(not(test))]

use core::fmt;
use core::fmt::Write;

use serial_logger;
use serial_logger::write_static;

#[lang = "eh_personality"]
#[no_mangle]
pub extern "C" fn eh_personality() {
    write_static("PANIC: eh_personality\n");
}

#[lang = "eh_unwind_resume"]
#[no_mangle]
pub extern "C" fn rust_eh_unwind_resume() {
    write_static("PANIC: rust_eh_unwind_resume\n");
}

#[no_mangle]
pub extern "C" fn __udivti3() {
    write_static("ERROR: Unimplemented intrinsic __udivti3\n");
}

#[no_mangle]
pub extern "C" fn __umodti3() {
    write_static("ERROR: Unimplemented intrinsic __umodti3\n");
}

#[no_mangle]
pub extern "C" fn __muloti4() {
    write_static("ERROR: Unimplemented intrinsic __muloti4\n");
}

#[no_mangle]
pub extern "C" fn __floatundisf() {
    write_static("ERROR: Unimplemented intrinsic __floatundisf\n");
}

#[no_mangle]
pub extern "C" fn __floatundidf() {
    write_static("ERROR: Unimplemented intrinsic __floatundidf\n");
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn _Unwind_Resume() {
    write_static("PANIC: _Unwind_Resume\n");
}

#[allow(empty_loop)]
#[lang = "panic_fmt"]
#[no_mangle]
pub extern "C" fn panic_fmt(fmt: fmt::Arguments, _file_line: &(&'static str, u32)) -> ! {

    write_static("PANIC: \n");
    let mut logger: serial_logger::SerialLogger = Default::default();
    let _ = write!(logger, "{}\n", fmt);

    loop {
        unsafe {
            asm!("cli; hlt;");
        }
    }
}
<commit_msg>Print file & line number on panic<commit_after>#![cfg(not(test))]

use core::fmt;
use core::fmt::Write;

use serial_logger;
use serial_logger::write_static;

#[lang = "eh_personality"]
#[no_mangle]
pub extern "C" fn eh_personality() {
    write_static("PANIC: eh_personality\n");
}

#[lang = "eh_unwind_resume"]
#[no_mangle]
pub extern "C" fn rust_eh_unwind_resume() {
    write_static("PANIC: rust_eh_unwind_resume\n");
}

#[no_mangle]
pub extern "C" fn __udivti3() {
    write_static("ERROR: Unimplemented intrinsic __udivti3\n");
}

#[no_mangle]
pub extern "C" fn __umodti3() {
    write_static("ERROR: Unimplemented intrinsic __umodti3\n");
}

#[no_mangle]
pub extern "C" fn __muloti4() {
    write_static("ERROR: Unimplemented intrinsic __muloti4\n");
}

#[no_mangle]
pub extern "C" fn __floatundisf() {
    write_static("ERROR: Unimplemented intrinsic __floatundisf\n");
}

#[no_mangle]
pub extern "C" fn __floatundidf() {
    write_static("ERROR: Unimplemented intrinsic __floatundidf\n");
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn _Unwind_Resume() {
    write_static("PANIC: _Unwind_Resume\n");
}

#[allow(empty_loop)]
#[lang = "panic_fmt"]
#[no_mangle]
pub extern "C" fn panic_fmt(fmt: fmt::Arguments,  file: &'static str, line: u32) -> ! {

    write_static("PANIC: \n");
    let mut logger: serial_logger::SerialLogger = Default::default();
    let _ = write!(logger, "{} {} {}\n", fmt, file, line);

    loop {
        unsafe {
            asm!("cli; hlt;");
        }
    }
}
<|endoftext|>


<commit_before>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

#![allow(unused_must_use)]

include!("bindings.rs");

use std::os::raw::c_char;
use std::io::Write;
use std::os::unix::io::FromRawFd;
use std::os::unix::io::IntoRawFd;
use std::io::Read;

#[derive(PartialEq)]
enum PrintState {
    OUT,
    IN,
    DISPLAY
}

fn print_ptr_rec<W: Write>(port: &mut W, p: ptr, state: PrintState) {
    let x = p as u32;
    if  (x & fx_mask) == fx_tag {
        write!(port, "{}", (x as i32) >> fx_shift);
    } else if x == bool_f {
        write!(port, "#f");
    } else if x == bool_t {
        write!(port, "#t");
    } else if x == list_nil {
        write!(port, "()");
    } else if x == eof_obj {
        write!(port, "#!eof");
    } else if (x & char_mask) == char_tag {
        let c = std::char::from_u32(x >> char_shift).
            expect("a char");
        if state == PrintState::DISPLAY {
            write!(port, "{}", c);
        } else {
            if      c == '\t' { write!(port, "#\\tab"); }
            else if c == '\n' { write!(port, "#\\newline"); }
            else if c == '\r' { write!(port, "#\\return"); }
            else if c == ' '  { write!(port, "#\\space"); }
            else              { write!(port, "#\\{}", c); }
        }
    } else if (x & obj_mask) == pair_tag {
        if state == PrintState::OUT { write!(port, "("); }
        let cell = unsafe { *((x-pair_tag) as *const cell) };
        let car = cell.car;
        print_ptr_rec(port, car, PrintState::OUT);
        let cdr = cell.cdr;
        if cdr != list_nil {
            if (cdr & obj_mask) != pair_tag {
                write!(port, " . ");
                print_ptr_rec(port, cdr, PrintState::OUT);
            } else {
                write!(port, " ");
                print_ptr_rec(port, cdr, PrintState::IN);
            }
        }
        if state == PrintState::OUT { write!(port, ")"); }
    } else if (x & obj_mask) == vector_tag {
        write!(port, "#(");
        unsafe {
        let p = &*((x-vector_tag) as *const vector);
        let n = (p.length as i32) >> fx_shift;
        for i in 0..n {
            if i > 0 { write!(port, " "); }
            print_ptr_rec(port,
                *((p.buf.as_ptr()).offset(i as isize)),
                PrintState::OUT)
        }}
        write!(port, ")");
    } else if (x & obj_mask) == string_tag {
        if state == PrintState::OUT { write!(port, "\""); }
        unsafe {
        let p = &*((x-string_tag) as *const string);
        let n = (p.length as i32) >> fx_shift;
        for i in 0..n {
            let c = std::char::from_u32(*((p.buf.as_ptr()).offset(i as isize)) as u32)
                .expect("char");
            if c == '"'       { write!(port, "\\\""); }
            else if c == '\\' { write!(port, "\\\\"); }
            else              { write!(port, "{}", c); }
        }}
        if state == PrintState::OUT { write!(port, "\""); }
    } else if (x & obj_mask) == symbol_tag {
        print_ptr_rec(port, (x - symbol_tag) | string_tag, PrintState::IN);
    } else if (x & obj_mask) == closure_tag {
        write!(port, "#<procedure>");
    } else {
        write!(port, "#<unknown 0x{:x}>", x);
    }
}
fn print_ptr(x: ptr) {
    print_ptr_rec(&mut std::io::stdout(), x, PrintState::OUT);
    println!("");
}

fn eprint_ptr(msg: ptr, state: PrintState) {
    print_ptr_rec(&mut std::io::stderr(), msg, state);
}

#[no_mangle]
pub extern "C" fn ik_log(msg: ptr) -> ptr {
    eprint!("log: ");
    eprint_ptr(msg, PrintState::IN);
    eprintln!("");
    0
}
#[no_mangle]
pub extern "C" fn ik_error(x: ptr) {
    eprint!("Exception");
    if (x & obj_mask) == pair_tag {
        let cell = unsafe { *((x-pair_tag) as *const cell) };
        let caller = cell.car;
        let msg = cell.cdr;
        if caller != bool_f {
            eprint!(" in ");
            eprint_ptr(caller, PrintState::OUT);
        }
        eprint!(": ");
        eprint_ptr(msg, PrintState::IN);
    }
    eprintln!("");
    std::process::exit(0);
}

fn unshift(x: ptr) -> i32 {
    (x as i32) >> fx_shift
}
fn shift(x: i32) -> ptr {
    (x << fx_shift) as u32
}
fn ptr_string_to_str(x: ptr) -> String {
    unsafe {
        let p = &*((x-string_tag) as *const string);
        let n = unshift(p.length) as usize;
        let mut v = Vec::with_capacity(n);
        for i in 0..n {
            v.push(*(p.buf.as_ptr().offset(i as isize)) as u8);
        }
        std::ffi::CString::from_vec_unchecked(v).into_string().expect("string")
    }
}
#[no_mangle]
pub extern "C" fn s_write(fd: ptr, str: ptr, len: ptr) -> ptr {
    let s = ptr_string_to_str(str);
    let len = unshift(len) as usize;
    let s: String = s.chars().take(len).collect();
    let ufd = unshift(fd) as i32;
    let mut w = unsafe { std::fs::File::from_raw_fd(ufd) };
    write!(w, "{}", s);
    w.flush();
    w.into_raw_fd();
    shift(s.len() as i32)
}
#[no_mangle]
pub extern "C" fn s_open_write(fname: ptr) -> ptr {
    let s_fname = ptr_string_to_str(fname);
    let port = std::fs::File::create(s_fname).expect("created");
    let fd = port.into_raw_fd();
    shift(fd)
}
#[no_mangle]
pub extern "C" fn s_fflush(fd: ptr) -> ptr {
    let ufd = unshift(fd) as i32;
    let mut w = unsafe { std::fs::File::from_raw_fd(ufd) };
    w.flush();
    w.into_raw_fd();
    0
}
#[no_mangle]
pub extern "C" fn scheme_write(fd: ptr, x: ptr, opt: ptr) -> ptr {
    let ufd = unshift(fd) as i32;
    let state = unshift(opt);
    let state =
        if state == 0 { PrintState::OUT }
    else if state == 1 { PrintState::IN }
    else { PrintState :: DISPLAY };
    let mut w = unsafe { std::fs::File::from_raw_fd(ufd) };
    print_ptr_rec(&mut w, x, state);
    w.flush();
    w.into_raw_fd();
    0
}
#[no_mangle]
pub extern "C" fn s_open_read(fname: ptr) -> ptr {
    let s_fname = ptr_string_to_str(fname);
    let port = std::fs::File::open(s_fname).expect("opened");
    let fd = port.into_raw_fd();
    shift(fd)
}
#[no_mangle]
pub extern "C" fn s_read_char(fd: ptr) -> ptr {
    let ufd = unshift(fd) as i32;
    let mut w = unsafe { std::fs::File::from_raw_fd(ufd) };
    let mut b = [0; 1];
    w.read_exact(&mut b);
    let v = if b[0] == 0 { eof_obj }
        else { ((b[0] as u32) << char_shift) | char_tag };
    w.into_raw_fd();
    v
}
#[no_mangle]
pub extern "C" fn s_close(fd: ptr) -> ptr {
    let ufd = unshift(fd) as i32;
    let w = unsafe { std::fs::File::from_raw_fd(ufd) };
    std::mem::drop(w);
    shift(0)
}

#[no_mangle]
pub extern "C" fn heap_alloc(mem: *mut memory, _stack: *mut c_char, size: usize) -> *mut c_char {
    let heap_next = unsafe { (*mem).heap_next };
    let heap_new = unsafe { heap_next.offset(size as isize) };
    if heap_new >= unsafe { (*mem).heap_top } {
        eprintln!("Exception: overflow");
        std::process::exit(0);
    }
    unsafe {(*mem).heap_next = heap_new};
    return heap_next;
}

fn allocate_protected_space(size: usize) -> *mut c_char {
    let mut v = Vec::with_capacity(size);
    let ptr = v.as_mut_ptr();
    std::mem::forget(v);
    ptr
}

fn deallocate_protected_space(p: *mut c_char, size: usize) {
    unsafe { std::mem::drop(Vec::from_raw_parts(p, 0, size)) };
}

fn main() {
    let stack_size = 16 * 4096;
    let heap_size = 4 * 16 * 4096;
    let global_size = 16 * 4096;
    let scratch_size = 16 * 4096;

    let stack_top = allocate_protected_space(stack_size);
    let stack_base = unsafe { stack_top.offset(stack_size as isize) };

    let heap = allocate_protected_space(heap_size);
    let global = allocate_protected_space(global_size);
    let scratch = allocate_protected_space(scratch_size);

    let uninit = 0 as (*mut std::os::raw::c_void);

    let mut ctxt = context {
        eax : uninit,
        ebx : uninit,
        ecx : uninit,
        edx : uninit,
        esi : uninit,
        edi : uninit,
        ebp : uninit,
        esp : uninit,
    };

    let heap_top = unsafe { heap.offset((heap_size as isize)/2) };
    let mut mem = memory {
        heap_next : heap,
        global_next : global,
        heap_base : heap,
        heap_top : heap_top,
        heap_base_alt : heap_top,
        heap_top_alt : unsafe { heap.offset(heap_size as isize) },
        global_base : global,
        stack_base : stack_base,
        scratch_base : scratch,
        edi : 0
    };

    let r = unsafe {
        scheme_entry(&mut ctxt, stack_base, &mut mem)
    };
    print_ptr(r);

    deallocate_protected_space(stack_top, stack_size);
    deallocate_protected_space(heap, stack_size);
}
<commit_msg>commit some clippy changes<commit_after>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

#![allow(unused_must_use)]

include!("bindings.rs");

use std::os::raw::c_char;
use std::io::Write;
use std::os::unix::io::FromRawFd;
use std::os::unix::io::IntoRawFd;
use std::io::Read;

#[derive(PartialEq)]
enum PrintState {
    OUT,
    IN,
    DISPLAY
}

fn print_ptr_rec<W: Write>(port: &mut W, p: ptr, state: PrintState) {
    let x = p as u32;
    if  (x & fx_mask) == fx_tag {
        write!(port, "{}", (x as i32) >> fx_shift);
    } else if x == bool_f {
        write!(port, "#f");
    } else if x == bool_t {
        write!(port, "#t");
    } else if x == list_nil {
        write!(port, "()");
    } else if x == eof_obj {
        write!(port, "#!eof");
    } else if (x & char_mask) == char_tag {
        let c = std::char::from_u32(x >> char_shift).
            expect("a char");
        if state == PrintState::DISPLAY {
            write!(port, "{}", c);
        } else {
            if      c == '\t' { write!(port, "#\\tab"); }
            else if c == '\n' { write!(port, "#\\newline"); }
            else if c == '\r' { write!(port, "#\\return"); }
            else if c == ' '  { write!(port, "#\\space"); }
            else              { write!(port, "#\\{}", c); }
        }
    } else if (x & obj_mask) == pair_tag {
        if state == PrintState::OUT { write!(port, "("); }
        let cell = unsafe { *((x-pair_tag) as *const cell) };
        let car = cell.car;
        print_ptr_rec(port, car, PrintState::OUT);
        let cdr = cell.cdr;
        if cdr != list_nil {
            if (cdr & obj_mask) != pair_tag {
                write!(port, " . ");
                print_ptr_rec(port, cdr, PrintState::OUT);
            } else {
                write!(port, " ");
                print_ptr_rec(port, cdr, PrintState::IN);
            }
        }
        if state == PrintState::OUT { write!(port, ")"); }
    } else if (x & obj_mask) == vector_tag {
        write!(port, "#(");
        unsafe {
        let p = &*((x-vector_tag) as *const vector);
        let n = (p.length as i32) >> fx_shift;
        for i in 0..n {
            if i > 0 { write!(port, " "); }
            print_ptr_rec(port,
                *((p.buf.as_ptr()).add(i as usize)),
                PrintState::OUT)
        }}
        write!(port, ")");
    } else if (x & obj_mask) == string_tag {
        if state == PrintState::OUT { write!(port, "\""); }
        unsafe {
        let p = &*((x-string_tag) as *const string);
        let n = (p.length as i32) >> fx_shift;
        for i in 0..n {
            let c = std::char::from_u32(*((p.buf.as_ptr()).add(i as usize)) as u32)
                .expect("char");
            if c == '"'       { write!(port, "\\\""); }
            else if c == '\\' { write!(port, "\\\\"); }
            else              { write!(port, "{}", c); }
        }}
        if state == PrintState::OUT { write!(port, "\""); }
    } else if (x & obj_mask) == symbol_tag {
        print_ptr_rec(port, (x - symbol_tag) | string_tag, PrintState::IN);
    } else if (x & obj_mask) == closure_tag {
        write!(port, "#<procedure>");
    } else {
        write!(port, "#<unknown 0x{:x}>", x);
    }
}
fn print_ptr(x: ptr) {
    print_ptr_rec(&mut std::io::stdout(), x, PrintState::OUT);
    println!();
}

fn eprint_ptr(msg: ptr, state: PrintState) {
    print_ptr_rec(&mut std::io::stderr(), msg, state);
}

#[no_mangle]
pub extern "C" fn ik_log(msg: ptr) -> ptr {
    eprint!("log: ");
    eprint_ptr(msg, PrintState::IN);
    eprintln!();
    0
}
#[no_mangle]
pub extern "C" fn ik_error(x: ptr) {
    eprint!("Exception");
    if (x & obj_mask) == pair_tag {
        let cell = unsafe { *((x-pair_tag) as *const cell) };
        let caller = cell.car;
        let msg = cell.cdr;
        if caller != bool_f {
            eprint!(" in ");
            eprint_ptr(caller, PrintState::OUT);
        }
        eprint!(": ");
        eprint_ptr(msg, PrintState::IN);
    }
    eprintln!();
    std::process::exit(0);
}

fn unshift(x: ptr) -> i32 {
    (x as i32) >> fx_shift
}
fn shift(x: i32) -> ptr {
    (x << fx_shift) as u32
}
fn ptr_string_to_str(x: ptr) -> String {
    unsafe {
        let p = &*((x-string_tag) as *const string);
        let n = unshift(p.length) as usize;
        let mut v = Vec::with_capacity(n);
        for i in 0..n {
            v.push(*(p.buf.as_ptr().add(i as usize)) as u8);
        }
        std::ffi::CString::from_vec_unchecked(v).into_string().expect("string")
    }
}
#[no_mangle]
pub extern "C" fn s_write(fd: ptr, str: ptr, len: ptr) -> ptr {
    let s = ptr_string_to_str(str);
    let len = unshift(len) as usize;
    let s: String = s.chars().take(len).collect();
    let ufd = unshift(fd) as i32;
    let mut w = unsafe { std::fs::File::from_raw_fd(ufd) };
    write!(w, "{}", s);
    w.flush();
    w.into_raw_fd();
    shift(s.len() as i32)
}
#[no_mangle]
pub extern "C" fn s_open_write(fname: ptr) -> ptr {
    let s_fname = ptr_string_to_str(fname);
    let port = std::fs::File::create(s_fname).expect("created");
    let fd = port.into_raw_fd();
    shift(fd)
}
#[no_mangle]
pub extern "C" fn s_fflush(fd: ptr) -> ptr {
    let ufd = unshift(fd) as i32;
    let mut w = unsafe { std::fs::File::from_raw_fd(ufd) };
    w.flush();
    w.into_raw_fd();
    0
}
#[no_mangle]
pub extern "C" fn scheme_write(fd: ptr, x: ptr, opt: ptr) -> ptr {
    let ufd = unshift(fd) as i32;
    let state = unshift(opt);
    let state =
        if state == 0 { PrintState::OUT }
    else if state == 1 { PrintState::IN }
    else { PrintState :: DISPLAY };
    let mut w = unsafe { std::fs::File::from_raw_fd(ufd) };
    print_ptr_rec(&mut w, x, state);
    w.flush();
    w.into_raw_fd();
    0
}
#[no_mangle]
pub extern "C" fn s_open_read(fname: ptr) -> ptr {
    let s_fname = ptr_string_to_str(fname);
    let port = std::fs::File::open(s_fname).expect("opened");
    let fd = port.into_raw_fd();
    shift(fd)
}
#[no_mangle]
pub extern "C" fn s_read_char(fd: ptr) -> ptr {
    let ufd = unshift(fd) as i32;
    let mut w = unsafe { std::fs::File::from_raw_fd(ufd) };
    let mut b = [0; 1];
    w.read_exact(&mut b);
    let v = if b[0] == 0 { eof_obj }
        else { ((b[0] as u32) << char_shift) | char_tag };
    w.into_raw_fd();
    v
}
#[no_mangle]
pub extern "C" fn s_close(fd: ptr) -> ptr {
    let ufd = unshift(fd) as i32;
    let w = unsafe { std::fs::File::from_raw_fd(ufd) };
    std::mem::drop(w);
    shift(0)
}

#[no_mangle]
pub extern "C" fn heap_alloc(mem: *mut memory, _stack: *mut c_char, size: usize) -> *mut c_char {
    let heap_next = unsafe {*mem}.heap_next;
    let heap_new = unsafe { heap_next.add(size) };
    if heap_new >= unsafe {*mem}.heap_top {
        eprintln!("Exception: overflow");
        std::process::exit(0);
    }
    unsafe {(*mem).heap_next = heap_new};
    return heap_next;
}

fn allocate_protected_space(size: usize) -> *mut c_char {
    let mut v = Vec::with_capacity(size);
    let ptr = v.as_mut_ptr();
    std::mem::forget(v);
    ptr
}

fn deallocate_protected_space(p: *mut c_char, size: usize) {
    unsafe { std::mem::drop(Vec::from_raw_parts(p, 0, size)) };
}

fn main() {
    let stack_size = 16 * 4096;
    let heap_size = 4 * 16 * 4096;
    let global_size = 16 * 4096;
    let scratch_size = 16 * 4096;

    let stack_top = allocate_protected_space(stack_size);
    let stack_base = unsafe { stack_top.add(stack_size) };

    let heap = allocate_protected_space(heap_size);
    let global = allocate_protected_space(global_size);
    let scratch = allocate_protected_space(scratch_size);

    let uninit = 0 as (*mut std::os::raw::c_void);

    let mut ctxt = context {
        eax : uninit,
        ebx : uninit,
        ecx : uninit,
        edx : uninit,
        esi : uninit,
        edi : uninit,
        ebp : uninit,
        esp : uninit,
    };

    let heap_top = unsafe { heap.add(heap_size/2) };
    let mut mem = memory {
        heap_next : heap,
        global_next : global,
        heap_base : heap,
        heap_top : heap_top,
        heap_base_alt : heap_top,
        heap_top_alt : unsafe { heap.add(heap_size) },
        global_base : global,
        stack_base : stack_base,
        scratch_base : scratch,
        edi : 0
    };

    let r = unsafe {
        scheme_entry(&mut ctxt, stack_base, &mut mem)
    };
    print_ptr(r);

    deallocate_protected_space(stack_top, stack_size);
    deallocate_protected_space(heap, stack_size);
}
<|endoftext|>


<commit_before>use std;
use std::env;
use std::fs;
use std::path::PathBuf;
use command_line_arguments::CommandLineArguments;
use datetime::system_time_to_date_time;
use hostname;
use qork;
use slog::Logger;
use xdg::BaseDirectories;

// The complete execution context of Qork.
pub struct Context {
    logger: Logger,
    // The raw command line arguments.
    args: Vec<String>,
    // Parsed form of the arguments.
    command_line_arguments: CommandLineArguments,
    exe_path: Option<PathBuf>,
    exe_meta_data: Option<fs::Metadata>,
    hostname: Option<String>,
    // xdg base dir object, typically '~/.config/qork', with a default profile of
    // 'default', which means the effective directory is '~/.config/qork/default'
    xdg: BaseDirectories,
    // TODO: system_type, user_name
}

/*
fn get_config_directory(logger: &Logger, args: &CommandLineArguments) -> PathBuf {
    const CONFIG_DIR_KEY : &'static str = "config_dir";
    const CONFIG_DIR : &'static str = ".qork.d";

    // Command line has highest priority.
    if let &Some(ref cd) = args.config_dir() {
        info!(logger, "Configuration Directory set from command line argument"; CONFIG_DIR_KEY => &cd);
        return PathBuf::from(&cd);
    }

    // Next is an environment variable.
    if let Ok(env_var) = std::env::var("QORK_CONFIG_DIR") {
        if !env_var.is_empty() {
            info!(logger, "Configuration Directory determined from QORK_CONFIG_DIR environment variable"; CONFIG_DIR_KEY => &env_var);
            return PathBuf::from(env_var);
        }
    }

    // If still no luck, try for '.qork.d' in the user's home directory - if we can
    // determine the user's home directory, that is.
    if let Some(mut home_dir) = env::home_dir() {
        home_dir.push(CONFIG_DIR);
        info!(logger, "Configuration Directory defaulted to '{}' in user's home directory", CONFIG_DIR; CONFIG_DIR_KEY => %&home_dir.display());
        return home_dir;
    }

    // Still stuck? Try .qork.d in the exe's directroy.
    if let Ok(mut exe_path) = std::env::current_exe() {
        exe_path.pop();
        exe_path.push(CONFIG_DIR);
        info!(logger, "Configuration Directory defaulted to '{}' in directory of the exe", CONFIG_DIR; CONFIG_DIR_KEY => %&exe_path.display());
        return exe_path;
    }

    // Last, just default to .qork.d in the current working directory.
    warn!(logger, "Unable to determine Configuration Directory from command line parameter, home dir, or exe dir: defaulting to '{}' in the current working directory", CONFIG_DIR;
        CONFIG_DIR_KEY => CONFIG_DIR);
    PathBuf::from(CONFIG_DIR)
}
*/

impl Context {
    pub fn new(logger: Logger, args: CommandLineArguments) -> Context {
        let exe = std::env::current_exe().ok();
        let md = exe.as_ref().and_then(|e| e.metadata().ok());
        let profile = args.xdg_profile().as_ref().unwrap();
        let bd = BaseDirectories::with_profile(qork::APP_NAME, profile).unwrap();

        Context {
            logger: logger,
            args: std::env::args().collect(),
            exe_path: exe,
            exe_meta_data: md,
            hostname: hostname::get_hostname(),
            command_line_arguments: args,
            xdg: bd
        }
    }

    pub fn logger(&self) -> &Logger {
        &self.logger
    }

    pub fn args(&self) -> &Vec<String> {
        &self.args
    }

    pub fn command_line_arguments(&self) -> &CommandLineArguments {
        &self.command_line_arguments
    }

    pub fn exe_path(&self) -> &Option<PathBuf> {
        &self.exe_path
    }

    pub fn exe_meta_data(&self) -> &Option<fs::Metadata> {
        &self.exe_meta_data
    }

    pub fn hostname(&self) -> &Option<String> {
        &self.hostname
    }

    pub fn xdg(&self) -> &BaseDirectories {
        &self.xdg
    }

    pub fn version(&self) -> &'static str {
        qork::VERSION
    }

    pub fn log_created_message(&self) -> () {
        let p = self.exe_path.as_ref()
            .and_then(|p| p.to_str())
            .unwrap_or("unknown");

        let bytes = self.exe_meta_data.as_ref()
            .map(|m| m.len().to_string())
            .unwrap_or("unknown".to_string());

        let mdate = self.exe_meta_data.as_ref()
            .and_then(|md| md.modified().ok())
            .map(|md| system_time_to_date_time(md))
            .map(|md| md.format("%Y-%m-%d %H:%M:%S%.3f UTC").to_string())
            .unwrap_or("unknown".to_string());

        info!(self.logger, "Created Context";
               "config_directory" => %&self.xdg.get_config_home().display(),
               "version" => self.version(),
               "hostname" => &self.hostname,
               "exe_modified" => mdate,
               "exe_bytes" => bytes,
               "exe_path" => p
         );
    }
}<commit_msg>Add command line option to set the XDG profile name.<commit_after>use std;
use std::env;
use std::fs;
use std::path::PathBuf;
use command_line_arguments::CommandLineArguments;
use datetime::system_time_to_date_time;
use hostname;
use qork;
use slog::Logger;
use xdg::BaseDirectories;

// The complete execution context of Qork.
pub struct Context {
    logger: Logger,
    // The raw command line arguments.
    args: Vec<String>,
    // Parsed form of the arguments.
    command_line_arguments: CommandLineArguments,
    exe_path: Option<PathBuf>,
    exe_meta_data: Option<fs::Metadata>,
    hostname: Option<String>,
    // xdg base dir object, typically '~/.config/qork', with a default profile of
    // 'default', which means the effective directory is '~/.config/qork/default'
    xdg: BaseDirectories,
    // TODO: system_type, user_name
}

impl Context {
    pub fn new(logger: Logger, args: CommandLineArguments) -> Context {
        let exe = std::env::current_exe().ok();
        let md = exe.as_ref().and_then(|e| e.metadata().ok());

        let profile = {
            match args.xdg_profile()
            {
                &Some(ref p) => { p.clone().to_string() },
                &None => "default".to_string()
            }
        };

        let bd = BaseDirectories::with_profile(qork::APP_NAME, profile).unwrap();

        Context {
            logger: logger,
            args: std::env::args().collect(),
            exe_path: exe,
            exe_meta_data: md,
            hostname: hostname::get_hostname(),
            command_line_arguments: args,
            xdg: bd
        }
    }

    pub fn logger(&self) -> &Logger {
        &self.logger
    }

    pub fn args(&self) -> &Vec<String> {
        &self.args
    }

    pub fn command_line_arguments(&self) -> &CommandLineArguments {
        &self.command_line_arguments
    }

    pub fn exe_path(&self) -> &Option<PathBuf> {
        &self.exe_path
    }

    pub fn exe_meta_data(&self) -> &Option<fs::Metadata> {
        &self.exe_meta_data
    }

    pub fn hostname(&self) -> &Option<String> {
        &self.hostname
    }

    pub fn xdg(&self) -> &BaseDirectories {
        &self.xdg
    }

    pub fn version(&self) -> &'static str {
        qork::VERSION
    }

    pub fn log_created_message(&self) -> () {
        let p = self.exe_path.as_ref()
            .and_then(|p| p.to_str())
            .unwrap_or("unknown");

        let bytes = self.exe_meta_data.as_ref()
            .map(|m| m.len().to_string())
            .unwrap_or("unknown".to_string());

        let mdate = self.exe_meta_data.as_ref()
            .and_then(|md| md.modified().ok())
            .map(|md| system_time_to_date_time(md))
            .map(|md| md.format("%Y-%m-%d %H:%M:%S%.3f UTC").to_string())
            .unwrap_or("unknown".to_string());

        info!(self.logger, "Created Context";
               "config_directory" => %&self.xdg.get_config_home().display(),
               "version" => self.version(),
               "hostname" => &self.hostname,
               "exe_modified" => mdate,
               "exe_bytes" => bytes,
               "exe_path" => p
         );
    }
}<|endoftext|>