<commit_before>//! Shared settings module.
//!
//! This module defines data structures to access the settings defined in the meta language.
//!
//! Each settings group is translated to a `Flags` struct either in this module or in its
//! ISA-specific `settings` module. The struct provides individual getter methods for all of the
//! settings as well as computed predicate flags.
//!
//! The `Flags` struct is immutable once it has been created. A `Builder` instance is used to
//! create it.
//!
//! # Example
//! ```
//! use cretonne::settings::{self, Configurable};
//!
//! let mut b = settings::builder();
//! b.set("opt_level", "fastest");
//!
//! let f = settings::Flags::new(&b);
//! assert_eq!(f.opt_level(), settings::OptLevel::Fastest);
//! ```

use std::fmt;
use std::result;

use constant_hash::{probe, simple_hash};

/// A string-based configurator for settings groups.
///
/// The `Configurable` protocol allows settings to be modified by name before a finished `Flags`
/// struct is created.
pub trait Configurable {
    /// Set the string value of any setting by name.
    ///
    /// This can set any type of setting whether it is numeric, boolean, or enumerated.
    fn set(&mut self, name: &str, value: &str) -> Result<()>;

    /// Set the value of a boolean setting by name.
    ///
    /// If the identified setting isn't a boolean, a `BadType` error is returned.
    fn set_bool(&mut self, name: &str, value: bool) -> Result<()>;
}

/// Collect settings values based on a template.
pub struct Builder {
    template: &'static detail::Template,
    bytes: Vec<u8>,
}

impl Builder {
    /// Create a new builder with defaults and names from the given template.
    pub fn new(tmpl: &'static detail::Template) -> Builder {
        Builder {
            template: tmpl,
            bytes: tmpl.defaults.into(),
        }
    }

    /// Extract contents of builder once everything is configured.
    pub fn state_for(&self, name: &str) -> &[u8] {
        assert_eq!(name, self.template.name);
        &self.bytes[..]
    }

    /// Set the value of a single bit.
    fn set_bit(&mut self, offset: usize, bit: u8, value: bool) {
        let byte = &mut self.bytes[offset];
        let mask = 1 << bit;
        if value {
            *byte |= mask;
        } else {
            *byte &= !mask;
        }
    }

    /// Look up a descriptor by name.
    fn lookup(&self, name: &str) -> Result<(usize, detail::Detail)> {
        match probe(self.template, name, simple_hash(name)) {
            None => Err(Error::BadName),
            Some(entry) => {
                let d = &self.template.descriptors[self.template.hash_table[entry] as usize];
                Ok((d.offset as usize, d.detail))
            }
        }
    }
}

fn parse_bool_value(value: &str) -> Result<bool> {
    match value {
        "true" | "on" | "yes" | "1" => Ok(true),
        "false" | "off" | "no" | "0" => Ok(false),
        _ => Err(Error::BadValue),
    }
}

fn parse_enum_value(value: &str, choices: &[&str]) -> Result<u8> {
    match choices.iter().position(|&tag| tag == value) {
        Some(idx) => Ok(idx as u8),
        None => Err(Error::BadValue),
    }
}

impl Configurable for Builder {
    fn set_bool(&mut self, name: &str, value: bool) -> Result<()> {
        use self::detail::Detail;
        let (offset, detail) = self.lookup(name)?;
        if let Detail::Bool { bit } = detail {
            self.set_bit(offset, bit, value);
            Ok(())
        } else {
            Err(Error::BadType)
        }
    }

    fn set(&mut self, name: &str, value: &str) -> Result<()> {
        use self::detail::Detail;
        let (offset, detail) = self.lookup(name)?;
        match detail {
            Detail::Bool { bit } => {
                self.set_bit(offset, bit, parse_bool_value(value))?;
            }
            Detail::Num => {
                self.bytes[offset] = value.parse().map_err(|_| Error::BadValue)?;
            }
            Detail::Enum { last, enumerators } => {
                self.bytes[offset] = parse_enum_value(value,
                                                      self.template.enums(last, enumerators))?;
            }
        }
        Ok(())
    }
}

/// An error produced when changing a setting.
#[derive(Debug, PartialEq, Eq)]
pub enum Error {
    /// No setting by this name exists.
    BadName,

    /// Type mismatch for setting (e.g., setting an enum setting as a bool).
    BadType,

    /// This is not a valid value for this setting.
    BadValue,
}

/// A result returned when changing a setting.
pub type Result<T> = result::Result<T, Error>;

/// Implementation details for generated code.
///
/// This module holds definitions that need to be public so the can be instantiated by generated
/// code in other modules.
pub mod detail {
    use std::fmt;
    use constant_hash;

    /// An instruction group template.
    pub struct Template {
        /// Name of the instruction group.
        pub name: &'static str,
        /// List of setting descriptors.
        pub descriptors: &'static [Descriptor],
        /// Union of all enumerators.
        pub enumerators: &'static [&'static str],
        /// Hash table of settings.
        pub hash_table: &'static [u16],
        /// Default values.
        pub defaults: &'static [u8],
    }

    impl Template {
        /// Get enumerators corresponding to a `Details::Enum`.
        pub fn enums(&self, last: u8, enumerators: u16) -> &[&'static str] {
            let from = enumerators as usize;
            let len = last as usize + 1;
            &self.enumerators[from..from + len]
        }

        /// Format a setting value as a TOML string. This is mostly for use by the generated
        /// `Display` implementation.
        pub fn format_toml_value(&self,
                                 detail: Detail,
                                 byte: u8,
                                 f: &mut fmt::Formatter)
                                 -> fmt::Result {
            match detail {
                Detail::Bool { bit } => write!(f, "{}", (byte & (1 << bit)) != 0),
                Detail::Num => write!(f, "{}", byte),
                Detail::Enum { last, enumerators } => {
                    if byte <= last {
                        let tags = self.enums(last, enumerators);
                        write!(f, "\"{}\"", tags[byte as usize])
                    } else {
                        write!(f, "{}", byte)
                    }
                }
            }
        }
    }

    /// The template contains a hash table for by-name lookup.
    impl<'a> constant_hash::Table<&'a str> for Template {
        fn len(&self) -> usize {
            self.hash_table.len()
        }

        fn key(&self, idx: usize) -> Option<&'a str> {
            let e = self.hash_table[idx] as usize;
            if e < self.descriptors.len() {
                Some(self.descriptors[e].name)
            } else {
                None
            }
        }
    }

    /// A setting descriptor holds the information needed to generically set and print a setting.
    ///
    /// Each settings group will be represented as a constant DESCRIPTORS array.
    pub struct Descriptor {
        /// Lower snake-case name of setting as defined in meta.
        pub name: &'static str,

        /// Offset of byte containing this setting.
        pub offset: u32,

        /// Additional details, depending on the kind of setting.
        pub detail: Detail,
    }

    /// The different kind of settings along with descriptor bits that depend on the kind.
    #[derive(Clone, Copy)]
    pub enum Detail {
        /// A boolean setting only uses one bit, numbered from LSB.
        Bool {
            /// 0-7.
            bit: u8,
        },

        /// A numerical setting uses the whole byte.
        Num,

        /// An Enum setting uses a range of enumerators.
        Enum {
            /// Numerical value of last enumerator, allowing for 1-256 enumerators.
            last: u8,

            /// First enumerator in the ENUMERATORS table.
            enumerators: u16,
        },
    }
}

// Include code generated by `meta/gen_settings.py`. This file contains a public `Flags` struct
// with an impl for all of the settings defined in `meta/cretonne/settings.py`.
include!(concat!(env!("OUT_DIR"), "/settings.rs"));

