<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
use ::arch::vga;
use core::ptr::Unique;
use core::mem;
use core::fmt::{Write, Result};
use spin::Mutex;

const ANSI_ESCAPE: &'static str = r"\x1b";

pub struct Terminal { buffer: Unique<vga::Buffer>
                    , x: usize
                    , y: usize
                    , colors: vga::Palette
                    }

macro_rules! next_ansi_byte {
    ($b:expr) => { $b.next().expect("Unterminated ANSI escape sequence!") }
}

impl Terminal {

    #[inline]
    fn buffer(&mut self) -> &mut vga::Buffer {
        unsafe { self.buffer.get_mut() }
    }

    pub fn set_colors(&mut self, bg: vga::Color, fg: vga::Color)
                     -> &mut Self
    {
        self.colors = vga::Palette::new(bg,fg);
        self
    }
    fn scroll(&mut self) {
        let mut rows = self.buffer()
                           .iter_mut();

        let mut next = rows.next()
                           .unwrap();

        while let Some(thing) = rows.next() {
            mem::swap(next, thing);
            next = thing;
        }

        // empty last line
        unsafe { *next = mem::zeroed() }
    }

    pub fn clear(&mut self) -> &mut Self {
        unsafe { *(self.buffer()) = mem::zeroed(); }
        self
    }

    pub fn write_byte(&mut self, byte: u8) -> &mut Self {
        if byte == b'\n' {
            self.x = 0;
            self.y += 1;
        } else {
            // set character at position
            self.buffer()[self.y][self.x]
                = vga::Char { ascii: byte
                            , colors: self.colors };
            self.x += 1;

            // check for line wrapping
            if self.x >= vga::X_MAX {
                self.x = 0;
                self.y += 1;
            }
        }
        // check for scrolling
        if self.y >= vga::Y_MAX {
            self.scroll();
            self.y = vga::Y_MAX- 1;
        }
        self
    }

    fn handle_ansi_escape(&self, escape_code: &str) -> Result {

        // let escape_seq: &str = bytes.take_while(|b| b != b'm')
        //                       .collect::<&str>();
        // match escape_seq {
        //     [b'3', n] => unsafe {
        //         self.colors.set_foreground(mem::transmute(n - 48))
        //     }
        // }
        // while let Some(byte) = bytes.next() {
        //     match *byte {
        //         // we've recieved an ANSI escape sequence.
        //         // this basically enters a mediocre FSM for matching ANSI
        //         // control codes.
        //         0x1b => match *next_ansi_byte!(bytes) {
        //             // handle multi-char ANSI escapes
        //             b'[' => match *next_ansi_byte!(bytes) {
        //                 // foreground color code
        //                 fg @ 30 ... 37 => {
        //                     if !(*next_ansi_byte!(bytes) == b'm') {
        //                         unsafe {
        //                             let color: vga::Color
        //                                 = mem::transmute(fg - 30);
        //                             self.colors
        //                                 .set_foreground(color);
        //                         }
        //
        //                     }
        //                 }
        //                 // background color code
        //               , 40 ... 47 => {
        //
        //                 }
        //               , _ => unimplemented!()
        //             }
        //           , _    => unimplemented!()
        //         }
        //         // otherwise, treat the byte as a normal ASCII char
        //       , b => { self.write_byte(b); }
        //     }
        // }
        unimplemented!()
    }

}

impl Write for Terminal {

    fn write_str(&mut self, s: &str) -> Result {
        if s.contains(ANSI_ESCAPE) {
            let escape_idxes = s.match_indices(ANSI_ESCAPE);
            for (idx, _) in escape_idxes {
                let (segment, _) = s.split_at(idx);
                if segment.starts_with(ANSI_ESCAPE) {
                    try!(self.handle_ansi_escape(segment))
                } else {
                    for byte in segment.as_bytes() {
                        self.write_byte(*byte);
                    }
                }
            }
        } else {
            for byte in s.as_bytes() {
                self.write_byte(*byte);
            }
        }
        Ok(())
    }

}

/// The system's VGA terminal
pub static CONSOLE: Mutex<Terminal>
    = Mutex::new(Terminal {
        colors: vga::Palette::new( vga::Color::LightGreen
                                 , vga::Color::Black
                                 )
      , x: 0
      , y: 0
      , buffer: unsafe { Unique::new(0xB8000 as *mut _) },
    });
<commit_msg>Single color ANSI color escapes should happen now.<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
use ::arch::vga;
use core::ptr::Unique;
use core::mem;
use core::fmt::{Write, Result};
use spin::Mutex;

const ANSI_ESCAPE: &'static str = r"\x1b";

pub struct Terminal { buffer: Unique<vga::Buffer>
                    , x: usize
                    , y: usize
                    , colors: vga::Palette
                    }

macro_rules! next_ansi_byte {
    ($b:expr) => { $b.next().expect("Unterminated ANSI escape sequence!") }
}

impl Terminal {

    #[inline]
    fn buffer(&mut self) -> &mut vga::Buffer {
        unsafe { self.buffer.get_mut() }
    }

    pub fn set_colors(&mut self, bg: vga::Color, fg: vga::Color)
                     -> &mut Self
    {
        self.colors = vga::Palette::new(bg,fg);
        self
    }
    fn scroll(&mut self) {
        let mut rows = self.buffer()
                           .iter_mut();

        let mut next = rows.next()
                           .unwrap();

        while let Some(thing) = rows.next() {
            mem::swap(next, thing);
            next = thing;
        }

        // empty last line
        unsafe { *next = mem::zeroed() }
    }

    pub fn clear(&mut self) -> &mut Self {
        unsafe { *(self.buffer()) = mem::zeroed(); }
        self
    }

    pub fn write_byte(&mut self, byte: u8) -> &mut Self {
        if byte == b'\n' {
            self.x = 0;
            self.y += 1;
        } else {
            // set character at position
            self.buffer()[self.y][self.x]
                = vga::Char { ascii: byte
                            , colors: self.colors };
            self.x += 1;

            // check for line wrapping
            if self.x >= vga::X_MAX {
                self.x = 0;
                self.y += 1;
            }
        }
        // check for scrolling
        if self.y >= vga::Y_MAX {
            self.scroll();
            self.y = vga::Y_MAX- 1;
        }
        self
    }

    fn handle_ansi_escape(&self, escape_code: &str) -> Result {
        match escape_code[4..].as_bytes() {
            [b'3', n @ u8, b'm'] => {
                unsafe { self.colors
                             .set_foreground(mem::transmute(n - 48)); }
                Ok(())
            }
          , [b'4', n @ u8, b'm'] => {
                unsafe { self.colors
                             .set_background(mem::transmute(n - 48)); }
                Ok(())
            }
          , _ => unimplemented!()
        }
        // let escape_seq: &str = bytes.take_while(|b| b != b'm')
        //                       .collect::<&str>();
        // match escape_seq {
        //     [b'3', n] => unsafe {
        //         self.colors.set_foreground(mem::transmute(n - 48))
        //     }
        // }
        // while let Some(byte) = bytes.next() {
        //     match *byte {
        //         // we've recieved an ANSI escape sequence.
        //         // this basically enters a mediocre FSM for matching ANSI
        //         // control codes.
        //         0x1b => match *next_ansi_byte!(bytes) {
        //             // handle multi-char ANSI escapes
        //             b'[' => match *next_ansi_byte!(bytes) {
        //                 // foreground color code
        //                 fg @ 30 ... 37 => {
        //                     if !(*next_ansi_byte!(bytes) == b'm') {
        //                         unsafe {
        //                             let color: vga::Color
        //                                 = mem::transmute(fg - 30);
        //                             self.colors
        //                                 .set_foreground(color);
        //                         }
        //
        //                     }
        //                 }
        //                 // background color code
        //               , 40 ... 47 => {
        //
        //                 }
        //               , _ => unimplemented!()
        //             }
        //           , _    => unimplemented!()
        //         }
        //         // otherwise, treat the byte as a normal ASCII char
        //       , b => { self.write_byte(b); }
        //     }
        // }

    }

}

impl Write for Terminal {

    fn write_str(&mut self, s: &str) -> Result {
        if s.contains(ANSI_ESCAPE) {
            let escape_idxes = s.match_indices(ANSI_ESCAPE);
            for (idx, _) in escape_idxes {
                let (segment, _) = s.split_at(idx);
                if segment.starts_with(ANSI_ESCAPE) {
                    try!(self.handle_ansi_escape(segment))
                } else {
                    for byte in segment.as_bytes() {
                        self.write_byte(*byte);
                    }
                }
            }
        } else {
            for byte in s.as_bytes() {
                self.write_byte(*byte);
            }
        }
        Ok(())
    }

}