#[cfg(test)]
mod tests {
    use super::{builder, Flags};
    use super::Error::*;
    use super::Configurable;

    #[test]
    fn display_default() {
        let b = builder();
        let f = Flags::new(&b);
        assert_eq!(f.to_string(),
                   "[shared]\n\
                    opt_level = \"default\"\n\
                    is_64bit = false\n\
                    is_compressed = false\n\
                    enable_float = true\n\
                    enable_simd = true\n\
                    enable_atomics = true\n");
        assert_eq!(f.opt_level(), super::OptLevel::Default);
        assert_eq!(f.enable_simd(), true);
    }

    #[test]
    fn modify_bool() {
        let mut b = builder();
        assert_eq!(b.set_bool("not_there", true), Err(BadName));
        assert_eq!(b.set_bool("enable_simd", true), Ok(()));
        assert_eq!(b.set_bool("enable_simd", false), Ok(()));

        let f = Flags::new(&b);
        assert_eq!(f.enable_simd(), false);
    }

    #[test]
    fn modify_string() {
        let mut b = builder();
        assert_eq!(b.set("not_there", "true"), Err(BadName));
        assert_eq!(b.set("enable_simd", ""), Err(BadValue));
        assert_eq!(b.set("enable_simd", "best"), Err(BadValue));
        assert_eq!(b.set("opt_level", "true"), Err(BadValue));
        assert_eq!(b.set("opt_level", "best"), Ok(()));
        assert_eq!(b.set("enable_simd", "0"), Ok(()));

        let f = Flags::new(&b);
        assert_eq!(f.enable_simd(), false);
        assert_eq!(f.opt_level(), super::OptLevel::Best);
    }
}
<commit_msg>Fixes error on propagating a Result<()> with the `?` operator<commit_after>//! Shared settings module.
//!
//! This module defines data structures to access the settings defined in the meta language.
//!
//! Each settings group is translated to a `Flags` struct either in this module or in its
//! ISA-specific `settings` module. The struct provides individual getter methods for all of the
//! settings as well as computed predicate flags.
//!
//! The `Flags` struct is immutable once it has been created. A `Builder` instance is used to
//! create it.
//!
//! # Example
//! ```
//! use cretonne::settings::{self, Configurable};
//!
//! let mut b = settings::builder();
//! b.set("opt_level", "fastest");
//!
//! let f = settings::Flags::new(&b);
//! assert_eq!(f.opt_level(), settings::OptLevel::Fastest);
//! ```

use std::fmt;
use std::result;

use constant_hash::{probe, simple_hash};

/// A string-based configurator for settings groups.
///
/// The `Configurable` protocol allows settings to be modified by name before a finished `Flags`
/// struct is created.
pub trait Configurable {
    /// Set the string value of any setting by name.
    ///
    /// This can set any type of setting whether it is numeric, boolean, or enumerated.
    fn set(&mut self, name: &str, value: &str) -> Result<()>;

    /// Set the value of a boolean setting by name.
    ///
    /// If the identified setting isn't a boolean, a `BadType` error is returned.
    fn set_bool(&mut self, name: &str, value: bool) -> Result<()>;
}

/// Collect settings values based on a template.
pub struct Builder {
    template: &'static detail::Template,
    bytes: Vec<u8>,
}

impl Builder {
    /// Create a new builder with defaults and names from the given template.
    pub fn new(tmpl: &'static detail::Template) -> Builder {
        Builder {
            template: tmpl,
            bytes: tmpl.defaults.into(),
        }
    }

    /// Extract contents of builder once everything is configured.
    pub fn state_for(&self, name: &str) -> &[u8] {
        assert_eq!(name, self.template.name);
        &self.bytes[..]
    }

    /// Set the value of a single bit.
    fn set_bit(&mut self, offset: usize, bit: u8, value: bool) {
        let byte = &mut self.bytes[offset];
        let mask = 1 << bit;
        if value {
            *byte |= mask;
        } else {
            *byte &= !mask;
        }
    }

    /// Look up a descriptor by name.
    fn lookup(&self, name: &str) -> Result<(usize, detail::Detail)> {
        match probe(self.template, name, simple_hash(name)) {
            None => Err(Error::BadName),
            Some(entry) => {
                let d = &self.template.descriptors[self.template.hash_table[entry] as usize];
                Ok((d.offset as usize, d.detail))
            }
        }
    }
}

fn parse_bool_value(value: &str) -> Result<bool> {
    match value {
        "true" | "on" | "yes" | "1" => Ok(true),
        "false" | "off" | "no" | "0" => Ok(false),
        _ => Err(Error::BadValue),
    }
}

fn parse_enum_value(value: &str, choices: &[&str]) -> Result<u8> {
    match choices.iter().position(|&tag| tag == value) {
        Some(idx) => Ok(idx as u8),
        None => Err(Error::BadValue),
    }
}

impl Configurable for Builder {
    fn set_bool(&mut self, name: &str, value: bool) -> Result<()> {
        use self::detail::Detail;
        let (offset, detail) = self.lookup(name)?;
        if let Detail::Bool { bit } = detail {
            self.set_bit(offset, bit, value);
            Ok(())
        } else {
            Err(Error::BadType)
        }
    }

    fn set(&mut self, name: &str, value: &str) -> Result<()> {
        use self::detail::Detail;
        let (offset, detail) = self.lookup(name)?;
        match detail {
            Detail::Bool { bit } => {
                // Cannot currently propagate Result<()> up on functions returning ()
                // with the `?` operator
                self.set_bit(offset, bit, parse_bool_value(value)?);
            }
            Detail::Num => {
                self.bytes[offset] = value.parse().map_err(|_| Error::BadValue)?;
            }
            Detail::Enum { last, enumerators } => {
                self.bytes[offset] = parse_enum_value(value,
                                                      self.template.enums(last, enumerators))?;
            }
        }
        Ok(())
    }
}

/// An error produced when changing a setting.
#[derive(Debug, PartialEq, Eq)]
pub enum Error {
    /// No setting by this name exists.
    BadName,

    /// Type mismatch for setting (e.g., setting an enum setting as a bool).
    BadType,

    /// This is not a valid value for this setting.
    BadValue,
}

/// A result returned when changing a setting.
pub type Result<T> = result::Result<T, Error>;

/// Implementation details for generated code.
///
/// This module holds definitions that need to be public so the can be instantiated by generated
/// code in other modules.
pub mod detail {
    use std::fmt;
    use constant_hash;

    /// An instruction group template.
    pub struct Template {
        /// Name of the instruction group.
        pub name: &'static str,
        /// List of setting descriptors.
        pub descriptors: &'static [Descriptor],
        /// Union of all enumerators.
        pub enumerators: &'static [&'static str],
        /// Hash table of settings.
        pub hash_table: &'static [u16],
        /// Default values.
        pub defaults: &'static [u8],
    }

    impl Template {
        /// Get enumerators corresponding to a `Details::Enum`.
        pub fn enums(&self, last: u8, enumerators: u16) -> &[&'static str] {
            let from = enumerators as usize;
            let len = last as usize + 1;
            &self.enumerators[from..from + len]
        }

        /// Format a setting value as a TOML string. This is mostly for use by the generated
        /// `Display` implementation.
        pub fn format_toml_value(&self,
                                 detail: Detail,
                                 byte: u8,
                                 f: &mut fmt::Formatter)
                                 -> fmt::Result {
            match detail {
                Detail::Bool { bit } => write!(f, "{}", (byte & (1 << bit)) != 0),
                Detail::Num => write!(f, "{}", byte),
                Detail::Enum { last, enumerators } => {
                    if byte <= last {
                        let tags = self.enums(last, enumerators);
                        write!(f, "\"{}\"", tags[byte as usize])
                    } else {
                        write!(f, "{}", byte)
                    }
                }
            }
        }
    }

    /// The template contains a hash table for by-name lookup.
    impl<'a> constant_hash::Table<&'a str> for Template {
        fn len(&self) -> usize {
            self.hash_table.len()
        }

        fn key(&self, idx: usize) -> Option<&'a str> {
            let e = self.hash_table[idx] as usize;
            if e < self.descriptors.len() {
                Some(self.descriptors[e].name)
            } else {
                None
            }
        }
    }

    /// A setting descriptor holds the information needed to generically set and print a setting.
    ///
    /// Each settings group will be represented as a constant DESCRIPTORS array.
    pub struct Descriptor {
        /// Lower snake-case name of setting as defined in meta.
        pub name: &'static str,

        /// Offset of byte containing this setting.
        pub offset: u32,

        /// Additional details, depending on the kind of setting.
        pub detail: Detail,
    }

    /// The different kind of settings along with descriptor bits that depend on the kind.
    #[derive(Clone, Copy)]
    pub enum Detail {
        /// A boolean setting only uses one bit, numbered from LSB.
        Bool {
            /// 0-7.
            bit: u8,
        },

        /// A numerical setting uses the whole byte.
        Num,

        /// An Enum setting uses a range of enumerators.
        Enum {
            /// Numerical value of last enumerator, allowing for 1-256 enumerators.
            last: u8,

            /// First enumerator in the ENUMERATORS table.
            enumerators: u16,
        },
    }
}

// Include code generated by `meta/gen_settings.py`. This file contains a public `Flags` struct
// with an impl for all of the settings defined in `meta/cretonne/settings.py`.
include!(concat!(env!("OUT_DIR"), "/settings.rs"));

#[cfg(test)]
mod tests {
    use super::{builder, Flags};
    use super::Error::*;
    use super::Configurable;

    #[test]
    fn display_default() {
        let b = builder();
        let f = Flags::new(&b);
        assert_eq!(f.to_string(),
                   "[shared]\n\
                    opt_level = \"default\"\n\
                    is_64bit = false\n\
                    is_compressed = false\n\
                    enable_float = true\n\
                    enable_simd = true\n\
                    enable_atomics = true\n");
        assert_eq!(f.opt_level(), super::OptLevel::Default);
        assert_eq!(f.enable_simd(), true);
    }

    #[test]
    fn modify_bool() {
        let mut b = builder();
        assert_eq!(b.set_bool("not_there", true), Err(BadName));
        assert_eq!(b.set_bool("enable_simd", true), Ok(()));
        assert_eq!(b.set_bool("enable_simd", false), Ok(()));

        let f = Flags::new(&b);
        assert_eq!(f.enable_simd(), false);
    }