/// The system's VGA terminal
pub static CONSOLE: Mutex<Terminal>
    = Mutex::new(Terminal {
        colors: vga::Palette::new( vga::Color::LightGreen
                                 , vga::Color::Black
                                 )
      , x: 0
      , y: 0
      , buffer: unsafe { Unique::new(0xB8000 as *mut _) },
    });
<|endoftext|>


<commit_before>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

//! Parser for Intecture data files.

#[macro_use]
mod macros;
mod condition;

use error::{Error, Result};
use serde_json::{self, Value};
use std::collections::BTreeMap;
use std::fs;
use std::path::{Path, PathBuf};

#[doc(hidden)]
pub fn open<P: AsRef<Path>>(path: P) -> Result<Value> {
    let mut p = PathBuf::from("data");
    p.push(path);
    open_raw(&p)
}

fn open_raw<P: AsRef<Path>>(path: P) -> Result<Value> {
    let mut fh = try!(fs::File::open(path.as_ref()));
    let data: Value = try!(serde_json::from_reader(&mut fh));

    if !data.is_object() {
        Err(Error::Generic("Value is not an object".into()))
    } else {
        Ok(data)
    }
}

pub fn merge(mut me: Value, mut last_value: Value) -> Result<Value> {
    for dep in try!(dependencies(&mut me)) {
        last_value = try!(merge(dep, last_value));
    }

    let lv_clone = last_value.clone();
    Ok(try!(merge_values(me, last_value, &lv_clone)))
}

fn dependencies(me: &mut Value) -> Result<Vec<Value>> {
    let mut deps = Vec::new();
    let mut payloads: Vec<String> = Vec::new();

    if let Some(inc) = me.find("_include") {
        if !inc.is_array() {
            return Err(Error::Generic("Value of `_include` is not an array".into()));
        }

        // Loop in reverse order to get lowest importance first
        for i in inc.as_array().unwrap().iter().rev() {
            if let Some(s) = i.as_str() {
                if s.starts_with("payload:") {
                    let (_, payload) = s.split_at(8);
                    let payload = payload.trim();
                    let parts: Vec<&str> = payload.split("::").collect();

                    let mut buf = PathBuf::from("payloads");
                    buf.push(try!(parts.get(0).ok_or(Error::Generic("Empty payload in `_include`".into()))));
                    buf.push("data");
                    buf.push(parts.get(1).unwrap_or(&"main"));
                    buf.set_extension("json");

                    if let Ok(d) = open_raw(&buf) {
                        deps.push(d);
                    }
                    payloads.insert(0, payload.into());
                } else {
                    deps.push(try!(open(s)));
                }
            } else {
                return Err(Error::Generic("Non-string value in `_include`".into()));
            }
        }
    }

    if me.is_object() && !payloads.is_empty() {
        me.as_object_mut().unwrap().insert("_payloads".into(), serde_json::to_value(payloads));
    }

    Ok(deps)
}

fn merge_values(into: Value, mut from: Value, parent_from: &Value) -> Result<Value> {
    match into {
        Value::Null |
        Value::Bool(_) |
        Value::I64(_) |
        Value::U64(_) |
        Value::F64(_) |
        Value::String(_) => Ok(into),
        Value::Array(mut a) => {
            if from.is_array() {
                a.append(from.as_array_mut().unwrap());
            } else {
                a.push(from);
            }

            let mut b = Vec::new();

            for v in a {
                b.push(try!(merge_values(v, Value::Null, parent_from)));
            }

            Ok(Value::Array(b))
        },
        Value::Object(o) => {
            let mut new: BTreeMap<String, Value> = BTreeMap::new();

            for (mut key, mut value) in o {
                if key.ends_with("?") || key.ends_with("?!") {
                    if key.pop().unwrap() == '!' {
                        key.pop();
                        key.push('!');
                    }

                    value = try!(query_value(&parent_from, value)).unwrap_or(Value::Null);
                }

                if key.ends_with("!") {
                    key.pop();
                }
                else if let Some(o1) = from.find(&key) {
                    value = try!(merge_values(value, o1.clone(), &parent_from));
                }

                new.insert(key, value);
            }

            // Insert any missing values
            if let Some(o1) = from.as_object() {
                for (key, value) in o1 {
                    if !new.contains_key(key) {
                        new.insert(key.clone(), value.clone());
                    }
                }
            }

            Ok(Value::Object(new))
        }
    }
}

fn query_value(data: &Value, value: Value) -> Result<Option<Value>> {
    match value {
        Value::Array(a) => {
            for opt in a {
                if let Some(v) = try!(query_value(data, opt)) {
                    return Ok(Some(v));
                }
            }
        },
        Value::Object(mut o) => {
            if let Some(v) = o.remove("_") {
                if let Some(q) = o.get("?") {
                    match *q {
                        Value::String(ref s) => {
                            if try!(condition::eval(data, s)) {
                                return Ok(Some(v));
                            }
                        },
                        _ => return Err(Error::Generic("Query must be string".into())),
                    };
                }

                return Ok(Some(v));
            }
        },
        _ => return Ok(Some(value)),
    }

    Ok(None)
}

#[cfg(test)]
mod tests {
    use serde_json::{self, Value};
    use std::fs;
    use std::io::Write;
    use std::path::PathBuf;
    use super::*;
    use tempdir::TempDir;

    #[test]
    fn test_parser() {
        let tempdir = TempDir::new("parser_test").unwrap();
        let mut path = tempdir.path().to_owned();

        path.push("data");
        fs::create_dir(&path).unwrap();
        path.pop();
        path.push("payloads/payload/data");

        fs::create_dir_all(&path).unwrap();
        path.pop();
        path.pop();
        path.pop();

        let expected_value = create_data(&mut path);

        path.push("data/top.json");
        let value = open(&path).unwrap();
        let value = merge(value, Value::Null).unwrap();

        assert_eq!(value, expected_value);
    }

    fn create_data(path: &mut PathBuf) -> Value {
        path.push("data/middle.json");
        let mut fh = fs::File::create(&path).unwrap();
        path.pop();
        path.pop();
        fh.write_all(format!("{{
            \"payload\": {{
                \"b!\": [ 3, 4 ],
                \"d\": [ 987 ]
            }},
            \"variable\": false,
            \"d\": 4,
            \"_include\": [
                \"payload: {}/payloads/payload::default\"
            ]
        }}", path.to_str().unwrap()).as_bytes()).unwrap();

        path.push("data/bottom.json");
        let mut fh = fs::File::create(&path).unwrap();
        path.pop();
        path.pop();
        fh.write_all(b"{
            \"moo\": \"cow\",
            \"payload\": {
                \"b\": [ 5 ],
                \"d\": [ 999 ]
            }
        }").unwrap();

        path.push("payloads/payload/data/default.json");
        let mut fh = fs::File::create(&path).unwrap();
        path.pop();
        path.pop();
        path.pop();
        path.pop();
        fh.write_all(b"{
            \"pvalue\": \"payload\"
        }").unwrap();

        path.push("data/top.json");
        let mut fh = fs::File::create(&path).unwrap();
        path.pop();
        path.pop();
        fh.write_all(format!("{{
            \"a\": 1,
            \"payload\": {{
                \"b\": [ 1, 2 ],
                \"c?\": [
                    {{
                        \"_\": [ 6, 7 ],
                        \"?\": \"/variable = false\"
                    }},
                    {{
                        \"_\": [ 8, 9 ]
                    }}
                ],
                \"d\": [ 123 ]
            }},
            \"variable\": {{
                \"one!\": true,
                \"two\": false
            }},
            \"_include\": [
                \"{}/data/middle.json\",
                \"{0}/data/bottom.json\"
            ]
        }}", path.to_str().unwrap()).as_bytes()).unwrap();

        serde_json::from_str(&format!("{{
            \"_include\": [
                \"{}/data/middle.json\",
                \"{0}/data/bottom.json\",
                \"payload: {0}/payloads/payload::default\"
            ],
            \"_payloads\": [
                \"{0}/payloads/payload::default\"
            ],
            \"a\": 1,
            \"d\": 4,
            \"moo\": \"cow\",
            \"payload\": {{
                \"b\": [ 1, 2, 3, 4 ],
                \"c\": [ 6, 7 ],
                \"d\": [ 123, 987, 999 ]
            }},
            \"pvalue\": \"payload\",
            \"variable\": {{
                \"one\": true,
                \"two\": false
            }}
        }}", path.to_str().unwrap())).unwrap()
    }
}
<commit_msg>Fixed bug where nested object values would not always be merged<commit_after>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