    #[test]
    fn modify_string() {
        let mut b = builder();
        assert_eq!(b.set("not_there", "true"), Err(BadName));
        assert_eq!(b.set("enable_simd", ""), Err(BadValue));
        assert_eq!(b.set("enable_simd", "best"), Err(BadValue));
        assert_eq!(b.set("opt_level", "true"), Err(BadValue));
        assert_eq!(b.set("opt_level", "best"), Ok(()));
        assert_eq!(b.set("enable_simd", "0"), Ok(()));

        let f = Flags::new(&b);
        assert_eq!(f.enable_simd(), false);
        assert_eq!(f.opt_level(), super::OptLevel::Best);
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::{io, io::prelude::*};
use std::collections::HashMap;

type Recipe<T> = HashMap<T, u32>;
type RecipeBook<T> = HashMap<T, (Recipe<T>, u32)>;

fn get_input() -> io::Result<String> {
  let mut file = File::open("14.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn parse_input(input: &str) -> RecipeBook<&str> {
  fn parse_ingredient(input: &str) -> Option<(&str, u32)> {
    let mut tokens = input.trim().split(" ");

    match (tokens.next(), tokens.next()) {
      (Some(amount), Some(id)) => {
        amount.parse::<u32>().ok()
        .map(|amount| (id, amount))
      },
      _ => None
    }
  }

  input.lines()
  .map(|line| line.split(" => "))
  .filter_map(|mut tokens| match (tokens.next(), tokens.next()) {
    (Some(ingredients), Some(outcome)) => {
      Some((ingredients.split(", "), outcome))
    },
    _ => None
  })
  .map(|(ingredients, outcome)| (ingredients.filter_map(parse_ingredient), parse_ingredient(outcome)))
  .filter_map(|(ingredients, outcome)| outcome.and_then(|outcome| {
    let ingredients = ingredients.collect::<HashMap<_, _>>();

    if ingredients.len() == 0 {
      return None;
    }

    Some((outcome.0, (ingredients, outcome.1)))
  }))
  .collect()
}

fn main() {
  let input = get_input().unwrap();
  let recipes = parse_input(&input);

  println!("{:?}", recipes);
}
<commit_msg>Add (wrong) day 14 solution<commit_after>use std::fs::File;
use std::{io, io::prelude::*};
use std::hash::Hash;
use std::fmt::Debug;
use std::collections::HashMap;

type Recipe<T> = Vec<(T, u32)>;
type RecipeBook<T> = HashMap<T, (Recipe<T>, u32)>;

fn get_input() -> io::Result<String> {
  let mut file = File::open("14.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn parse_input(input: &str) -> RecipeBook<&str> {
  fn parse_ingredient(input: &str) -> Option<(&str, u32)> {
    let mut tokens = input.trim().split(" ");

    match (tokens.next(), tokens.next()) {
      (Some(amount), Some(id)) => {
        amount.parse::<u32>().ok()
        .map(|amount| (id, amount))
      },
      _ => None
    }
  }

  input.lines()
  .map(|line| line.split(" => "))
  .filter_map(|mut tokens| match (tokens.next(), tokens.next()) {
    (Some(ingredients), Some(outcome)) => {
      Some((ingredients.split(", "), outcome))
    },
    _ => None
  })
  .map(|(ingredients, outcome)| (ingredients.filter_map(parse_ingredient), parse_ingredient(outcome)))
  .filter_map(|(ingredients, outcome)| outcome.and_then(|outcome| {
    let ingredients = ingredients.collect::<Recipe<_>>();

    if ingredients.len() == 0 {
      return None;
    }

    Some((outcome.0, (ingredients, outcome.1)))
  }))
  .collect()
}

fn get_base_ingredient_amount<T>(recipes: &RecipeBook<T>, ingredient: T, amount: u32, residues: &mut HashMap<T, u32>) -> u32
where T: Eq + Clone + Copy + Debug + Hash {
  let mut amount = amount;

  if let Some(residue) = residues.get_mut(&ingredient) {
    if *residue >= amount {
      amount = 0;
      *residue -= amount;
    } else {
      amount -= *residue;
      *residue = 0;
    }
  }

  if amount == 0 {
    return 0;
  }

  let result = match recipes.get(&ingredient) {
    None => amount,
    Some((subrecipe, yield_amount)) => {
      let n = ((amount as f64) / (*yield_amount as f64)).ceil() as u32;
      let residue = yield_amount * n - amount;

      let result = subrecipe.iter()
        .map(|&(ingredient, amount)| {
          get_base_ingredient_amount(recipes, ingredient, amount * n, residues)
        })
        .sum();

      if residue > 0 {
        let new_residue = residues.get(&ingredient).cloned().unwrap_or(0) + residue;
        residues.insert(ingredient, new_residue);
      }

      result
    }
  };

  result
}

fn main() {
  let input = get_input().unwrap();
  let recipes = parse_input(&input);

  let x = get_base_ingredient_amount(&recipes, "FUEL", 1, &mut HashMap::new());

  println!("{:?}", x);
}
<|endoftext|>


<commit_before>#![crate_type="staticlib"]
#![feature(alloc)]
#![feature(allocator)]
#![feature(arc_counts)]
#![feature(augmented_assignments)]
#![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(op_assign_traits)]
#![feature(unboxed_closures)]
#![feature(unsafe_no_drop_flag)]
#![feature(unwind_attributes)]
#![feature(vec_push_all)]
#![feature(zero_one)]
#![no_std]

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate collections;

use acpi::Acpi;

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::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_switch;

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

use syscall::handle::*;

/// Common std-like functionality
#[macro_use]
pub mod common;
/// ACPI
pub mod acpi;
/// Allocation
pub mod alloc_system;
/// Audio
pub mod audio;
/// Disk drivers
pub mod disk;
/// Various drivers
pub mod drivers;
/// Environment
pub mod env;
/// Externs
pub mod externs;
/// Filesystems
pub mod fs;
/// 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;

        for i in env().contexts.lock().iter() {
            if i.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 console = env().console.lock();
        console.instant = false;
    }

    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();
            console.instant = false;
            if console.draw && console.redraw {
                console.redraw = false;
                console.display.flip();
            }
        }

        unsafe { context_switch(false) };
    }
}

static BSS_TEST_ZERO: usize = 0;
static BSS_TEST_NONZERO: usize = usize::MAX;

/// Initialize kernel
unsafe fn init(font_data: usize, tss_data: usize) {
    // Zero BSS, this initializes statics that are set to 0
    {
        extern {
            static mut __bss_start: u8;
            static mut __bss_end: u8;
        }

        let start_ptr = &mut __bss_start;
        let end_ptr = &mut __bss_end;

        if start_ptr as *const _ as usize <= end_ptr as *const _ as usize {
            let size = end_ptr as *const _ as usize - start_ptr as *const _ as usize;
            memset(start_ptr, 0, size);
        }

        assert_eq!(BSS_TEST_ZERO, 0);
        assert_eq!(BSS_TEST_NONZERO, usize::MAX);
    }

    // Setup paging, this allows for memory allocation
    Page::init();
    memory::cluster_init();
    // Unmap first page to catch null pointer errors (after reading memory map)
    Page::new(0).unmap();

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

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

            debug!("Redox {} bits\n", mem::size_of::<usize>() * 8);

            if let Some(acpi) = Acpi::new() {
                env.schemes.push(UnsafeCell::new(acpi));
            }

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

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

            pci::pci_init(env);

            env.schemes.push(UnsafeCell::new(DebugScheme::new()));
            env.schemes.push(UnsafeCell::new(box ContextScheme));
            env.schemes.push(UnsafeCell::new(box InterruptScheme));
            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();
            });

            env.contexts.lock().enabled = true;

            if let Ok(mut resource) = Url::from_str("file:/schemes/").open() {
                let mut vec: Vec<u8> = Vec::new();
                let _ = 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);
                }

                execute(Url::from_str("file:/apps/login/main.bin"), 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.current() {
                    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 -15..16 {
                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 {
                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 {
                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) };
    }

    //Do not catch init interrupt
    if interrupt < 0xFF {
        env().interrupts.lock()[interrupt as usize] += 1;
    }

    match interrupt {
        0x20 => {
            {
                let mut clock_monotonic = env().clock_monotonic.lock();
                *clock_monotonic = *clock_monotonic + PIT_DURATION;
            }
            {
                let mut clock_realtime = env().clock_realtime.lock();
                *clock_realtime = *clock_realtime + PIT_DURATION;
            }

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

            if switch {
                unsafe { context_switch(true) };
            }
        }
        i @ 0x21 ... 0x2F => env().on_irq(i as u8 - 0x20),
        0x80 => if !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"),
        0x9 => exception!("Coprocessor Segment Overrun"), // legacy
        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>Do not iterate over context 0<commit_after>#![crate_type="staticlib"]
#![feature(alloc)]
#![feature(allocator)]
#![feature(arc_counts)]
#![feature(augmented_assignments)]
#![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(op_assign_traits)]
#![feature(unboxed_closures)]
#![feature(unsafe_no_drop_flag)]
#![feature(unwind_attributes)]
#![feature(vec_push_all)]
#![feature(zero_one)]
#![no_std]

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate collections;

use acpi::Acpi;

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::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_switch;

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

use syscall::handle::*;

/// Common std-like functionality
#[macro_use]
pub mod common;
/// ACPI
pub mod acpi;
/// Allocation
pub mod alloc_system;
/// Audio
pub mod audio;
/// Disk drivers
pub mod disk;
/// Various drivers
pub mod drivers;
/// Environment
pub mod env;
/// Externs
pub mod externs;
/// Filesystems
pub mod fs;
/// 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;

        for i in env().contexts.lock().iter().skip(1) {
            if i.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 console = env().console.lock();
        console.instant = false;
    }

    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();
            console.instant = false;
            if console.draw && console.redraw {
                console.redraw = false;
                console.display.flip();
            }
        }

        unsafe { context_switch(false) };
    }
}

static BSS_TEST_ZERO: usize = 0;
static BSS_TEST_NONZERO: usize = usize::MAX;