//! Parser for Intecture data files.

#[macro_use]
mod macros;
mod condition;

use error::{Error, Result};
use serde_json::{self, Value};
use std::collections::BTreeMap;
use std::fs;
use std::path::{Path, PathBuf};

#[doc(hidden)]
pub fn open<P: AsRef<Path>>(path: P) -> Result<Value> {
    let mut p = PathBuf::from("data");
    p.push(path);
    open_raw(&p)
}

fn open_raw<P: AsRef<Path>>(path: P) -> Result<Value> {
    let mut fh = try!(fs::File::open(path.as_ref()));
    let data: Value = try!(serde_json::from_reader(&mut fh));

    if !data.is_object() {
        Err(Error::Generic("Value is not an object".into()))
    } else {
        Ok(data)
    }
}

pub fn merge(mut me: Value, mut last_value: Value) -> Result<Value> {
    for dep in try!(dependencies(&mut me)) {
        last_value = try!(merge(dep, last_value));
    }

    let lv_clone = last_value.clone();
    Ok(try!(merge_values(me, last_value, &lv_clone)))
}

fn dependencies(me: &mut Value) -> Result<Vec<Value>> {
    let mut deps = Vec::new();
    let mut payloads: Vec<String> = Vec::new();

    if let Some(inc) = me.find("_include") {
        if !inc.is_array() {
            return Err(Error::Generic("Value of `_include` is not an array".into()));
        }

        // Loop in reverse order to get lowest importance first
        for i in inc.as_array().unwrap().iter().rev() {
            if let Some(s) = i.as_str() {
                if s.starts_with("payload:") {
                    let (_, payload) = s.split_at(8);
                    let payload = payload.trim();
                    let parts: Vec<&str> = payload.split("::").collect();

                    let mut buf = PathBuf::from("payloads");
                    buf.push(try!(parts.get(0).ok_or(Error::Generic("Empty payload in `_include`".into()))));
                    buf.push("data");
                    buf.push(parts.get(1).unwrap_or(&"main"));
                    buf.set_extension("json");

                    if let Ok(d) = open_raw(&buf) {
                        deps.push(d);
                    }
                    payloads.insert(0, payload.into());
                } else {
                    deps.push(try!(open(s)));
                }
            } else {
                return Err(Error::Generic("Non-string value in `_include`".into()));
            }
        }
    }

    if me.is_object() && !payloads.is_empty() {
        me.as_object_mut().unwrap().insert("_payloads".into(), serde_json::to_value(payloads));
    }

    Ok(deps)
}

fn merge_values(into: Value, mut from: Value, parent_from: &Value) -> Result<Value> {
    match into {
        Value::Null |
        Value::Bool(_) |
        Value::I64(_) |
        Value::U64(_) |
        Value::F64(_) |
        Value::String(_) => Ok(into),
        Value::Array(mut a) => {
            if from.is_array() {
                a.append(from.as_array_mut().unwrap());
            }
            else if !from.is_null() {
                a.push(from);
            }

            let mut b = Vec::new();

            for v in a {
                b.push(try!(merge_values(v, Value::Null, parent_from)));
            }

            Ok(Value::Array(b))
        },
        Value::Object(o) => {
            let mut new: BTreeMap<String, Value> = BTreeMap::new();

            for (mut key, mut value) in o {
                if key.ends_with("?") || key.ends_with("?!") {
                    if key.pop().unwrap() == '!' {
                        key.pop();
                        key.push('!');
                    }

                    value = try!(query_value(&parent_from, value)).unwrap_or(Value::Null);
                }

                let mut merge_val = Value::Null;

                if key.ends_with("!") {
                    key.pop();
                }
                else if let Some(o1) = from.find(&key) {
                    merge_val = o1.clone();
                }

                value = try!(merge_values(value, merge_val, &parent_from));

                new.insert(key, value);
            }

            // Insert any missing values
            if let Some(o1) = from.as_object() {
                for (key, value) in o1 {
                    if !new.contains_key(key) {
                        new.insert(key.clone(), value.clone());
                    }
                }
            }

            Ok(Value::Object(new))
        }
    }
}

fn query_value(data: &Value, value: Value) -> Result<Option<Value>> {
    match value {
        Value::Array(a) => {
            for opt in a {
                if let Some(v) = try!(query_value(data, opt)) {
                    return Ok(Some(v));
                }
            }
        },
        Value::Object(mut o) => {
            if let Some(v) = o.remove("_") {
                if let Some(q) = o.get("?") {
                    match *q {
                        Value::String(ref s) => {
                            if try!(condition::eval(data, s)) {
                                return Ok(Some(v));
                            }
                        },
                        _ => return Err(Error::Generic("Query must be string".into())),
                    };
                }

                return Ok(Some(v));
            }
        },
        _ => return Ok(Some(value)),
    }

    Ok(None)
}

#[cfg(test)]
mod tests {
    use serde_json::{self, Value};
    use std::fs;
    use std::io::Write;
    use std::path::PathBuf;
    use super::*;
    use tempdir::TempDir;

    #[test]
    fn test_parser() {
        let tempdir = TempDir::new("parser_test").unwrap();
        let mut path = tempdir.path().to_owned();

        path.push("data");
        fs::create_dir(&path).unwrap();
        path.pop();
        path.push("payloads/payload/data");

        fs::create_dir_all(&path).unwrap();
        path.pop();
        path.pop();
        path.pop();

        let expected_value = create_data(&mut path);

        path.push("data/top.json");
        let value = open(&path).unwrap();
        let value = merge(value, Value::Null).unwrap();

        assert_eq!(value, expected_value);
    }

    fn create_data(path: &mut PathBuf) -> Value {
        path.push("data/middle.json");
        let mut fh = fs::File::create(&path).unwrap();
        path.pop();
        path.pop();
        fh.write_all(format!("{{
            \"payload\": {{
                \"b!\": [ 3, 4 ],
                \"d\": [ 987 ]
            }},
            \"variable\": false,
            \"d\": 4,
            \"_include\": [
                \"payload: {}/payloads/payload::default\"
            ]
        }}", path.to_str().unwrap()).as_bytes()).unwrap();

        path.push("data/bottom.json");
        let mut fh = fs::File::create(&path).unwrap();
        path.pop();
        path.pop();
        fh.write_all(b"{
            \"moo\": \"cow\",
            \"payload\": {
                \"b\": [ 5 ],
                \"d\": [ 999 ]
            }
        }").unwrap();

        path.push("payloads/payload/data/default.json");
        let mut fh = fs::File::create(&path).unwrap();
        path.pop();
        path.pop();
        path.pop();
        path.pop();
        fh.write_all(b"{
            \"pvalue\": \"payload\"
        }").unwrap();

        path.push("data/top.json");
        let mut fh = fs::File::create(&path).unwrap();
        path.pop();
        path.pop();
        fh.write_all(format!("{{
            \"a\": 1,
            \"payload\": {{
                \"b\": [ 1, 2 ],
                \"c?\": [
                    {{
                        \"_\": [ 6, 7 ],
                        \"?\": \"/variable = false\"
                    }},
                    {{
                        \"_\": [ 8, 9 ]
                    }}
                ],
                \"d\": [ 123 ]
            }},
            \"variable\": {{
                \"one!\": true,
                \"two\": false
            }},
            \"_include\": [
                \"{}/data/middle.json\",
                \"{0}/data/bottom.json\"
            ]
        }}", path.to_str().unwrap()).as_bytes()).unwrap();

        serde_json::from_str(&format!("{{
            \"_include\": [
                \"{}/data/middle.json\",
                \"{0}/data/bottom.json\",
                \"payload: {0}/payloads/payload::default\"
            ],
            \"_payloads\": [
                \"{0}/payloads/payload::default\"
            ],
            \"a\": 1,
            \"d\": 4,
            \"moo\": \"cow\",
            \"payload\": {{
                \"b\": [ 1, 2, 3, 4 ],
                \"c\": [ 6, 7 ],
                \"d\": [ 123, 987, 999 ]
            }},
            \"pvalue\": \"payload\",
            \"variable\": {{
                \"one\": true,
                \"two\": false
            }}
        }}", path.to_str().unwrap())).unwrap()
    }
}
<|endoftext|>


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

#[crate_type = "bin"];

#[allow(non_camel_case_types)];

#[no_core]; // XXX: Remove after snapshot
#[no_std];

extern mod core(name = "std", vers = "0.7-pre");
extern mod extra(name = "extra", vers = "0.7-pre");

use core::prelude::*;
use core::*;

use extra::getopts;
use extra::test;

use core::result::{Ok, Err};