/// Initialize kernel
unsafe fn init(font_data: usize, tss_data: usize) {
    // Zero BSS, this initializes statics that are set to 0
    {
        extern {
            static mut __bss_start: u8;
            static mut __bss_end: u8;
        }

        let start_ptr = &mut __bss_start;
        let end_ptr = &mut __bss_end;

        if start_ptr as *const _ as usize <= end_ptr as *const _ as usize {
            let size = end_ptr as *const _ as usize - start_ptr as *const _ as usize;
            memset(start_ptr, 0, size);
        }

        assert_eq!(BSS_TEST_ZERO, 0);
        assert_eq!(BSS_TEST_NONZERO, usize::MAX);
    }

    // Setup paging, this allows for memory allocation
    Page::init();
    memory::cluster_init();
    // Unmap first page to catch null pointer errors (after reading memory map)
    Page::new(0).unmap();

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

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

            debug!("Redox {} bits\n", mem::size_of::<usize>() * 8);

            if let Some(acpi) = Acpi::new() {
                env.schemes.push(UnsafeCell::new(acpi));
            }

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

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

            pci::pci_init(env);

            env.schemes.push(UnsafeCell::new(DebugScheme::new()));
            env.schemes.push(UnsafeCell::new(box ContextScheme));
            env.schemes.push(UnsafeCell::new(box InterruptScheme));
            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();
            });

            env.contexts.lock().enabled = true;

            if let Ok(mut resource) = Url::from_str("file:/schemes/").open() {
                let mut vec: Vec<u8> = Vec::new();
                let _ = 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);
                }

                execute(Url::from_str("file:/apps/login/main.bin"), 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.current() {
                    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 -15..16 {
                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 {
                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 {
                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) };
    }

    //Do not catch init interrupt
    if interrupt < 0xFF {
        env().interrupts.lock()[interrupt as usize] += 1;
    }

    match interrupt {
        0x20 => {
            {
                let mut clock_monotonic = env().clock_monotonic.lock();
                *clock_monotonic = *clock_monotonic + PIT_DURATION;
            }
            {
                let mut clock_realtime = env().clock_realtime.lock();
                *clock_realtime = *clock_realtime + PIT_DURATION;
            }

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

            if switch {
                unsafe { context_switch(true) };
            }
        }
        i @ 0x21 ... 0x2F => env().on_irq(i as u8 - 0x20),
        0x80 => if !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"),
        0x9 => exception!("Coprocessor Segment Overrun"), // legacy
        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>#![crate_name="kernel"]
#![crate_type="staticlib"]
#![feature(alloc)]
#![feature(allocator)]
#![feature(arc_counts)]
#![feature(augmented_assignments)]
#![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(op_assign_traits)]
#![feature(unboxed_closures)]
#![feature(unsafe_no_drop_flag)]
#![feature(unwind_attributes)]
#![feature(vec_push_all)]
#![feature(zero_one)]
#![feature(collections_range)]
#![no_std]

#![allow(deprecated)]
#![deny(warnings)]

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate collections;

extern crate system;

use acpi::Acpi;

use alloc::boxed::Box;

use arch::context::{context_switch, Context};
use arch::memory;
use arch::paging::Page;
use arch::regs::Regs;
use arch::tss::TSS;

use collections::string::ToString;

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

use common::time::Duration;

use drivers::pci;
use drivers::io::{Io, Pio};
use drivers::ps2::*;
use drivers::rtc::*;
use drivers::serial::*;

use env::Environment;

use graphics::display;

use schemes::context::*;
use schemes::debug::*;
use schemes::display::*;
use schemes::interrupt::*;
use schemes::memory::*;
use schemes::test::*;

use syscall::execute::execute;
use syscall::{do_sys_chdir, do_sys_exit, do_sys_open, syscall_handle};

pub use system::externs::*;

/// Common std-like functionality
#[macro_use]
pub mod common;
#[macro_use]
pub mod macros;
/// Allocation
pub mod alloc_system;
/// ACPI
pub mod acpi;
/// Architecture dependant
pub mod arch;
/// Audio
pub mod audio;
/// Disk drivers
pub mod disk;
/// Various drivers
pub mod drivers;
/// Environment
pub mod env;
/// Filesystems
pub mod fs;
/// Various graphical methods
pub mod graphics;
/// Networking
pub mod network;
/// Panic
pub mod panic;
/// Schemes
pub mod schemes;
/// Synchronization
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: 4500572,
};

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

        let mut halt = true;

        for context in env().contexts.lock().iter().skip(1) {
            if ! context.blocked {
                halt = false;
                break;
            }
        }

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

extern {
    static mut __text_start: u8;
    static mut __text_end: u8;
    static mut __rodata_start: u8;
    static mut __rodata_end: u8;
    static mut __data_start: u8;
    static mut __data_end: u8;
    static mut __bss_start: u8;
    static mut __bss_end: u8;
}

static BSS_TEST_ZERO: usize = 0;
static BSS_TEST_NONZERO: usize = usize::MAX;

/// Initialize kernel
unsafe fn init(tss_data: usize) {

    // Test
    assume!(true);

    // Zero BSS, this initializes statics that are set to 0
    {
        let start_ptr = &mut __bss_start as *mut u8;
        let end_ptr = & __bss_end as *const u8 as usize;

        if start_ptr as usize <= end_ptr {
            let size = end_ptr - start_ptr as usize;
            memset(start_ptr, 0, size);
        }

        assert_eq!(BSS_TEST_ZERO, 0);
        assert_eq!(BSS_TEST_NONZERO, usize::MAX);
    }

    // Setup paging, this allows for memory allocation
    Page::init();
    memory::cluster_init();

    //Get the VBE information before unmapping the first megabyte
    display::vbe_init();

    // Unmap first page (TODO: Unmap more)
    {
        let start_ptr = 0;
        let end_ptr = 0x1000;

        if start_ptr as usize <= end_ptr {
            let size = end_ptr - start_ptr as usize;
            for page in 0..(size + 4095)/4096 {
                Page::new(start_ptr as usize + page * 4096).unmap();
            }
        }
    }

    //Remap text
    {
        let start_ptr = & __text_start as *const u8 as usize;
        let end_ptr = & __text_end as *const u8 as usize;
        if start_ptr as usize <= end_ptr {
            let size = end_ptr - start_ptr as usize;
            for page in 0..(size + 4095)/4096 {
                Page::new(start_ptr as usize + page * 4096).
                    map_kernel_read(start_ptr as usize + page * 4096);
            }
        }
    }

    //Remap rodata
    {
        let start_ptr = & __rodata_start as *const u8 as usize;
        let end_ptr = & __rodata_end as *const u8 as usize;
        if start_ptr <= end_ptr {
            let size = end_ptr - start_ptr;
            for page in 0..(size + 4095)/4096 {
                Page::new(start_ptr + page * 4096).
                    map_kernel_read(start_ptr + page * 4096);
            }
        }
    }

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

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

            env.console.lock().draw = true;

            debugln!("Redox {} bits", mem::size_of::<usize>() * 8);

            if let Some(acpi) = Acpi::new() {
                env.schemes.lock().push(acpi);
            }

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

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

            pci::pci_init(env);

            env.schemes.lock().push(DebugScheme::new());
            env.schemes.lock().push(box DisplayScheme);
            env.schemes.lock().push(box ContextScheme);
            env.schemes.lock().push(box InterruptScheme);
            env.schemes.lock().push(box MemoryScheme);
            env.schemes.lock().push(box TestScheme);

            env.contexts.lock().enabled = true;

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

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

                if let Err(err) = execute(vec!["init".to_string()]) {
                    debugln!("INIT: Failed to execute: {}", err);
                }
            });
        },
        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 Ok(context) = contexts.current() {
                    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 mut fsw: usize = 0;
            let mut fcw: usize = 0;
            unsafe {
                asm!("fnstsw $0" : "=*m"(&mut fsw) : : : "intel", "volatile");
                asm!("fnstcw $0" : "=*m"(&mut fcw) : : : "intel", "volatile");
            }
            debugln!("    FSW: {:08X}    FCW: {:08X}", fsw, fcw);

            let sp = regs.sp as *const u32;
            for y in -15..16 {
                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 {
                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 {
                do_sys_exit(usize::MAX);
            }
        })
    };

    //Do not catch init interrupt
    if interrupt < 0xFF {
        env().interrupts.lock()[interrupt as usize] += 1;
    }

    match interrupt {
        0x20 => {
            {
                let mut clock_monotonic = env().clock_monotonic.lock();
                *clock_monotonic = *clock_monotonic + PIT_DURATION;
            }
            {
                let mut clock_realtime = env().clock_realtime.lock();
                *clock_realtime = *clock_realtime + PIT_DURATION;
            }

            if let Ok(mut current) = env().contexts.lock().current_mut() {
                current.time += 1;
            }

            unsafe { context_switch(); }
        }
        i @ 0x21 ... 0x2F => {
            env().on_irq(i as u8 - 0x20);
        },
        0x80 => syscall_handle(regs),
        0xFF => {
            unsafe {
                init(regs.ax);
                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"),
        0x9 => exception!("Coprocessor Segment Overrun"), // legacy
        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"),
    }

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

        Pio::<u8>::new(0x20).write(0x20);
    }
}
<commit_msg>Remove the augmented_assignments feature flag<commit_after>#![crate_name="kernel"]
#![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(op_assign_traits)]
#![feature(unboxed_closures)]
#![feature(unsafe_no_drop_flag)]
#![feature(unwind_attributes)]
#![feature(vec_push_all)]
#![feature(zero_one)]
#![feature(collections_range)]
#![no_std]

#![allow(deprecated)]
#![deny(warnings)]

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate collections;

extern crate system;

use acpi::Acpi;

use alloc::boxed::Box;

use arch::context::{context_switch, Context};
use arch::memory;
use arch::paging::Page;
use arch::regs::Regs;
use arch::tss::TSS;

use collections::string::ToString;

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

use common::time::Duration;

use drivers::pci;
use drivers::io::{Io, Pio};
use drivers::ps2::*;
use drivers::rtc::*;
use drivers::serial::*;