use common::config;
use common::mode_run_pass;
use common::mode_run_fail;
use common::mode_compile_fail;
use common::mode_pretty;
use common::mode_debug_info;
use common::mode;
use util::logv;

pub mod procsrv;
pub mod util;
pub mod header;
pub mod runtest;
pub mod common;
pub mod errors;

mod std {
    pub use core::cmp;
    pub use core::str;
    pub use core::sys;
    pub use core::unstable;
}

pub fn main() {
    let args = os::args();
    let config = parse_config(args);
    log_config(&config);
    run_tests(&config);
}

pub fn parse_config(args: ~[~str]) -> config {
    let opts =
        ~[getopts::reqopt("compile-lib-path"),
          getopts::reqopt("run-lib-path"),
          getopts::reqopt("rustc-path"), getopts::reqopt("src-base"),
          getopts::reqopt("build-base"), getopts::reqopt("aux-base"),
          getopts::reqopt("stage-id"),
          getopts::reqopt("mode"), getopts::optflag("ignored"),
          getopts::optopt("runtool"), getopts::optopt("rustcflags"),
          getopts::optflag("verbose"),
          getopts::optopt("logfile"),
          getopts::optflag("jit"),
          getopts::optflag("newrt"),
          getopts::optopt("target"),
          getopts::optopt("adb-path"),
          getopts::optopt("adb-test-dir")
         ];

    assert!(!args.is_empty());
    let args_ = vec::tail(args);
    let matches =
        &match getopts::getopts(args_, opts) {
          Ok(m) => m,
          Err(f) => fail!(getopts::fail_str(f))
        };

    fn opt_path(m: &getopts::Matches, nm: &str) -> Path {
        Path(getopts::opt_str(m, nm))
    }

    config {
        compile_lib_path: getopts::opt_str(matches, "compile-lib-path"),
        run_lib_path: getopts::opt_str(matches, "run-lib-path"),
        rustc_path: opt_path(matches, "rustc-path"),
        src_base: opt_path(matches, "src-base"),
        build_base: opt_path(matches, "build-base"),
        aux_base: opt_path(matches, "aux-base"),
        stage_id: getopts::opt_str(matches, "stage-id"),
        mode: str_mode(getopts::opt_str(matches, "mode")),
        run_ignored: getopts::opt_present(matches, "ignored"),
        filter:
             if !matches.free.is_empty() {
                 option::Some(copy matches.free[0])
             } else { option::None },
        logfile: getopts::opt_maybe_str(matches, "logfile").map(|s| Path(*s)),
        runtool: getopts::opt_maybe_str(matches, "runtool"),
        rustcflags: getopts::opt_maybe_str(matches, "rustcflags"),
        jit: getopts::opt_present(matches, "jit"),
        newrt: getopts::opt_present(matches, "newrt"),
        target: opt_str2(getopts::opt_maybe_str(matches, "target")).to_str(),
        adb_path: opt_str2(getopts::opt_maybe_str(matches, "adb-path")).to_str(),
        adb_test_dir:
            opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")).to_str(),
        adb_device_status:
            if (opt_str2(getopts::opt_maybe_str(matches, "target")) ==
                ~"arm-linux-androideabi") {
                if (opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")) !=
                    ~"(none)" &&
                    opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")) !=
                    ~"") { true }
                else { false }
            } else { false },
        verbose: getopts::opt_present(matches, "verbose")
    }
}

pub fn log_config(config: &config) {
    let c = config;
    logv(c, fmt!("configuration:"));
    logv(c, fmt!("compile_lib_path: %s", config.compile_lib_path));
    logv(c, fmt!("run_lib_path: %s", config.run_lib_path));
    logv(c, fmt!("rustc_path: %s", config.rustc_path.to_str()));
    logv(c, fmt!("src_base: %s", config.src_base.to_str()));
    logv(c, fmt!("build_base: %s", config.build_base.to_str()));
    logv(c, fmt!("stage_id: %s", config.stage_id));
    logv(c, fmt!("mode: %s", mode_str(config.mode)));
    logv(c, fmt!("run_ignored: %b", config.run_ignored));
    logv(c, fmt!("filter: %s", opt_str(&config.filter)));
    logv(c, fmt!("runtool: %s", opt_str(&config.runtool)));
    logv(c, fmt!("rustcflags: %s", opt_str(&config.rustcflags)));
    logv(c, fmt!("jit: %b", config.jit));
    logv(c, fmt!("newrt: %b", config.newrt));
    logv(c, fmt!("target: %s", config.target));
    logv(c, fmt!("adb_path: %s", config.adb_path));
    logv(c, fmt!("adb_test_dir: %s", config.adb_test_dir));
    logv(c, fmt!("adb_device_status: %b", config.adb_device_status));
    logv(c, fmt!("verbose: %b", config.verbose));
    logv(c, fmt!("\n"));
}

pub fn opt_str<'a>(maybestr: &'a Option<~str>) -> &'a str {
    match *maybestr {
        option::None => "(none)",
        option::Some(ref s) => {
            let s: &'a str = *s;
            s
        }
    }
}

pub fn opt_str2(maybestr: Option<~str>) -> ~str {
    match maybestr { None => ~"(none)", Some(s) => { s } }
}

pub fn str_opt(maybestr: ~str) -> Option<~str> {
    if maybestr != ~"(none)" { option::Some(maybestr) } else { option::None }
}

pub fn str_mode(s: ~str) -> mode {
    match s {
      ~"compile-fail" => mode_compile_fail,
      ~"run-fail" => mode_run_fail,
      ~"run-pass" => mode_run_pass,
      ~"pretty" => mode_pretty,
      ~"debug-info" => mode_debug_info,
      _ => fail!("invalid mode")
    }
}

pub fn mode_str(mode: mode) -> ~str {
    match mode {
      mode_compile_fail => ~"compile-fail",
      mode_run_fail => ~"run-fail",
      mode_run_pass => ~"run-pass",
      mode_pretty => ~"pretty",
      mode_debug_info => ~"debug-info",
    }
}

pub fn run_tests(config: &config) {
    let opts = test_opts(config);
    let tests = make_tests(config);
    let res = test::run_tests_console(&opts, tests);
    if !res { fail!("Some tests failed"); }
}

pub fn test_opts(config: &config) -> test::TestOpts {
    test::TestOpts {
        filter: copy config.filter,
        run_ignored: config.run_ignored,
        logfile: copy config.logfile,
        run_tests: true,
        run_benchmarks: false,
        save_results: option::None,
        compare_results: option::None
    }
}

pub fn make_tests(config: &config) -> ~[test::TestDescAndFn] {
    debug!("making tests from %s",
           config.src_base.to_str());
    let mut tests = ~[];
    let dirs = os::list_dir_path(&config.src_base);
    for dirs.iter().advance |file| {
        let file = copy *file;
        debug!("inspecting file %s", file.to_str());
        if is_test(config, file) {
            tests.push(make_test(config, file))
        }
    }
    tests
}

pub fn is_test(config: &config, testfile: &Path) -> bool {
    // Pretty-printer does not work with .rc files yet
    let valid_extensions =
        match config.mode {
          mode_pretty => ~[~".rs"],
          _ => ~[~".rc", ~".rs"]
        };
    let invalid_prefixes = ~[~".", ~"#", ~"~"];
    let name = testfile.filename().get();

    let mut valid = false;

    for valid_extensions.iter().advance |ext| {
        if name.ends_with(*ext) { valid = true; }
    }

    for invalid_prefixes.iter().advance |pre| {
        if name.starts_with(*pre) { valid = false; }
    }

    return valid;
}

pub fn make_test(config: &config, testfile: &Path) -> test::TestDescAndFn {
    test::TestDescAndFn {
        desc: test::TestDesc {
            name: make_test_name(config, testfile),
            ignore: header::is_test_ignored(config, testfile),
            should_fail: false
        },
        testfn: make_test_closure(config, testfile),
    }
}

pub fn make_test_name(config: &config, testfile: &Path) -> test::TestName {

    // Try to elide redundant long paths
    fn shorten(path: &Path) -> ~str {
        let filename = path.filename();
        let dir = path.pop().filename();
        fmt!("%s/%s", dir.get_or_default(~""), filename.get_or_default(~""))
    }

    test::DynTestName(fmt!("[%s] %s",
                           mode_str(config.mode),
                           shorten(testfile)))
}

pub fn make_test_closure(config: &config, testfile: &Path) -> test::TestFn {
    use core::cell::Cell;
    let config = Cell::new(copy *config);
    let testfile = Cell::new(testfile.to_str());
    test::DynTestFn(|| { runtest::run(config.take(), testfile.take()) })
}
<commit_msg>Whitespace<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[crate_type = "bin"];

#[allow(non_camel_case_types)];

#[no_core]; // XXX: Remove after snapshot
#[no_std];

extern mod core(name = "std", vers = "0.7-pre");
extern mod extra(name = "extra", vers = "0.7-pre");

use core::prelude::*;
use core::*;

use extra::getopts;
use extra::test;

use core::result::{Ok, Err};

use common::config;
use common::mode_run_pass;
use common::mode_run_fail;
use common::mode_compile_fail;
use common::mode_pretty;
use common::mode_debug_info;
use common::mode;
use util::logv;

pub mod procsrv;
pub mod util;
pub mod header;
pub mod runtest;
pub mod common;
pub mod errors;

mod std {
    pub use core::cmp;
    pub use core::str;
    pub use core::sys;
    pub use core::unstable;
}

pub fn main() {
    let args = os::args();
    let config = parse_config(args);
    log_config(&config);
    run_tests(&config);
}

pub fn parse_config(args: ~[~str]) -> config {
    let opts =
        ~[getopts::reqopt("compile-lib-path"),
          getopts::reqopt("run-lib-path"),
          getopts::reqopt("rustc-path"), getopts::reqopt("src-base"),
          getopts::reqopt("build-base"), getopts::reqopt("aux-base"),
          getopts::reqopt("stage-id"),
          getopts::reqopt("mode"), getopts::optflag("ignored"),
          getopts::optopt("runtool"), getopts::optopt("rustcflags"),
          getopts::optflag("verbose"),
          getopts::optopt("logfile"),
          getopts::optflag("jit"),
          getopts::optflag("newrt"),
          getopts::optopt("target"),
          getopts::optopt("adb-path"),
          getopts::optopt("adb-test-dir")
         ];

    assert!(!args.is_empty());
    let args_ = vec::tail(args);
    let matches =
        &match getopts::getopts(args_, opts) {
          Ok(m) => m,
          Err(f) => fail!(getopts::fail_str(f))
        };

    fn opt_path(m: &getopts::Matches, nm: &str) -> Path {
        Path(getopts::opt_str(m, nm))
    }

    config {
        compile_lib_path: getopts::opt_str(matches, "compile-lib-path"),
        run_lib_path: getopts::opt_str(matches, "run-lib-path"),
        rustc_path: opt_path(matches, "rustc-path"),
        src_base: opt_path(matches, "src-base"),
        build_base: opt_path(matches, "build-base"),
        aux_base: opt_path(matches, "aux-base"),
        stage_id: getopts::opt_str(matches, "stage-id"),
        mode: str_mode(getopts::opt_str(matches, "mode")),
        run_ignored: getopts::opt_present(matches, "ignored"),
        filter:
             if !matches.free.is_empty() {
                 option::Some(copy matches.free[0])
             } else { option::None },
        logfile: getopts::opt_maybe_str(matches, "logfile").map(|s| Path(*s)),
        runtool: getopts::opt_maybe_str(matches, "runtool"),
        rustcflags: getopts::opt_maybe_str(matches, "rustcflags"),
        jit: getopts::opt_present(matches, "jit"),
        newrt: getopts::opt_present(matches, "newrt"),
        target: opt_str2(getopts::opt_maybe_str(matches, "target")).to_str(),
        adb_path: opt_str2(getopts::opt_maybe_str(matches, "adb-path")).to_str(),
        adb_test_dir:
            opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")).to_str(),
        adb_device_status:
            if (opt_str2(getopts::opt_maybe_str(matches, "target")) ==
                ~"arm-linux-androideabi") {
                if (opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")) !=
                    ~"(none)" &&
                    opt_str2(getopts::opt_maybe_str(matches, "adb-test-dir")) !=
                    ~"") { true }
                else { false }
            } else { false },
        verbose: getopts::opt_present(matches, "verbose")
    }
}

pub fn log_config(config: &config) {
    let c = config;
    logv(c, fmt!("configuration:"));
    logv(c, fmt!("compile_lib_path: %s", config.compile_lib_path));
    logv(c, fmt!("run_lib_path: %s", config.run_lib_path));
    logv(c, fmt!("rustc_path: %s", config.rustc_path.to_str()));
    logv(c, fmt!("src_base: %s", config.src_base.to_str()));
    logv(c, fmt!("build_base: %s", config.build_base.to_str()));
    logv(c, fmt!("stage_id: %s", config.stage_id));
    logv(c, fmt!("mode: %s", mode_str(config.mode)));
    logv(c, fmt!("run_ignored: %b", config.run_ignored));
    logv(c, fmt!("filter: %s", opt_str(&config.filter)));
    logv(c, fmt!("runtool: %s", opt_str(&config.runtool)));
    logv(c, fmt!("rustcflags: %s", opt_str(&config.rustcflags)));
    logv(c, fmt!("jit: %b", config.jit));
    logv(c, fmt!("newrt: %b", config.newrt));
    logv(c, fmt!("target: %s", config.target));
    logv(c, fmt!("adb_path: %s", config.adb_path));
    logv(c, fmt!("adb_test_dir: %s", config.adb_test_dir));
    logv(c, fmt!("adb_device_status: %b", config.adb_device_status));
    logv(c, fmt!("verbose: %b", config.verbose));
    logv(c, fmt!("\n"));
}

pub fn opt_str<'a>(maybestr: &'a Option<~str>) -> &'a str {
    match *maybestr {
        option::None => "(none)",
        option::Some(ref s) => {
            let s: &'a str = *s;
            s
        }
    }
}

pub fn opt_str2(maybestr: Option<~str>) -> ~str {
    match maybestr { None => ~"(none)", Some(s) => { s } }
}

pub fn str_opt(maybestr: ~str) -> Option<~str> {
    if maybestr != ~"(none)" { option::Some(maybestr) } else { option::None }
}

pub fn str_mode(s: ~str) -> mode {
    match s {
      ~"compile-fail" => mode_compile_fail,
      ~"run-fail" => mode_run_fail,
      ~"run-pass" => mode_run_pass,
      ~"pretty" => mode_pretty,
      ~"debug-info" => mode_debug_info,
      _ => fail!("invalid mode")
    }
}

pub fn mode_str(mode: mode) -> ~str {
    match mode {
      mode_compile_fail => ~"compile-fail",
      mode_run_fail => ~"run-fail",
      mode_run_pass => ~"run-pass",
      mode_pretty => ~"pretty",
      mode_debug_info => ~"debug-info",
    }
}

pub fn run_tests(config: &config) {
    let opts = test_opts(config);
    let tests = make_tests(config);
    let res = test::run_tests_console(&opts, tests);
    if !res { fail!("Some tests failed"); }
}

pub fn test_opts(config: &config) -> test::TestOpts {
    test::TestOpts {
        filter: copy config.filter,
        run_ignored: config.run_ignored,
        logfile: copy config.logfile,
        run_tests: true,
        run_benchmarks: false,
        save_results: option::None,
        compare_results: option::None
    }
}

pub fn make_tests(config: &config) -> ~[test::TestDescAndFn] {
    debug!("making tests from %s",
           config.src_base.to_str());
    let mut tests = ~[];
    let dirs = os::list_dir_path(&config.src_base);
    for dirs.iter().advance |file| {
        let file = copy *file;
        debug!("inspecting file %s", file.to_str());
        if is_test(config, file) {
            tests.push(make_test(config, file))
        }
    }
    tests
}

pub fn is_test(config: &config, testfile: &Path) -> bool {
    // Pretty-printer does not work with .rc files yet
    let valid_extensions =
        match config.mode {
          mode_pretty => ~[~".rs"],
          _ => ~[~".rc", ~".rs"]
        };
    let invalid_prefixes = ~[~".", ~"#", ~"~"];
    let name = testfile.filename().get();

    let mut valid = false;

    for valid_extensions.iter().advance |ext| {
        if name.ends_with(*ext) { valid = true; }
    }

    for invalid_prefixes.iter().advance |pre| {
        if name.starts_with(*pre) { valid = false; }
    }

    return valid;
}

pub fn make_test(config: &config, testfile: &Path) -> test::TestDescAndFn {
    test::TestDescAndFn {
        desc: test::TestDesc {
            name: make_test_name(config, testfile),
            ignore: header::is_test_ignored(config, testfile),
            should_fail: false
        },
        testfn: make_test_closure(config, testfile),
    }
}

pub fn make_test_name(config: &config, testfile: &Path) -> test::TestName {

    // Try to elide redundant long paths
    fn shorten(path: &Path) -> ~str {
        let filename = path.filename();
        let dir = path.pop().filename();
        fmt!("%s/%s", dir.get_or_default(~""), filename.get_or_default(~""))
    }

    test::DynTestName(fmt!("[%s] %s",
                           mode_str(config.mode),
                           shorten(testfile)))
}