use env::Environment;

use graphics::display;

use schemes::context::*;
use schemes::debug::*;
use schemes::display::*;
use schemes::interrupt::*;
use schemes::memory::*;
use schemes::test::*;

use syscall::execute::execute;
use syscall::{do_sys_chdir, do_sys_exit, do_sys_open, syscall_handle};

pub use system::externs::*;

/// Common std-like functionality
#[macro_use]
pub mod common;
#[macro_use]
pub mod macros;
/// Allocation
pub mod alloc_system;
/// ACPI
pub mod acpi;
/// Architecture dependant
pub mod arch;
/// Audio
pub mod audio;
/// Disk drivers
pub mod disk;
/// Various drivers
pub mod drivers;
/// Environment
pub mod env;
/// Filesystems
pub mod fs;
/// Various graphical methods
pub mod graphics;
/// Networking
pub mod network;
/// Panic
pub mod panic;
/// Schemes
pub mod schemes;
/// Synchronization
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: 4500572,
};

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

        let mut halt = true;

        for context in env().contexts.lock().iter().skip(1) {
            if ! context.blocked {
                halt = false;
                break;
            }
        }

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

extern {
    static mut __text_start: u8;
    static mut __text_end: u8;
    static mut __rodata_start: u8;
    static mut __rodata_end: u8;
    static mut __data_start: u8;
    static mut __data_end: u8;
    static mut __bss_start: u8;
    static mut __bss_end: u8;
}

static BSS_TEST_ZERO: usize = 0;
static BSS_TEST_NONZERO: usize = usize::MAX;

/// Initialize kernel
unsafe fn init(tss_data: usize) {

    // Test
    assume!(true);

    // Zero BSS, this initializes statics that are set to 0
    {
        let start_ptr = &mut __bss_start as *mut u8;
        let end_ptr = & __bss_end as *const u8 as usize;

        if start_ptr as usize <= end_ptr {
            let size = end_ptr - start_ptr as usize;
            memset(start_ptr, 0, size);
        }

        assert_eq!(BSS_TEST_ZERO, 0);
        assert_eq!(BSS_TEST_NONZERO, usize::MAX);
    }

    // Setup paging, this allows for memory allocation
    Page::init();
    memory::cluster_init();

    //Get the VBE information before unmapping the first megabyte
    display::vbe_init();

    // Unmap first page (TODO: Unmap more)
    {
        let start_ptr = 0;
        let end_ptr = 0x1000;

        if start_ptr as usize <= end_ptr {
            let size = end_ptr - start_ptr as usize;
            for page in 0..(size + 4095)/4096 {
                Page::new(start_ptr as usize + page * 4096).unmap();
            }
        }
    }

    //Remap text
    {
        let start_ptr = & __text_start as *const u8 as usize;
        let end_ptr = & __text_end as *const u8 as usize;
        if start_ptr as usize <= end_ptr {
            let size = end_ptr - start_ptr as usize;
            for page in 0..(size + 4095)/4096 {
                Page::new(start_ptr as usize + page * 4096).
                    map_kernel_read(start_ptr as usize + page * 4096);
            }
        }
    }

    //Remap rodata
    {
        let start_ptr = & __rodata_start as *const u8 as usize;
        let end_ptr = & __rodata_end as *const u8 as usize;
        if start_ptr <= end_ptr {
            let size = end_ptr - start_ptr;
            for page in 0..(size + 4095)/4096 {
                Page::new(start_ptr + page * 4096).
                    map_kernel_read(start_ptr + page * 4096);
            }
        }
    }

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

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

            env.console.lock().draw = true;

            debugln!("Redox {} bits", mem::size_of::<usize>() * 8);

            if let Some(acpi) = Acpi::new() {
                env.schemes.lock().push(acpi);
            }

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

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

            pci::pci_init(env);

            env.schemes.lock().push(DebugScheme::new());
            env.schemes.lock().push(box DisplayScheme);
            env.schemes.lock().push(box ContextScheme);
            env.schemes.lock().push(box InterruptScheme);
            env.schemes.lock().push(box MemoryScheme);
            env.schemes.lock().push(box TestScheme);

            env.contexts.lock().enabled = true;

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

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

                if let Err(err) = execute(vec!["init".to_string()]) {
                    debugln!("INIT: Failed to execute: {}", err);
                }
            });
        },
        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 Ok(context) = contexts.current() {
                    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 mut fsw: usize = 0;
            let mut fcw: usize = 0;
            unsafe {
                asm!("fnstsw $0" : "=*m"(&mut fsw) : : : "intel", "volatile");
                asm!("fnstcw $0" : "=*m"(&mut fcw) : : : "intel", "volatile");
            }
            debugln!("    FSW: {:08X}    FCW: {:08X}", fsw, fcw);

            let sp = regs.sp as *const u32;
            for y in -15..16 {
                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 {
                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 {
                do_sys_exit(usize::MAX);
            }
        })
    };

    //Do not catch init interrupt
    if interrupt < 0xFF {
        env().interrupts.lock()[interrupt as usize] += 1;
    }

    match interrupt {
        0x20 => {
            {
                let mut clock_monotonic = env().clock_monotonic.lock();
                *clock_monotonic = *clock_monotonic + PIT_DURATION;
            }
            {
                let mut clock_realtime = env().clock_realtime.lock();
                *clock_realtime = *clock_realtime + PIT_DURATION;
            }

            if let Ok(mut current) = env().contexts.lock().current_mut() {
                current.time += 1;
            }

            unsafe { context_switch(); }
        }
        i @ 0x21 ... 0x2F => {
            env().on_irq(i as u8 - 0x20);
        },
        0x80 => syscall_handle(regs),
        0xFF => {
            unsafe {
                init(regs.ax);
                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"),
        0x9 => exception!("Coprocessor Segment Overrun"), // legacy
        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"),
    }

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

        Pio::<u8>::new(0x20).write(0x20);
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};

use toml;

fn search_template_in_dirs<'a>(dirs: &'a [PathBuf], path: &Path) -> Option<&'a PathBuf> {
    dirs.iter().find(|dir| dir.join(path).exists())
}

pub fn get_template_source(tpl_path: &Path) -> String {
    let dirs = template_dirs();
    let path = search_template_in_dirs(&dirs, tpl_path)
        .map(|dir| dir.join(tpl_path))
        .expect(&format!(
            "template file '{}' does not exist",
            tpl_path.to_str().unwrap()
        ));
    let mut f = match File::open(&path) {
        Err(_) => {
            let msg = format!("unable to open template file '{}'", &path.to_str().unwrap());
            panic!(msg)
        }
        Ok(f) => f,
    };
    let mut s = String::new();
    f.read_to_string(&mut s).unwrap();
    if s.ends_with('\n') {
        let _ = s.pop();
    }
    s
}

pub fn find_template_from_path(path: &str, start_at: Option<&Path>) -> PathBuf {
    let dirs = template_dirs();
    if let Some(rel) = start_at {
        let root = search_template_in_dirs(&dirs, rel).expect(&format!(
            "unable to find previously available template file '{}'",
            rel.to_str().unwrap()
        ));
        let fs_rel_path = root.join(rel).with_file_name(path);
        if fs_rel_path.exists() {
            return fs_rel_path.strip_prefix(&root).unwrap().to_owned();
        }
    }

    let path = Path::new(path);
    search_template_in_dirs(&dirs, &path).expect(&format!(
        "template {:?} not found in directories {:?}",
        path.to_str().unwrap(),
        dirs
    ));
    path.to_owned()
}

static CONFIG_FILE_NAME: &str = "askama.toml";

#[derive(Deserialize)]
struct RawConfig {
    dirs: Option<Vec<String>>,
}