pub fn make_test_closure(config: &config, testfile: &Path) -> test::TestFn {
    use core::cell::Cell;
    let config = Cell::new(copy *config);
    let testfile = Cell::new(testfile.to_str());
    test::DynTestFn(|| { runtest::run(config.take(), testfile.take()) })
}
<|endoftext|>


<commit_before>use std::net::TcpStream;
use std::io::{self, Write};

use url;
use rustc_serialize::base64::{ToBase64, MIME};

use ogg::OggPage;

// TODO: Move mountpoint information into some serializable thing
// https://gist.github.com/ePirat/adc3b8ba00d85b7e3870#specifying-mountpoint-information
#[derive(RustcDecodable, Clone, Debug)]
pub struct IceCastWriterOptions {
    public: bool,
    name: Option<String>,
    description: Option<String>,
    url: Option<String>,
    genre: Option<String>,
}

impl IceCastWriterOptions {
    pub fn set_name(&mut self, name: &str) -> &mut Self {
        self.name = Some(name.to_string());
        self
    }

    pub fn set_description(&mut self, description: &str) -> &mut Self {
        self.description = Some(description.to_string());
        self
    }

    pub fn set_url(&mut self, url: &str) -> &mut Self {
        self.url = Some(url.to_string());
        self
    }

    pub fn set_genre(&mut self, genre: &str) -> &mut Self {
        self.genre = Some(genre.to_string());
        self
    }
}

impl Default for IceCastWriterOptions {
    fn default() -> IceCastWriterOptions {
        IceCastWriterOptions {
            public: false,
            name: None,
            description: None,
            url: None,
            genre: None,
        }
    }
}

pub struct IceCastWriter {
    stream: TcpStream,
    options: IceCastWriterOptions,
}

impl IceCastWriter {
    #[allow(dead_code)]
    pub fn new(url: &url::Url) -> io::Result<IceCastWriter> {
        IceCastWriter::with_options(url, &IceCastWriterOptions::default())
    }

    pub fn with_options(url: &url::Url, opts: &IceCastWriterOptions) -> io::Result<IceCastWriter> {
        let endpoint = try!(get_endpoint(url).ok_or_else(|| {
            io::Error::new(io::ErrorKind::Other, "Missing hostname in URL")
        }));

        let stream = try!(TcpStream::connect(&endpoint[..]));
        let mut writer = IceCastWriter {
            stream: stream,
            options: opts.clone(),
        };
        try!(writer.send_header(url));
        Ok(writer)
    }

    fn send_header(&mut self, url: &url::Url) -> io::Result<()> {
        let options = &self.options;

        let mount = try!(url.serialize_path().ok_or_else(|| {
            io::Error::new(io::ErrorKind::Other, "Missing path in URL")
        }));
        try!(write!(self.stream, "SOURCE {} HTTP/1.0\r\n", mount));

        if let Some(userpass) = get_authorization_header(url) {
            try!(write!(self.stream, "{}\r\n", userpass));
        }
        if let Some(host) = get_host_header(url) {
            // TODO: Verify this
            try!(write!(self.stream, "{}\r\n", host));
        }

        try!(write!(self.stream, "Accept: */*"));
        try!(write!(self.stream, "User-Agent: ireul\r\n"));

        if options.public {
            try!(write!(self.stream, "Ice-Public: 1\r\n"));
        }

        if let Some(ref name) = options.name {
            try!(write!(self.stream, "Ice-Name: {}\r\n", name));
        }

        if let Some(ref description) = options.description {
            try!(write!(self.stream, "Ice-Description: {}\r\n", description));
        }

        if let Some(ref url) = options.url {
            try!(write!(self.stream, "Ice-Url: {}\r\n", url));
        }

        if let Some(ref genre) = options.genre {
            try!(write!(self.stream, "Ice-Genre: {}\r\n", genre));
        }

        // Do not reorder Content-Type! Somehow IceCast treated it as audio/mpeg when moved up
        try!(write!(self.stream, "Content-Type: audio/ogg\r\n"));

        // IceCast responds with some headers and a HTTP OK, but they're not parsed yet
        self.stream.write_all(b"\r\n")
    }

    pub fn send_ogg_page(&mut self, page: &OggPage) -> io::Result<()> {
        self.stream.write_all(page.as_u8_slice())
    }
}

fn get_endpoint(url: &url::Url) -> Option<String> {
    match (url.domain(), url.port()) {
        (None, _) => None,
        (Some(domain), None) => {
            Some(format!("{}:8000", domain))
        }
        (Some(domain), Some(port)) => {
            Some(format!("{}:{}", domain, port))
        }
    }
}

fn get_host_header(url: &url::Url) -> Option<String> {
    match get_endpoint(url) {
        None => None,
        Some(endpoint) => Some(format!("Host: {}", endpoint)),
    }
}

fn get_authorization_header(url: &url::Url) -> Option<String> {
    let mut emit = false;
    let mut userpass = String::new();

    if let Some(user) = url.username() {
        emit = true;
        userpass.push_str(user);
    }
    if let Some(password) = url.password() {
        emit = true;
        userpass.push_str(":");
        userpass.push_str(password);
    }

    let mut config = MIME;
    config.line_length = None;
    let userpass_b64 = userpass.as_bytes().to_base64(config);

    match emit {
        true => Some(format!("Authorization: Basic {}", userpass_b64)),
        false => None,
    }
}
<commit_msg>core: Add timeouts to IceCastWriter<commit_after>use std::net::TcpStream;
use std::io::{self, Write};

use url;
use rustc_serialize::base64::{ToBase64, MIME};

use ogg::OggPage;

// TODO: Move mountpoint information into some serializable thing
// https://gist.github.com/ePirat/adc3b8ba00d85b7e3870#specifying-mountpoint-information
#[derive(RustcDecodable, Clone, Debug)]
pub struct IceCastWriterOptions {
    public: bool,
    name: Option<String>,
    description: Option<String>,
    url: Option<String>,
    genre: Option<String>,
}

impl IceCastWriterOptions {
    pub fn set_name(&mut self, name: &str) -> &mut Self {
        self.name = Some(name.to_string());
        self
    }

    pub fn set_description(&mut self, description: &str) -> &mut Self {
        self.description = Some(description.to_string());
        self
    }

    pub fn set_url(&mut self, url: &str) -> &mut Self {
        self.url = Some(url.to_string());
        self
    }

    pub fn set_genre(&mut self, genre: &str) -> &mut Self {
        self.genre = Some(genre.to_string());
        self
    }
}

impl Default for IceCastWriterOptions {
    fn default() -> IceCastWriterOptions {
        IceCastWriterOptions {
            public: false,
            name: None,
            description: None,
            url: None,
            genre: None,
        }
    }
}

pub struct IceCastWriter {
    stream: TcpStream,
    options: IceCastWriterOptions,
}

impl IceCastWriter {
    #[allow(dead_code)]
    pub fn new(url: &url::Url) -> io::Result<IceCastWriter> {
        IceCastWriter::with_options(url, &IceCastWriterOptions::default())
    }

    pub fn with_options(url: &url::Url, opts: &IceCastWriterOptions) -> io::Result<IceCastWriter> {
        let endpoint = try!(get_endpoint(url).ok_or_else(|| {
            io::Error::new(io::ErrorKind::Other, "Missing hostname in URL")
        }));

        let mut stream = try!(TcpStream::connect(&endpoint[..]));
        try!(tcp_stream_setup(&mut stream));
        let mut writer = IceCastWriter {
            stream: stream,
            options: opts.clone(),
        };
        try!(writer.send_header(url));
        Ok(writer)
    }

    fn send_header(&mut self, url: &url::Url) -> io::Result<()> {
        let options = &self.options;

        let mount = try!(url.serialize_path().ok_or_else(|| {
            io::Error::new(io::ErrorKind::Other, "Missing path in URL")
        }));
        try!(write!(self.stream, "SOURCE {} HTTP/1.0\r\n", mount));

        if let Some(userpass) = get_authorization_header(url) {
            try!(write!(self.stream, "{}\r\n", userpass));
        }
        if let Some(host) = get_host_header(url) {
            // TODO: Verify this
            try!(write!(self.stream, "{}\r\n", host));
        }

        try!(write!(self.stream, "Accept: */*"));
        try!(write!(self.stream, "User-Agent: ireul\r\n"));

        if options.public {
            try!(write!(self.stream, "Ice-Public: 1\r\n"));
        }

        if let Some(ref name) = options.name {
            try!(write!(self.stream, "Ice-Name: {}\r\n", name));
        }

        if let Some(ref description) = options.description {
            try!(write!(self.stream, "Ice-Description: {}\r\n", description));
        }

        if let Some(ref url) = options.url {
            try!(write!(self.stream, "Ice-Url: {}\r\n", url));
        }

        if let Some(ref genre) = options.genre {
            try!(write!(self.stream, "Ice-Genre: {}\r\n", genre));
        }

        // Do not reorder Content-Type! Somehow IceCast treated it as audio/mpeg when moved up
        try!(write!(self.stream, "Content-Type: audio/ogg\r\n"));

        // IceCast responds with some headers and a HTTP OK, but they're not parsed yet
        self.stream.write_all(b"\r\n")
    }

    pub fn send_ogg_page(&mut self, page: &OggPage) -> io::Result<()> {
        self.stream.write_all(page.as_u8_slice())
    }
}

fn tcp_stream_setup(stream: &mut TcpStream) -> io::Result<()> {
    use std::time::Duration;

    try!(stream.set_read_timeout(Some(Duration::new(10, 0))));
    try!(stream.set_write_timeout(Some(Duration::new(10, 0))));
    Ok(())
}

fn get_endpoint(url: &url::Url) -> Option<String> {
    match (url.domain(), url.port()) {
        (None, _) => None,
        (Some(domain), None) => {
            Some(format!("{}:8000", domain))
        }
        (Some(domain), Some(port)) => {
            Some(format!("{}:{}", domain, port))
        }
    }
}

fn get_host_header(url: &url::Url) -> Option<String> {
    match get_endpoint(url) {
        None => None,
        Some(endpoint) => Some(format!("Host: {}", endpoint)),
    }
}

fn get_authorization_header(url: &url::Url) -> Option<String> {
    let mut emit = false;
    let mut userpass = String::new();

    if let Some(user) = url.username() {
        emit = true;
        userpass.push_str(user);
    }
    if let Some(password) = url.password() {
        emit = true;
        userpass.push_str(":");
        userpass.push_str(password);
    }

    let mut config = MIME;
    config.line_length = None;
    let userpass_b64 = userpass.as_bytes().to_base64(config);

    match emit {
        true => Some(format!("Authorization: Basic {}", userpass_b64)),
        false => None,
    }
}
<|endoftext|>


<commit_before>#![crate_name = "compress#0.1"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![comment = "Various compression algorithms written in rust."]
#![deny(missing_doc)]
#![feature(macro_rules, phase)]

//! dox (placeholder)

#[phase(plugin, link)]
extern crate log;
extern crate debug;

#[cfg(test)] extern crate rand;
#[cfg(test)] extern crate test;

/// Public exports
pub use Adler32 = self::checksum::adler::State32;

/// Checksum algorithms
// http://en.wikipedia.org/wiki/Checksum
pub mod checksum {
    pub mod adler;
}

pub mod bwt;
pub mod flate;
pub mod lz4;
pub mod zlib;

/// Entropy coder family
// http://en.wikipedia.org/wiki/Entropy_encoding
pub mod entropy {
    pub mod ari;
}
<commit_msg>Valid crate name!<commit_after>#![crate_name = "compress"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![comment = "Various compression algorithms written in rust."]
#![deny(missing_doc)]
#![feature(macro_rules, phase)]

//! dox (placeholder)

#[phase(plugin, link)]
extern crate log;
extern crate debug;

#[cfg(test)] extern crate rand;
#[cfg(test)] extern crate test;

/// Public exports
pub use Adler32 = self::checksum::adler::State32;

/// Checksum algorithms
// http://en.wikipedia.org/wiki/Checksum
pub mod checksum {
    pub mod adler;
}

pub mod bwt;
pub mod flate;
pub mod lz4;
pub mod zlib;

/// Entropy coder family
// http://en.wikipedia.org/wiki/Entropy_encoding
pub mod entropy {
    pub mod ari;
}
<|endoftext|>


<commit_before>use spin::Once;
use x86_64::instructions::segmentation::set_cs;
use x86_64::instructions::tables::{lidt, load_tss};
use x86_64::structures::gdt::SegmentSelector;
use x86_64::structures::idt::InterruptStackFrame;
use x86_64::structures::tss::TaskStateSegment;
use x86_64::structures::DescriptorTablePointer;
use x86_64::PrivilegeLevel;
use x86_64::VirtAddr;

use core::fmt;
use core::mem::{self, MaybeUninit};
use core::ptr;

use crate::memory::{self, MemoryController};

#[macro_use]
mod macros;
mod gdt;
mod handler;
pub mod idt;

use self::handler::*;

#[derive(Clone, Copy)]
#[repr(C, packed)]
pub struct ExceptionStackFrame {
    instruction_pointer: u64,
    code_segment: u64,
    cpu_flags: u64,
    stack_pointer: u64,
    stack_segment: u64,
}
impl fmt::Display for ExceptionStackFrame {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let ip = self.instruction_pointer;
        let cs = self.code_segment;
        let fl = self.cpu_flags;
        let sp = self.stack_pointer;
        let ss = self.stack_segment;

        write!(
            f,
            concat!(
                "ExceptionStackFrame {{\n",
                "  rip: {:#x},\n",
                "  cs: {:#x},\n",
                "  flags: {:#x},\n",
                "  rsp: {:#x},\n",
                "  ss: {:#x}\n",
                "}}"
            ),
            ip, cs, fl, sp, ss
        )
    }
}
impl fmt::Debug for ExceptionStackFrame {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self)
    }
}

/// Write process descriptor tables (IDT, GDT) to given address
pub unsafe fn write_process_dts(dst: VirtAddr, idt_table: VirtAddr) {
    use x86_64::structures::gdt::DescriptorFlags as GDTF;

    let idt_desc_size = mem::size_of::<idt::Descriptor>();
    let idt_size_bytes = idt_desc_size * idt::ENTRY_COUNT;
    let call_instruction_size: u64 = 5; // Call instruction size in bytes

    // Write IDT
    for index in 0..idt::ENTRY_COUNT {
        let table_offset = index as u64 * call_instruction_size; // Jump table offset
        ptr::write(
            (dst + index * idt_desc_size).as_mut_ptr(),
            idt::Descriptor::new_no_ist(
                true,
                idt_table.as_u64() + table_offset,
                PrivilegeLevel::Ring0,
            ),
        );
    }

    // Write GDT
    let gdt_null_entry = GDTF::empty();
    let gdt_kernel_code = GDTF::USER_SEGMENT | GDTF::PRESENT | GDTF::EXECUTABLE | GDTF::LONG_MODE;
    ptr::write((dst + idt_size_bytes).as_mut_ptr(), gdt_null_entry);
    ptr::write((dst + (idt_size_bytes + 8)).as_mut_ptr(), gdt_kernel_code);
}

pub fn init() {
    let mut handlers: [idt::Descriptor; idt::ENTRY_COUNT] =
        [idt::Descriptor::new(false, 0, PrivilegeLevel::Ring0, 0); idt::ENTRY_COUNT];

    // Bind exception handlers
    handlers[0x00] = simple_exception_handler!("Divide-by-zero Error");
    handlers[0x03] = exception_handler!(exception_bp);
    handlers[0x06] = exception_handler!(exception_ud);
    handlers[0x08] = exception_handler_with_error_code!(exception_df, PrivilegeLevel::Ring0, 5);
    handlers[0x0b] = exception_handler_with_error_code!(exception_snp);
    handlers[0x0d] = exception_handler_with_error_code!(exception_gpf);
    handlers[0x0e] = exception_handler_with_error_code!(exception_pf);
    handlers[0x20] = irq_handler_switch!(exception_irq0);
    handlers[0x21] = irq_handler!(exception_irq1);
    handlers[0x21] = irq_handler!(exception_irq7);
    handlers[0x2e] = irq_handler!(exception_irq14);
    handlers[0x2e] = irq_handler!(exception_irq15);

    for index in 0..idt::ENTRY_COUNT {
        unsafe {
            ptr::write_volatile(
                (idt::ADDRESS + index * mem::size_of::<idt::Descriptor>()) as *mut _,
                handlers[index],
            );
        }
    }

    rprintln!("Loading new IDT...");

    unsafe {
        lidt(&DescriptorTablePointer {
            limit: (idt::ENTRY_COUNT * mem::size_of::<idt::Descriptor>()) as u16 - 1,
            base: idt::ADDRESS as u64,
        });
    }

    rprintln!("Enabled.");
}