struct Config {
    dirs: Vec<PathBuf>,
}

impl RawConfig {
    fn from_file(filename: &PathBuf) -> Option<RawConfig> {
        if filename.exists() {
            let mut contents = String::new();
            File::open(filename)
                .unwrap()
                .read_to_string(&mut contents)
                .unwrap();
            Some(toml::from_str(&contents).unwrap())
        } else {
            None
        }
    }
}

impl Config {
    fn from_file() -> Config {
        let root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
        let filename = root.join(CONFIG_FILE_NAME);
        RawConfig::from_file(&filename).map_or_else(
            || Config {
                dirs: vec![root.join("templates")],
            },
            |config| Config {
                dirs: config
                    .dirs
                    .unwrap_or_else(|| Vec::new())
                    .into_iter()
                    .map(|directory| root.join(directory))
                    .collect(),
            },
        )
    }
}

pub fn template_dirs() -> Vec<PathBuf> {
    Config::from_file().dirs
}

#[cfg(test)]
mod tests {
    use super::Path;
    use super::{find_template_from_path, get_template_source};

    #[test]
    fn get_source() {
        assert_eq!(get_template_source(Path::new("sub/b.html")), "bar");
    }

    #[test]
    fn find_absolute() {
        let path = find_template_from_path("sub/b.html", Some(Path::new("a.html")));
        assert_eq!(path, Path::new("sub/b.html"));
    }

    #[test]
    #[should_panic]
    fn find_relative_nonexistent() {
        find_template_from_path("b.html", Some(Path::new("a.html")));
    }

    #[test]
    fn find_relative() {
        let path = find_template_from_path("c.html", Some(Path::new("sub/b.html")));
        assert_eq!(path, Path::new("sub/c.html"));
    }

    #[test]
    fn find_relative_sub() {
        let path = find_template_from_path("sub1/d.html", Some(Path::new("sub/b.html")));
        assert_eq!(path, Path::new("sub/sub1/d.html"));
    }
}
<commit_msg>Reorder items in top-down order<commit_after>use std::env;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};

use toml;

fn search_template_in_dirs<'a>(dirs: &'a [PathBuf], path: &Path) -> Option<&'a PathBuf> {
    dirs.iter().find(|dir| dir.join(path).exists())
}

pub fn get_template_source(tpl_path: &Path) -> String {
    let dirs = template_dirs();
    let path = search_template_in_dirs(&dirs, tpl_path)
        .map(|dir| dir.join(tpl_path))
        .expect(&format!(
            "template file '{}' does not exist",
            tpl_path.to_str().unwrap()
        ));
    let mut f = match File::open(&path) {
        Err(_) => {
            let msg = format!("unable to open template file '{}'", &path.to_str().unwrap());
            panic!(msg)
        }
        Ok(f) => f,
    };
    let mut s = String::new();
    f.read_to_string(&mut s).unwrap();
    if s.ends_with('\n') {
        let _ = s.pop();
    }
    s
}

pub fn find_template_from_path(path: &str, start_at: Option<&Path>) -> PathBuf {
    let dirs = template_dirs();
    if let Some(rel) = start_at {
        let root = search_template_in_dirs(&dirs, rel).expect(&format!(
            "unable to find previously available template file '{}'",
            rel.to_str().unwrap()
        ));
        let fs_rel_path = root.join(rel).with_file_name(path);
        if fs_rel_path.exists() {
            return fs_rel_path.strip_prefix(&root).unwrap().to_owned();
        }
    }

    let path = Path::new(path);
    search_template_in_dirs(&dirs, &path).expect(&format!(
        "template {:?} not found in directories {:?}",
        path.to_str().unwrap(),
        dirs
    ));
    path.to_owned()
}

pub fn template_dirs() -> Vec<PathBuf> {
    Config::from_file().dirs
}

struct Config {
    dirs: Vec<PathBuf>,
}

impl Config {
    fn from_file() -> Config {
        let root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
        let filename = root.join(CONFIG_FILE_NAME);
        RawConfig::from_file(&filename).map_or_else(
            || Config {
                dirs: vec![root.join("templates")],
            },
            |config| Config {
                dirs: config
                    .dirs
                    .unwrap_or_else(|| Vec::new())
                    .into_iter()
                    .map(|directory| root.join(directory))
                    .collect(),
            },
        )
    }
}

#[derive(Deserialize)]
struct RawConfig {
    dirs: Option<Vec<String>>,
}

impl RawConfig {
    fn from_file(filename: &PathBuf) -> Option<RawConfig> {
        if filename.exists() {
            let mut contents = String::new();
            File::open(filename)
                .unwrap()
                .read_to_string(&mut contents)
                .unwrap();
            Some(toml::from_str(&contents).unwrap())
        } else {
            None
        }
    }
}

static CONFIG_FILE_NAME: &str = "askama.toml";

#[cfg(test)]
mod tests {
    use super::Path;
    use super::{find_template_from_path, get_template_source};

    #[test]
    fn get_source() {
        assert_eq!(get_template_source(Path::new("sub/b.html")), "bar");
    }

    #[test]
    fn find_absolute() {
        let path = find_template_from_path("sub/b.html", Some(Path::new("a.html")));
        assert_eq!(path, Path::new("sub/b.html"));
    }

    #[test]
    #[should_panic]
    fn find_relative_nonexistent() {
        find_template_from_path("b.html", Some(Path::new("a.html")));
    }

    #[test]
    fn find_relative() {
        let path = find_template_from_path("c.html", Some(Path::new("sub/b.html")));
        assert_eq!(path, Path::new("sub/c.html"));
    }

    #[test]
    fn find_relative_sub() {
        let path = find_template_from_path("sub1/d.html", Some(Path::new("sub/b.html")));
        assert_eq!(path, Path::new("sub/sub1/d.html"));
    }
}
<|endoftext|>


<commit_before>#![feature(lang_items, alloc_error_handler)]
#![no_std]
#![no_main]

use core::fmt::Write;
use data_encoding::Encoding;

#[lang = "eh_personality"]
extern "C" fn eh_personality() {}

struct Fd(libc::c_int);

impl core::fmt::Write for Fd {
    fn write_str(&mut self, s: &str) -> core::fmt::Result {
        unsafe {
            libc::write(self.0, s.as_ptr() as *const libc::c_void, s.len());
        }
        Ok(())
    }
}

#[panic_handler]
fn panic_handler(info: &core::panic::PanicInfo) -> ! {
    unsafe {
        let _ = writeln!(Fd(2), "{}", info);
        libc::exit(1);
    }
}

#[cfg(feature = "alloc")]
mod alloc {
    use core::alloc::{GlobalAlloc, Layout};

    struct Malloc;

    unsafe impl GlobalAlloc for Malloc {
        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
            libc::malloc(layout.size()) as *mut u8
        }
        unsafe fn dealloc(&self, ptr: *mut u8, _: Layout) {
            libc::free(ptr as *mut libc::c_void)
        }
    }

    #[alloc_error_handler]
    fn foo(_: Layout) -> ! {
        loop {}
    }

    #[global_allocator]
    static GLOBAL: Malloc = Malloc;
}

fn test_encode(encoding: &Encoding, input: &[u8], output: &mut [u8], result: &str) {
    let olen = encoding.encode_len(input.len());
    encoding.encode_mut(input, &mut output[.. olen]);
    assert_eq!(core::str::from_utf8(&output[.. olen]).unwrap(), result);
    #[cfg(feature = "alloc")]
    assert_eq!(encoding.encode(input), result);
}

fn test_decode(encoding: &Encoding, input: &str, output: &mut [u8], result: &[u8]) {
    let ilen = encoding.decode_len(input.len()).unwrap();
    let olen = encoding.decode_mut(input.as_bytes(), &mut output[.. ilen]).unwrap();
    assert_eq!(&output[.. olen], result);
    #[cfg(feature = "alloc")]
    assert_eq!(encoding.decode(input.as_bytes()).unwrap(), result);
}

fn test(encoding: &Encoding, input: &[u8], output: &str, buffer: &mut [u8]) {
    test_encode(encoding, input, buffer, output);
    test_decode(encoding, output, buffer, input);
}

#[cfg(feature = "alloc")]
fn test_macro() {
    const FOOBAR: &'static [u8] = &data_encoding_macro::base64!("Zm9vYmFy");
    const LETTER8: Encoding = data_encoding_macro::new_encoding! {
        symbols: "ABCDEFGH",
    };

    assert_eq!(FOOBAR, b"foobar");
    test(&LETTER8, &[0], "AAA", &mut [0; 3]);
    test(&LETTER8, b"foobar", "DBEGHFFHDAEGAFGC", &mut [0; 16]);
}

#[no_mangle]
pub extern "C" fn main(_argc: isize, _argv: *const *const u8) -> isize {
    test(&data_encoding::BASE32, b"hello", "NBSWY3DP", &mut [0; 8]);
    test(&data_encoding::BASE64, b"hello", "aGVsbG8=", &mut [0; 8]);
    test(&data_encoding::BASE64_NOPAD, b"hello", "aGVsbG8", &mut [0; 8]);
    test(&data_encoding::HEXLOWER_PERMISSIVE, b"hello", "68656c6c6f", &mut [0; 10]);
    test_decode(&data_encoding::HEXLOWER_PERMISSIVE, "68656C6C6F", &mut [0; 5], b"hello");
    #[cfg(feature = "alloc")]
    test_macro();
    let _ = writeln!(Fd(1), "All tests passed.");
    0
}
<commit_msg>nostd: also test macro with no-alloc<commit_after>#![feature(lang_items, alloc_error_handler)]
#![no_std]
#![no_main]

use core::fmt::Write;
use data_encoding::Encoding;

#[lang = "eh_personality"]
extern "C" fn eh_personality() {}

struct Fd(libc::c_int);

impl core::fmt::Write for Fd {
    fn write_str(&mut self, s: &str) -> core::fmt::Result {
        unsafe {
            libc::write(self.0, s.as_ptr() as *const libc::c_void, s.len());
        }
        Ok(())
    }
}

#[panic_handler]
fn panic_handler(info: &core::panic::PanicInfo) -> ! {
    unsafe {
        let _ = writeln!(Fd(2), "{}", info);
        libc::exit(1);
    }
}

#[cfg(feature = "alloc")]
mod alloc {
    use core::alloc::{GlobalAlloc, Layout};

    struct Malloc;

    unsafe impl GlobalAlloc for Malloc {
        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
            libc::malloc(layout.size()) as *mut u8
        }
        unsafe fn dealloc(&self, ptr: *mut u8, _: Layout) {
            libc::free(ptr as *mut libc::c_void)
        }
    }

    #[alloc_error_handler]
    fn foo(_: Layout) -> ! {
        loop {}
    }

    #[global_allocator]
    static GLOBAL: Malloc = Malloc;
}

fn test_encode(encoding: &Encoding, input: &[u8], output: &mut [u8], result: &str) {
    let olen = encoding.encode_len(input.len());
    encoding.encode_mut(input, &mut output[.. olen]);
    assert_eq!(core::str::from_utf8(&output[.. olen]).unwrap(), result);
    #[cfg(feature = "alloc")]
    assert_eq!(encoding.encode(input), result);
}

fn test_decode(encoding: &Encoding, input: &str, output: &mut [u8], result: &[u8]) {
    let ilen = encoding.decode_len(input.len()).unwrap();
    let olen = encoding.decode_mut(input.as_bytes(), &mut output[.. ilen]).unwrap();
    assert_eq!(&output[.. olen], result);
    #[cfg(feature = "alloc")]
    assert_eq!(encoding.decode(input.as_bytes()).unwrap(), result);
}

fn test(encoding: &Encoding, input: &[u8], output: &str, buffer: &mut [u8]) {
    test_encode(encoding, input, buffer, output);
    test_decode(encoding, output, buffer, input);
}

fn test_macro() {
    const FOOBAR: &'static [u8] = &data_encoding_macro::base64!("Zm9vYmFy");
    const LETTER8: Encoding = data_encoding_macro::new_encoding! {
        symbols: "ABCDEFGH",
    };

    assert_eq!(FOOBAR, b"foobar");
    test(&LETTER8, &[0], "AAA", &mut [0; 3]);
    test(&LETTER8, b"foobar", "DBEGHFFHDAEGAFGC", &mut [0; 16]);
}

#[no_mangle]
pub extern "C" fn main(_argc: isize, _argv: *const *const u8) -> isize {
    test(&data_encoding::BASE32, b"hello", "NBSWY3DP", &mut [0; 8]);
    test(&data_encoding::BASE64, b"hello", "aGVsbG8=", &mut [0; 8]);
    test(&data_encoding::BASE64_NOPAD, b"hello", "aGVsbG8", &mut [0; 8]);
    test(&data_encoding::HEXLOWER_PERMISSIVE, b"hello", "68656c6c6f", &mut [0; 10]);
    test_decode(&data_encoding::HEXLOWER_PERMISSIVE, "68656C6C6F", &mut [0; 5], b"hello");
    test_macro();
    let _ = writeln!(Fd(1), "All tests passed.");
    0
}
<|endoftext|>


<commit_before>#![feature(phase)]

#[phase(plugin)]
extern crate peg_syntax_ext;

use arithmetic::expression;

peg! arithmetic(r#"
#[pub]
expression -> int
	= sum

sum -> int
	= l:product "+" r:product { l+r }
	/ product

product -> int
	= l:atom "*" r:atom { l*r }
	/ atom

atom -> int
	= number
	/ "(" v:sum ")" { v }

number -> int
	= [0-9]+ { from_str::<int>(match_str).unwrap() }
"#)

fn main() {
	assert_eq!(expression("1+1"), Ok(2));
	assert_eq!(expression("5*5"), Ok(25));
	assert_eq!(expression("222+3333"), Ok(3555));
	assert_eq!(expression("2+3*4"), Ok(14));
	assert_eq!(expression("(2+2)*3"), Ok(12));
	assert!(expression("(22+)+1").is_err());
	assert!(expression("1++1").is_err());
	assert!(expression("3)+1").is_err());
	println!("Ok");
}
<commit_msg>rust RFC#378: Trailing semicolon on item macros in test_arithmetic<commit_after>#![feature(phase)]

#[phase(plugin)]
extern crate peg_syntax_ext;

use arithmetic::expression;

peg! arithmetic(r#"
#[pub]
expression -> int
	= sum

sum -> int
	= l:product "+" r:product { l+r }
	/ product

product -> int
	= l:atom "*" r:atom { l*r }
	/ atom

atom -> int
	= number
	/ "(" v:sum ")" { v }

number -> int
	= [0-9]+ { from_str::<int>(match_str).unwrap() }
"#);

fn main() {
	assert_eq!(expression("1+1"), Ok(2));
	assert_eq!(expression("5*5"), Ok(25));
	assert_eq!(expression("222+3333"), Ok(3555));
	assert_eq!(expression("2+3*4"), Ok(14));
	assert_eq!(expression("(2+2)*3"), Ok(12));
	assert!(expression("(22+)+1").is_err());
	assert!(expression("1++1").is_err());
	assert!(expression("3)+1").is_err());
	println!("Ok");
}
<|endoftext|>