static GDT: Once<gdt::GdtBuilder> = Once::new();
static TSS: Once<TaskStateSegment> = Once::new();

pub fn init_after_memory() {
    rprintln!("Swithcing to new GDT and TSS...");
    // Initialize TSS
    let double_fault_stack = memory::configure(|mem_ctrl: &mut MemoryController| {
        mem_ctrl
            .alloc_stack(1)
            .expect("could not allocate double fault stack")
    });

    let tss = TSS.call_once(|| {
        let mut tss = TaskStateSegment::new();
        tss.interrupt_stack_table[gdt::DOUBLE_FAULT_IST_INDEX] =
            VirtAddr::new(double_fault_stack.top.as_u64());
        tss
    });

    let mut code_selector: MaybeUninit<SegmentSelector> = MaybeUninit::uninit();
    let mut tss_selector: MaybeUninit<SegmentSelector> = MaybeUninit::uninit();

    let gdt = GDT.call_once(|| {
        let mut gdt = unsafe { gdt::GdtBuilder::new(VirtAddr::new_unchecked(0x1000)) };
        code_selector.write(gdt.add_entry(gdt::Descriptor::kernel_code_segment()));
        tss_selector.write(gdt.add_entry(gdt::Descriptor::tss_segment(&tss)));
        gdt
    });

    unsafe {
        // load GDT
        gdt.load();
        // reload code segment register
        set_cs(code_selector.assume_init());
        // load TSS
        load_tss(tss_selector.assume_init());
        // Write syscall address
        ptr::write(
            0x2000u64 as *mut u64,
            handler::process_interrupt as *const u64 as u64,
        );
    }
}

pub fn enable_external_interrupts() {
    rprintln!("Enabling external interrupts");

    unsafe {
        asm!("sti" :::: "volatile", "intel");
    }

    rprintln!("Done.");
}

pub fn disable_external_interrupts() {
    rprintln!("Enabling external interrupts");

    unsafe {
        asm!("cli" :::: "volatile", "intel");
    }

    rprintln!("Done.");
}
<commit_msg>Fix incorrect log message<commit_after>use spin::Once;
use x86_64::instructions::segmentation::set_cs;
use x86_64::instructions::tables::{lidt, load_tss};
use x86_64::structures::gdt::SegmentSelector;
use x86_64::structures::idt::InterruptStackFrame;
use x86_64::structures::tss::TaskStateSegment;
use x86_64::structures::DescriptorTablePointer;
use x86_64::PrivilegeLevel;
use x86_64::VirtAddr;

use core::fmt;
use core::mem::{self, MaybeUninit};
use core::ptr;

use crate::memory::{self, MemoryController};

#[macro_use]
mod macros;
mod gdt;
mod handler;
pub mod idt;

use self::handler::*;

#[derive(Clone, Copy)]
#[repr(C, packed)]
pub struct ExceptionStackFrame {
    instruction_pointer: u64,
    code_segment: u64,
    cpu_flags: u64,
    stack_pointer: u64,
    stack_segment: u64,
}
impl fmt::Display for ExceptionStackFrame {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let ip = self.instruction_pointer;
        let cs = self.code_segment;
        let fl = self.cpu_flags;
        let sp = self.stack_pointer;
        let ss = self.stack_segment;

        write!(
            f,
            concat!(
                "ExceptionStackFrame {{\n",
                "  rip: {:#x},\n",
                "  cs: {:#x},\n",
                "  flags: {:#x},\n",
                "  rsp: {:#x},\n",
                "  ss: {:#x}\n",
                "}}"
            ),
            ip, cs, fl, sp, ss
        )
    }
}
impl fmt::Debug for ExceptionStackFrame {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self)
    }
}

/// Write process descriptor tables (IDT, GDT) to given address
pub unsafe fn write_process_dts(dst: VirtAddr, idt_table: VirtAddr) {
    use x86_64::structures::gdt::DescriptorFlags as GDTF;

    let idt_desc_size = mem::size_of::<idt::Descriptor>();
    let idt_size_bytes = idt_desc_size * idt::ENTRY_COUNT;
    let call_instruction_size: u64 = 5; // Call instruction size in bytes

    // Write IDT
    for index in 0..idt::ENTRY_COUNT {
        let table_offset = index as u64 * call_instruction_size; // Jump table offset
        ptr::write(
            (dst + index * idt_desc_size).as_mut_ptr(),
            idt::Descriptor::new_no_ist(
                true,
                idt_table.as_u64() + table_offset,
                PrivilegeLevel::Ring0,
            ),
        );
    }

    // Write GDT
    let gdt_null_entry = GDTF::empty();
    let gdt_kernel_code = GDTF::USER_SEGMENT | GDTF::PRESENT | GDTF::EXECUTABLE | GDTF::LONG_MODE;
    ptr::write((dst + idt_size_bytes).as_mut_ptr(), gdt_null_entry);
    ptr::write((dst + (idt_size_bytes + 8)).as_mut_ptr(), gdt_kernel_code);
}

pub fn init() {
    let mut handlers: [idt::Descriptor; idt::ENTRY_COUNT] =
        [idt::Descriptor::new(false, 0, PrivilegeLevel::Ring0, 0); idt::ENTRY_COUNT];

    // Bind exception handlers
    handlers[0x00] = simple_exception_handler!("Divide-by-zero Error");
    handlers[0x03] = exception_handler!(exception_bp);
    handlers[0x06] = exception_handler!(exception_ud);
    handlers[0x08] = exception_handler_with_error_code!(exception_df, PrivilegeLevel::Ring0, 5);
    handlers[0x0b] = exception_handler_with_error_code!(exception_snp);
    handlers[0x0d] = exception_handler_with_error_code!(exception_gpf);
    handlers[0x0e] = exception_handler_with_error_code!(exception_pf);
    handlers[0x20] = irq_handler_switch!(exception_irq0);
    handlers[0x21] = irq_handler!(exception_irq1);
    handlers[0x21] = irq_handler!(exception_irq7);
    handlers[0x2e] = irq_handler!(exception_irq14);
    handlers[0x2e] = irq_handler!(exception_irq15);

    for index in 0..idt::ENTRY_COUNT {
        unsafe {
            ptr::write_volatile(
                (idt::ADDRESS + index * mem::size_of::<idt::Descriptor>()) as *mut _,
                handlers[index],
            );
        }
    }

    rprintln!("Loading new IDT...");

    unsafe {
        lidt(&DescriptorTablePointer {
            limit: (idt::ENTRY_COUNT * mem::size_of::<idt::Descriptor>()) as u16 - 1,
            base: idt::ADDRESS as u64,
        });
    }

    rprintln!("Enabled.");
}

static GDT: Once<gdt::GdtBuilder> = Once::new();
static TSS: Once<TaskStateSegment> = Once::new();

pub fn init_after_memory() {
    rprintln!("Swithcing to new GDT and TSS...");
    // Initialize TSS
    let double_fault_stack = memory::configure(|mem_ctrl: &mut MemoryController| {
        mem_ctrl
            .alloc_stack(1)
            .expect("could not allocate double fault stack")
    });

    let tss = TSS.call_once(|| {
        let mut tss = TaskStateSegment::new();
        tss.interrupt_stack_table[gdt::DOUBLE_FAULT_IST_INDEX] =
            VirtAddr::new(double_fault_stack.top.as_u64());
        tss
    });

    let mut code_selector: MaybeUninit<SegmentSelector> = MaybeUninit::uninit();
    let mut tss_selector: MaybeUninit<SegmentSelector> = MaybeUninit::uninit();

    let gdt = GDT.call_once(|| {
        let mut gdt = unsafe { gdt::GdtBuilder::new(VirtAddr::new_unchecked(0x1000)) };
        code_selector.write(gdt.add_entry(gdt::Descriptor::kernel_code_segment()));
        tss_selector.write(gdt.add_entry(gdt::Descriptor::tss_segment(&tss)));
        gdt
    });

    unsafe {
        // load GDT
        gdt.load();
        // reload code segment register
        set_cs(code_selector.assume_init());
        // load TSS
        load_tss(tss_selector.assume_init());
        // Write syscall address
        ptr::write(
            0x2000u64 as *mut u64,
            handler::process_interrupt as *const u64 as u64,
        );
    }
}

pub fn enable_external_interrupts() {
    rprintln!("Enabling external interrupts");

    unsafe {
        asm!("sti" :::: "volatile", "intel");
    }

    rprintln!("Done.");
}

pub fn disable_external_interrupts() {
    rprintln!("Disabling external interrupts");

    unsafe {
        asm!("cli" :::: "volatile", "intel");
    }

    rprintln!("Done.");
}
<|endoftext|>