<commit_before>use std::fs::File;
use std::collections::HashMap;
use std::io::BufReader;
use std::borrow::Cow;

use encoding::{Encoding, DecoderTrap};
use encoding::all::UTF_16LE;

use errors::*;
use {ExcelReader, Range, DataType, CellErrorType};
use vba::VbaProject;
use cfb::Cfb;
use utils::{read_u16, read_u32, read_slice};

enum CfbWrap {
    Wb(Cfb, BufReader<File>),
    Vba(VbaProject),
}

/// A struct representing an old xls format file (CFB)
pub struct Xls {
    sheets: HashMap<String, Range>,
    strings: Vec<String>,
    cfb: Option<CfbWrap>,
}

impl ExcelReader for Xls {

    fn new(r: File) -> Result<Self> {
        let len = try!(r.metadata()).len() as usize;
        let mut r = BufReader::new(r);
        let mut cfb = try!(Cfb::new(&mut r, len ));
        let wb = try!(cfb.get_stream("Workbook", &mut r));

        let mut xls = Xls {
            sheets: HashMap::new(),
            strings: Vec::new(),
            cfb: Some(CfbWrap::Wb(cfb, r)),
        };
        try!(xls.parse_workbook(&wb));
        Ok(xls)
    }

    fn has_vba(&mut self) -> bool {
        match self.cfb {
            Some(CfbWrap::Wb(ref cfb, _)) => cfb.has_directory("_VBA_PROJECT_CUR"),
            Some(CfbWrap::Vba(_)) => true,
            None => unreachable!(), // option is used to transfer ownership only
        }
    }

    fn vba_project(&mut self) -> Result<Cow<VbaProject>> {
        if let Some(CfbWrap::Wb(..)) = self.cfb {
            match self.cfb.take() {
                Some(CfbWrap::Wb(cfb, mut r)) => {
                    let vba = try!(VbaProject::from_cfb(&mut r, cfb));
                    self.cfb = Some(CfbWrap::Vba(vba));
                },
                _ => unreachable!(),
            }
        }

        match self.cfb {
            Some(CfbWrap::Vba(ref v)) => Ok(Cow::Borrowed(v)),
            _ => unreachable!(),
        }
    }

    /// Parses Workbook stream, no need for the relationships variable
    fn read_sheets_names(&mut self, _: &HashMap<Vec<u8>, String>)
        -> Result<HashMap<String, String>> {
        Ok(self.sheets.keys().map(|k| (k.to_string(), k.to_string())).collect())
    }

    fn read_shared_strings(&mut self) -> Result<Vec<String>> {
        Ok(self.strings.clone())
    }

    fn read_relationships(&mut self) -> Result<HashMap<Vec<u8>, String>> {
        Ok(HashMap::new())
    }

    fn read_worksheet_range(&mut self, name: &str, _: &[String]) -> Result<Range> {
        match self.sheets.get(name) {
            None => Err(format!("Sheet '{}' does not exist", name).into()),
            Some(r) => Ok(r.clone()),
        }
    }
}

impl Xls {
    fn parse_workbook(&mut self, stream: &[u8]) -> Result<()> {

        let mut sheets = Vec::new();
        {
            let mut wb = stream;
            let records = RecordIter { stream: &mut wb };
            for record in records {
                let r = try!(record);
                match r.typ {
                    0x0009 => if read_u16(&r.data[2..]) != 0x0005 {
                        return Err("Expecting Workbook BOF".into());
                    }, // BOF,
                    0x013D => {
                        let sheet_len = r.data.len() / 2;
                        sheets.reserve(sheet_len);
                    }, // RRTabId
                    0x0085 => sheets.push(try!(parse_sheet_name(r.data))), // BoundSheet8
                    0x00FC => self.strings = try!(parse_sst(r.data)), // SST
                    0x000A => break, // EOF,
                    _ => (),
                }
            }
        }

        'sh: for (pos, name) in sheets.into_iter() {
            let mut sh = &stream[pos..];
            let records = RecordIter { stream: &mut sh };
            let mut range = Range::default();
            for record in records {
                let r = try!(record);
                match r.typ {
                    0x0009 => if read_u16(&r.data[2..]) != 0x0010 { continue 'sh; }, // BOF, worksheet
                    0x0200 => range = try!(parse_dimensions(r.data)), // Dimensions
                    0x0203 => try!(parse_number(r.data, &mut range)), // Number
                    0x0205 => try!(parse_bool_err(r.data, &mut range)), // BoolErr
                    0x027E => try!(parse_rk(r.data, &mut range)), // RK
                    0x00FD => try!(parse_label_sst(r.data, &self.strings, &mut range)), // LabelSst
                    0x000A => break, // EOF,
                    _ => (),
                }
            }
            self.sheets.insert(name, range);
        }
        Ok(())
    }
}

fn parse_sheet_name(r: &[u8]) -> Result<(usize, String)> {
    let pos = read_u32(r) as usize;
    let sheet = try!(parse_short_string(&r[6..]));
    Ok((pos, sheet))
}

fn parse_sst(r: &[u8]) -> Result<Vec<String>> {
    if r.len() < 8 {
        return Err("Invalid sst length".into());
    }
    let len = read_slice::<i32>(&r[4..]) as usize;
    let mut sst = Vec::with_capacity(len);
    let mut read = &mut &r[8..];
    for _ in 0..len {
        sst.push(try!(read_rich_extended_string(read)));
    }
    Ok(sst)
}

fn parse_number(r: &[u8], range: &mut Range) -> Result<()> {
    if r.len() < 14 {
        return Err("Invalid number length".into());
    }
    let row = read_u16(r);
    let col = read_u16(&r[2..]);
    let v = read_slice::<f64>(&r[6..]);
    range.set_value((row as u32, col as u32), DataType::Float(v))
}

fn parse_bool_err(r: &[u8], range: &mut Range) -> Result<()> {
    if r.len() < 8 {
        return Err("Invalid BoolErr length".into());
    }
    let row = read_u16(r);
    let col = read_u16(&r[2..]);
    let v = match r[7] {
        0x00 => DataType::Bool(r[6] != 0),
        0x01 => match r[6] {
            0x00 => DataType::Error(CellErrorType::Null),
            0x07 => DataType::Error(CellErrorType::Div0),
            0x0F => DataType::Error(CellErrorType::Value),
            0x17 => DataType::Error(CellErrorType::Ref),
            0x1D => DataType::Error(CellErrorType::Name),
            0x24 => DataType::Error(CellErrorType::Num),
            0x2A => DataType::Error(CellErrorType::NA),
            0x2B => DataType::Error(CellErrorType::GettingData),
            e => return Err(format!("Unrecognized error {:x}", e).into()),
        },
        e => return Err(format!("Unrecognized fError {:x}", e).into()),
    };
    range.set_value((row as u32, col as u32), v)
}

fn parse_rk(r: &[u8], range: &mut Range) -> Result<()> {
    if r.len() < 10 {
        return Err("Invalid rk length".into());
    }
    let row = read_u16(r);
    let col = read_u16(&r[2..]);

    let d100 = (r[6] & 1) != 0;
    let is_int = (r[6] & 2) != 0;

    let mut v = [0u8; 8];
    v[4..].copy_from_slice(&r[6..10]);
    v[0] &= 0xFC;
    let v = if is_int {
        let v = (read_slice::<i32>(&v[4..]) >> 2) as i64;
        DataType::Int( if d100 { v/100 } else { v })
    } else {
        let v = read_slice(&v);
        DataType::Float( if d100 { v/100.0 } else { v })
    };

    range.set_value((row as u32, col as u32), v)
}

fn parse_short_string(r: &[u8]) -> Result<String> {
    if r.len() < 2 {
        return Err("Invalid short string length".into());
    }
    let mut len = r[0] as usize;
    let zero_high_byte = r[1] == 0;
    if zero_high_byte {
        if r.len() < 2 + len {
            return Err(format!("Invalid short string length {} < {}", r.len(), 2 + len).into());
        }
        ::std::str::from_utf8(&r[2..2 + len]).map(|s| s.to_string()).map_err(|e| e.into())
    } else {
        len *= 2;
        if r.len() < 2 + len {
            return Err(format!("Invalid short string length {} < {}", r.len(), 2 + len).into());
        }
        UTF_16LE.decode(&r[2..2 + len], DecoderTrap::Ignore).map_err(|e| e.to_string().into())
    }
}

fn parse_label_sst(r: &[u8], strings: &[String], range: &mut Range) -> Result<()> {
    if r.len() < 10 {
        return Err("Invalid short string length".into());
    }
    let row = read_u16(r);
    let col = read_u16(&r[2..]);
    let i = read_u32(&r[6..]) as usize;
    range.set_value((row as u32, col as u32), DataType::String(strings[i].clone()))
}

fn parse_dimensions(r: &[u8]) -> Result<Range> {
    if r.len() != 14 {
        return Err("Invalid dimensions lengths".into());
    }
    let rw_first = read_u32(&r[0..4]);
    let rw_last = read_u32(&r[4..8]) - 1;
    let col_first = read_u16(&r[8..10]);
    let col_last = read_u16(&r[10..12]) - 1;

    let start = (rw_first, col_first as u32);
    let size = ((rw_last - rw_first + 1) as usize, (col_last - col_first + 1) as usize);

    Ok(Range::new(start, size))
}

fn read_rich_extended_string(r: &mut &[u8]) -> Result<String> {
    if r.len() < 3 {
        return Err("Invalid rich extended string length".into());
    }

    let mut len = read_u16(r) as usize;
    let mut start = 3;
    let flags = r[2];
    let high_byte = flags & 0x1;
    let ext_st = flags & 0x4;
    let rich_st = flags & 0x8;
    let str_len = len;

    if rich_st != 0 {
        len += 4 * read_u16(&r[start..]) as usize;
        start += 2;
    }
    if ext_st != 0 {
        len += read_slice::<i32>(&r[start..]) as usize;
        start += 4;
    }

    let s = if high_byte == 0 {
        if r.len() < start + len {
            return Err(format!("Invalid rich extended string \
                                length: {} < {}", r.len(), start + len).into());
        }
        ::std::str::from_utf8(&r[start..start + str_len]).map(|s| s.to_string()).map_err(|e| e.into())
    } else {
        len += str_len;
        if r.len() < start + len {
            return Err(format!("Invalid rich extended string \
                                length: {} < {}", r.len(), start + len).into());
        }
        UTF_16LE.decode(&r[start..start + 2 * str_len], DecoderTrap::Ignore).map_err(|e| e.to_string().into())
    };

    *r = &r[start + len..];
    s
}

struct Record<'a> {
    typ: u16,
    data: &'a [u8],
}

struct RecordIter<'a> {
    stream: &'a[u8],
}

impl<'a> Iterator for RecordIter<'a> {
    type Item=Result<Record<'a>>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.stream.len() < 4 {
            return if self.stream.is_empty() {
                None
            } else {
                Some(Err("Expecting record type and length, found end of stream".into()))
            }
        }
        let t = read_u16(self.stream);
        let len = read_u16(&self.stream[2..]) as usize;
        if self.stream.len() < len + 4 {
            return Some(Err("Expecting record length, found end of stream".into()));
        }
        let (data, next) = self.stream.split_at(len + 4);
        self.stream = next;
        Some(Ok(Record { typ: t, data: &data[4..] }))
    }
}
<commit_msg>force 2 bytes encoding on xls<commit_after>use std::fs::File;
use std::collections::HashMap;
use std::io::BufReader;
use std::borrow::Cow;

use encoding::{Encoding, DecoderTrap};
use encoding::all::UTF_16LE;

use errors::*;
use {ExcelReader, Range, DataType, CellErrorType};
use vba::VbaProject;
use cfb::Cfb;
use utils::{read_u16, read_u32, read_slice};

enum CfbWrap {
    Wb(Cfb, BufReader<File>),
    Vba(VbaProject),
}

/// A struct representing an old xls format file (CFB)
pub struct Xls {
    codepage: u16,
    sheets: HashMap<String, Range>,
    strings: Vec<String>,
    cfb: Option<CfbWrap>,
}

impl ExcelReader for Xls {

    fn new(r: File) -> Result<Self> {
        let len = try!(r.metadata()).len() as usize;
        let mut r = BufReader::new(r);
        let mut cfb = try!(Cfb::new(&mut r, len ));
        let wb = try!(cfb.get_stream("Workbook", &mut r));

        let mut xls = Xls {
            codepage: 1200,
            sheets: HashMap::new(),
            strings: Vec::new(),
            cfb: Some(CfbWrap::Wb(cfb, r)),
        };
        try!(xls.parse_workbook(&wb));
        Ok(xls)
    }

    fn has_vba(&mut self) -> bool {
        match self.cfb {
            Some(CfbWrap::Wb(ref cfb, _)) => cfb.has_directory("_VBA_PROJECT_CUR"),
            Some(CfbWrap::Vba(_)) => true,
            None => unreachable!(), // option is used to transfer ownership only
        }
    }

    fn vba_project(&mut self) -> Result<Cow<VbaProject>> {
        if let Some(CfbWrap::Wb(..)) = self.cfb {
            match self.cfb.take() {
                Some(CfbWrap::Wb(cfb, mut r)) => {
                    let vba = try!(VbaProject::from_cfb(&mut r, cfb));
                    self.cfb = Some(CfbWrap::Vba(vba));
                },
                _ => unreachable!(),
            }
        }

        match self.cfb {
            Some(CfbWrap::Vba(ref v)) => Ok(Cow::Borrowed(v)),
            _ => unreachable!(),
        }
    }

    /// Parses Workbook stream, no need for the relationships variable
    fn read_sheets_names(&mut self, _: &HashMap<Vec<u8>, String>)
        -> Result<HashMap<String, String>> {
        Ok(self.sheets.keys().map(|k| (k.to_string(), k.to_string())).collect())
    }

    fn read_shared_strings(&mut self) -> Result<Vec<String>> {
        Ok(self.strings.clone())
    }

    fn read_relationships(&mut self) -> Result<HashMap<Vec<u8>, String>> {
        Ok(HashMap::new())
    }

    fn read_worksheet_range(&mut self, name: &str, _: &[String]) -> Result<Range> {
        match self.sheets.get(name) {
            None => Err(format!("Sheet '{}' does not exist", name).into()),
            Some(r) => Ok(r.clone()),
        }
    }
}

impl Xls {
    fn parse_workbook(&mut self, stream: &[u8]) -> Result<()> {

        let mut sheets = Vec::new();
        {
            let mut wb = stream;
            let records = RecordIter { stream: &mut wb };
            for record in records {
                let r = try!(record);
                match r.typ {
                    0x0009 => if read_u16(&r.data[2..]) != 0x0005 {
                        return Err("Expecting Workbook BOF".into());
                    }, // BOF,
                    0x0042 => self.codepage = read_u16(r.data), // CodePage (defines encoding)
                    0x013D => {
                        let sheet_len = r.data.len() / 2;
                        sheets.reserve(sheet_len);
                    }, // RRTabId
                    0x0085 => sheets.push(try!(parse_sheet_name(r.data))), // BoundSheet8
                    0x00FC => self.strings = try!(parse_sst(r.data)), // SST
                    0x000A => break, // EOF,
                    _ => (),
                }
            }
        }

        'sh: for (pos, name) in sheets.into_iter() {
            let mut sh = &stream[pos..];
            let records = RecordIter { stream: &mut sh };
            let mut range = Range::default();
            for record in records {
                let r = try!(record);
                match r.typ {
                    0x0009 => if read_u16(&r.data[2..]) != 0x0010 { continue 'sh; }, // BOF, worksheet
                    0x0200 => range = try!(parse_dimensions(r.data)), // Dimensions
                    0x0203 => try!(parse_number(r.data, &mut range)), // Number
                    0x0205 => try!(parse_bool_err(r.data, &mut range)), // BoolErr
                    0x027E => try!(parse_rk(r.data, &mut range)), // RK
                    0x00FD => try!(parse_label_sst(r.data, &self.strings, &mut range)), // LabelSst
                    0x000A => break, // EOF,
                    _ => (),
                }
            }
            self.sheets.insert(name, range);
        }
        Ok(())
    }
}

fn parse_sheet_name(r: &[u8]) -> Result<(usize, String)> {
    let pos = read_u32(r) as usize;
    let sheet = try!(parse_short_string(&r[6..]));
    Ok((pos, sheet))
}

fn parse_sst(r: &[u8]) -> Result<Vec<String>> {
    if r.len() < 8 {
        return Err("Invalid sst length".into());
    }
    let len = read_slice::<i32>(&r[4..]) as usize;
    let mut sst = Vec::with_capacity(len);
    let mut read = &mut &r[8..];
    for _ in 0..len {
        sst.push(try!(read_rich_extended_string(read)));
    }
    Ok(sst)
}

fn parse_number(r: &[u8], range: &mut Range) -> Result<()> {
    if r.len() < 14 {
        return Err("Invalid number length".into());
    }
    let row = read_u16(r);
    let col = read_u16(&r[2..]);
    let v = read_slice::<f64>(&r[6..]);
    range.set_value((row as u32, col as u32), DataType::Float(v))
}

fn parse_bool_err(r: &[u8], range: &mut Range) -> Result<()> {
    if r.len() < 8 {
        return Err("Invalid BoolErr length".into());
    }
    let row = read_u16(r);
    let col = read_u16(&r[2..]);
    let v = match r[7] {
        0x00 => DataType::Bool(r[6] != 0),
        0x01 => match r[6] {
            0x00 => DataType::Error(CellErrorType::Null),
            0x07 => DataType::Error(CellErrorType::Div0),
            0x0F => DataType::Error(CellErrorType::Value),
            0x17 => DataType::Error(CellErrorType::Ref),
            0x1D => DataType::Error(CellErrorType::Name),
            0x24 => DataType::Error(CellErrorType::Num),
            0x2A => DataType::Error(CellErrorType::NA),
            0x2B => DataType::Error(CellErrorType::GettingData),
            e => return Err(format!("Unrecognized error {:x}", e).into()),
        },
        e => return Err(format!("Unrecognized fError {:x}", e).into()),
    };
    range.set_value((row as u32, col as u32), v)
}

fn parse_rk(r: &[u8], range: &mut Range) -> Result<()> {
    if r.len() < 10 {
        return Err("Invalid rk length".into());
    }
    let row = read_u16(r);
    let col = read_u16(&r[2..]);

    let d100 = (r[6] & 1) != 0;
    let is_int = (r[6] & 2) != 0;

    let mut v = [0u8; 8];
    v[4..].copy_from_slice(&r[6..10]);
    v[0] &= 0xFC;
    let v = if is_int {
        let v = (read_slice::<i32>(&v[4..]) >> 2) as i64;
        DataType::Int( if d100 { v/100 } else { v })
    } else {
        let v = read_slice(&v);
        DataType::Float( if d100 { v/100.0 } else { v })
    };

    range.set_value((row as u32, col as u32), v)
}

fn parse_short_string(r: &[u8]) -> Result<String> {
    if r.len() < 2 {
        return Err("Invalid short string length".into());
    }
    let mut len = r[0] as usize;
    let zero_high_byte = r[1] == 0;
    let bytes = if zero_high_byte {
        // add 0x00 high bytes to unicodes
        let mut bytes = vec![0; len * 2];
        for (i, sce) in r[2..2 + len].iter().enumerate() {
            bytes[2 * i] = *sce;
        }
        Cow::Owned(bytes)
    } else {
        len *= 2;
        Cow::Borrowed(&r[2..2 + len])
    };
    UTF_16LE.decode(&bytes, DecoderTrap::Ignore).map_err(|e| e.to_string().into())
}

fn parse_label_sst(r: &[u8], strings: &[String], range: &mut Range) -> Result<()> {
    if r.len() < 10 {
        return Err("Invalid short string length".into());
    }
    let row = read_u16(r);
    let col = read_u16(&r[2..]);
    let i = read_u32(&r[6..]) as usize;
    range.set_value((row as u32, col as u32), DataType::String(strings[i].clone()))
}

fn parse_dimensions(r: &[u8]) -> Result<Range> {
    if r.len() != 14 {
        return Err("Invalid dimensions lengths".into());
    }
    let rw_first = read_u32(&r[0..4]);
    let rw_last = read_u32(&r[4..8]) - 1;
    let col_first = read_u16(&r[8..10]);
    let col_last = read_u16(&r[10..12]) - 1;

    let start = (rw_first, col_first as u32);
    let size = ((rw_last - rw_first + 1) as usize, (col_last - col_first + 1) as usize);

    Ok(Range::new(start, size))
}

fn read_rich_extended_string(r: &mut &[u8]) -> Result<String> {
    if r.len() < 3 {
        return Err("Invalid rich extended string length".into());
    }

    let mut len = read_u16(r) as usize;
    let mut start = 3;
    let flags = r[2];
    let high_byte = flags & 0x1;
    let ext_st = flags & 0x4;
    let rich_st = flags & 0x8;
    let str_len = len;

    if rich_st != 0 {
        len += 4 * read_u16(&r[start..]) as usize;
        start += 2;
    }
    if ext_st != 0 {
        len += read_slice::<i32>(&r[start..]) as usize;
        start += 4;
    }

    let bytes = if high_byte == 0 {
        // add 0x00 high bytes to unicodes
        let mut bytes = vec![0; str_len * 2];
        for (i, sce) in r[start..start + str_len].iter().enumerate() {
            bytes[2 * i] = *sce;
        }
        Cow::Owned(bytes)
    } else {
        len += str_len;
        Cow::Borrowed(&r[start..start + 2 * str_len])
    };

    if r.len() < start + len {
        return Err(format!("Invalid rich extended string \
                            length: {} < {}", r.len(), start + len).into());
    }

    *r = &r[start + len..];
    UTF_16LE.decode(&bytes, DecoderTrap::Ignore).map_err(|e| e.to_string().into())
}

struct Record<'a> {
    typ: u16,
    data: &'a [u8],
}

struct RecordIter<'a> {
    stream: &'a[u8],
}

impl<'a> Iterator for RecordIter<'a> {
    type Item=Result<Record<'a>>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.stream.len() < 4 {
            return if self.stream.is_empty() {
                None
            } else {
                Some(Err("Expecting record type and length, found end of stream".into()))
            }
        }
        let t = read_u16(self.stream);
        let len = read_u16(&self.stream[2..]) as usize;
        if self.stream.len() < len + 4 {
            return Some(Err("Expecting record length, found end of stream".into()));
        }
        let (data, next) = self.stream.split_at(len + 4);
        self.stream = next;
        Some(Ok(Record { typ: t, data: &data[4..] }))
    }
}
<|endoftext|>


<commit_before>/// Asserts that the trait is a child of all of the other traits.
///
/// Related:
/// - [`assert_trait_super_all!`]
///
/// # Examples
///
/// All types that implement [`Copy`] must implement [`Clone`]:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_trait_sub_all!(Copy: Clone);
/// ```
///
/// All types that implement [`Ord`] must implement [`PartialEq`], [`Eq`], and
/// [`PartialOrd`]:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_trait_sub_all!(Ord: PartialEq, Eq, PartialOrd);
/// ```
///
/// The following example fails to compile because [`Eq`] is not required for
/// [`PartialOrd`]:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_trait_sub_all!(PartialOrd: Eq);
/// ```
///
/// [`assert_trait_super_all!`]: macro.assert_trait_super_all.html
///
/// [`Copy`]:       https://doc.rust-lang.org/std/marker/trait.Copy.html
/// [`Clone`]:      https://doc.rust-lang.org/std/clone/trait.Clone.html
/// [`Ord`]:        https://doc.rust-lang.org/std/cmp/trait.Ord.html
/// [`PartialOrd`]: https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html
/// [`Eq`]:         https://doc.rust-lang.org/std/cmp/trait.Eq.html
/// [`PartialEq`]:  https://doc.rust-lang.org/std/cmp/trait.PartialEq.html
#[macro_export]
macro_rules! assert_trait_sub_all {
    ($sub:path: $($super:path),+ $(,)?) => {
        const _: () = {
            // One scope per super-trait.
            $({
                #[allow(non_camel_case_types)]
                trait __Impl_Implication: $super {}

                // Can only be implemented for `$sub` types if `$super` is
                // also implemented.
                impl<T: $sub> __Impl_Implication for T {}
            })+
        };
    };
}

/// Asserts that the trait is a parent of all of the other traits.
///
/// Related:
/// - [`assert_trait_sub_all!`]
///
/// # Examples
///
/// With this, traits `A` and `B` can both be tested to require [`Copy`] on a
/// single line:
///
/// ```
/// # use static_assertions::assert_trait_super_all;
/// trait A: Copy {}
/// trait B: Copy {}
///
/// assert_trait_super_all!(Copy: A, B);
/// ```
///
/// Otherwise, each sub-trait would require its own call to
/// [`assert_trait_sub_all!`]:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// # trait A: Copy {}
/// # trait B: Copy {}
/// assert_trait_sub_all!(A: Copy);
/// assert_trait_sub_all!(B: Copy);
/// ```
///
/// The following example fails to compile because trait `C` does not require
/// [`Copy`]:
///
/// ```compile_fail
/// # use static_assertions::assert_trait_super_all;
/// # trait A: Copy {}
/// # trait B: Copy {}
/// trait C {}
///
/// assert_trait_super_all!(Copy: A, B, C);
/// ```
///
/// [`assert_trait_sub_all!`]: macro.assert_trait_sub_all.html
///
/// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
#[macro_export(local_inner_macros)]
macro_rules! assert_trait_super_all {
    ($super:path: $($sub:path),+ $(,)?) => {
        $(assert_trait_sub_all!($sub: $super);)+
    };
}
<commit_msg>Implement `assert_trait_sub_any`<commit_after>/// Asserts that the trait is a child of all of the other traits.
///
/// Related:
/// - [`assert_trait_super_all!`]
///
/// # Examples
///
/// All types that implement [`Copy`] must implement [`Clone`]:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_trait_sub_all!(Copy: Clone);
/// ```
///
/// All types that implement [`Ord`] must implement [`PartialEq`], [`Eq`], and
/// [`PartialOrd`]:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_trait_sub_all!(Ord: PartialEq, Eq, PartialOrd);
/// ```
///
/// The following example fails to compile because [`Eq`] is not required for
/// [`PartialOrd`]:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_trait_sub_all!(PartialOrd: Eq);
/// ```
///
/// [`assert_trait_super_all!`]: macro.assert_trait_super_all.html
///
/// [`Copy`]:       https://doc.rust-lang.org/std/marker/trait.Copy.html
/// [`Clone`]:      https://doc.rust-lang.org/std/clone/trait.Clone.html
/// [`Ord`]:        https://doc.rust-lang.org/std/cmp/trait.Ord.html
/// [`PartialOrd`]: https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html
/// [`Eq`]:         https://doc.rust-lang.org/std/cmp/trait.Eq.html
/// [`PartialEq`]:  https://doc.rust-lang.org/std/cmp/trait.PartialEq.html
#[macro_export]
macro_rules! assert_trait_sub_all {
    ($sub:path: $($super:path),+ $(,)?) => {
        const _: () = {
            // One scope per super-trait.
            $({
                #[allow(non_camel_case_types)]
                trait __Impl_Implication: $super {}

                // Can only be implemented for `$sub` types if `$super` is
                // also implemented.
                impl<T: $sub> __Impl_Implication for T {}
            })+
        };
    };
}

/// Asserts that the trait is a parent of all of the other traits.
///
/// Related:
/// - [`assert_trait_sub_all!`]
///
/// # Examples
///
/// With this, traits `A` and `B` can both be tested to require [`Copy`] on a
/// single line:
///
/// ```
/// # use static_assertions::assert_trait_super_all;
/// trait A: Copy {}
/// trait B: Copy {}
///
/// assert_trait_super_all!(Copy: A, B);
/// ```
///
/// Otherwise, each sub-trait would require its own call to
/// [`assert_trait_sub_all!`]:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// # trait A: Copy {}
/// # trait B: Copy {}
/// assert_trait_sub_all!(A: Copy);
/// assert_trait_sub_all!(B: Copy);
/// ```
///
/// The following example fails to compile because trait `C` does not require
/// [`Copy`]:
///
/// ```compile_fail
/// # use static_assertions::assert_trait_super_all;
/// # trait A: Copy {}
/// # trait B: Copy {}
/// trait C {}
///
/// assert_trait_super_all!(Copy: A, B, C);
/// ```
///
/// [`assert_trait_sub_all!`]: macro.assert_trait_sub_all.html
///
/// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
#[macro_export(local_inner_macros)]
macro_rules! assert_trait_super_all {
    ($super:path: $($sub:path),+ $(,)?) => {
        $(assert_trait_sub_all!($sub: $super);)+
    };
}

/// Asserts that the trait is a child of one or more of the other traits.
///
/// Related:
/// - [`assert_impl_any!`]
///
/// # Examples
///
/// All types that implement [`Copy`] must implement [`Clone`]:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_trait_sub_any!(Copy: Clone);
/// ```
///
/// All types that implement [`Ord`] must implement [`Eq`], but don't have to implement [`Clone`]:
///
/// ```
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_trait_sub_any!(Ord: Eq, Clone);
/// ```
///
/// The following example fails to compile because neither [`Eq`] nor [`Clone`] are required for
/// [`PartialOrd`]:
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions; fn main() {}
/// assert_trait_sub_any!(PartialOrd: Eq, Clone);
/// ```
///
/// [`assert_impl_any!`]: macro.assert_impl_any.html
///
/// [`Copy`]:       https://doc.rust-lang.org/std/marker/trait.Copy.html
/// [`Clone`]:      https://doc.rust-lang.org/std/clone/trait.Clone.html
/// [`Ord`]:        https://doc.rust-lang.org/std/cmp/trait.Ord.html
/// [`PartialOrd`]: https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html
/// [`Eq`]:         https://doc.rust-lang.org/std/cmp/trait.Eq.html
/// [`PartialEq`]:  https://doc.rust-lang.org/std/cmp/trait.PartialEq.html
#[macro_export]
macro_rules! assert_trait_sub_any {
    ($sub:path: $($super:path),+ $(,)?) => {
        const _: fn() = || {
            use $crate::_core::marker::PhantomData;
            use $crate::_core::ops::Deref;

            fn forall<T: $sub>() {
                // Fallback to use as the first iterative assignment to `previous`.
                let previous = AssertImplAnyFallback;
                struct AssertImplAnyFallback;

                // Ensures that blanket traits can't impersonate the method. This
                // prevents a false positive attack where---if a blanket trait is in
                // scope that has `_static_assertions_impl_any`---the macro will
                // compile when it shouldn't.
                //
                // See https://github.com/nvzqz/static-assertions-rs/issues/19 for
                // more info.
                struct ActualAssertImplAnyToken;
                trait AssertImplAnyToken {}
                impl AssertImplAnyToken for ActualAssertImplAnyToken {}
                fn assert_impl_any_token<T: AssertImplAnyToken>(_: T) {}

                $(let previous = {
                    struct Wrapper<T, N>(PhantomData<T>, N);

                    // If the method for this wrapper can't be called then the
                    // compiler will insert a deref and try again. This forwards the
                    // compiler's next attempt to the previous wrapper.
                    impl<T, N> Deref for Wrapper<T, N> {
                        type Target = N;

                        fn deref(&self) -> &Self::Target {
                            &self.1
                        }
                    }

                    // This impl is bounded on the `$t` trait, so the method can
                    // only be called if `$x` implements `$t`. This is why a new
                    // `Wrapper` is defined for each `previous`.
                    impl<T: $super, N> Wrapper<T, N> {
                        fn _static_assertions_impl_any(&self) -> ActualAssertImplAnyToken {
                            ActualAssertImplAnyToken
                        }
                    }

                    Wrapper::<T, _>(PhantomData, previous)
                };)+

                // Attempt to find the method that can actually be called. The found
                // method must return a type that implements the sealed `Token`
                // trait, this ensures that blanket trait methods can't cause this
                // macro to compile.
                assert_impl_any_token(previous._static_assertions_impl_any());
            }
        };
    };
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate libstratis;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate clap;
#[cfg(feature="dbus_enabled")]
extern crate dbus;
extern crate libc;

#[cfg(test)]
extern crate quickcheck;

use std::env;
use std::error::Error;
use std::rc::Rc;
use std::cell::RefCell;
use std::process::exit;

use clap::{App, Arg};
use log::LogLevelFilter;
use env_logger::LogBuilder;

#[cfg(feature="dbus_enabled")]
use dbus::WatchEvent;

use libstratis::engine::{Engine, SimEngine, StratEngine};
use libstratis::stratis::{StratisResult, StratisError, VERSION};

/// If writing a program error to stderr fails, panic.
fn print_err(err: StratisError) -> () {
    eprintln!("{}", err.description());
}

fn run() -> StratisResult<()> {

    let matches = App::new("stratis")
        .version(VERSION)
        .about("Stratis storage management")
        .arg(Arg::with_name("debug")
                 .long("debug")
                 .help("Print additional output for debugging"))
        .arg(Arg::with_name("sim")
                 .long("sim")
                 .help("Use simulator engine"))
        .get_matches();

    let mut builder = LogBuilder::new();
    if matches.is_present("debug") {
        builder.filter(Some("stratisd"), LogLevelFilter::Debug);
        builder.filter(Some("libstratis"), LogLevelFilter::Debug);
    } else {
        if let Ok(s) = env::var("RUST_LOG") {
            builder.parse(&s);
        }
    };

    builder
        .init()
        .expect("This is the first and only initialization of the logger; it must succeed");

    let engine: Rc<RefCell<Engine>> = {
        if matches.is_present("sim") {
            info!("Using SimEngine");
            Rc::new(RefCell::new(SimEngine::default()))
        } else {
            info!("Using StratEngine");
            Rc::new(RefCell::new(StratEngine::initialize()?))
        }
    };

    #[cfg(feature="dbus_enabled")]
    let (dbus_conn, mut tree, dbus_context) = libstratis::dbus_api::connect(Rc::clone(&engine))?;

    let mut fds = Vec::new();

    let mut eventable = engine.borrow_mut().get_eventable()?;
    let engine_fds_end_idx = match eventable {
        Some(ref mut evt) => {
            fds.push(libc::pollfd {
                         fd: evt.get_pollable_fd(),
                         revents: 0,
                         events: libc::POLLIN,
                     });
            1
        }
        None => 0,
    };

    // Don't timeout if eventable lets us be event-driven
    let poll_timeout = if engine_fds_end_idx != 0 { -1 } else { 10000 };

    loop {
        // Unconditionally call evented() if engine has no eventable.
        // This looks like a bad idea, but the only engine that has
        // no eventable is the sim engine, and for that engine, evented()
        // is essentially a no-op.
        if engine_fds_end_idx == 0 {
            engine.borrow_mut().evented()?;
        }

        // Handle engine fd, if there is one.
        // If engine has no eventable, there is no engine fd; in that case
        // the body of the loop is executed zero times.
        for pfd in fds[..engine_fds_end_idx]
                .iter_mut()
                .filter(|pfd| pfd.revents != 0) {
            pfd.revents = 0;
            eventable
                .as_mut()
                .expect("index < engine_fds_end_idx <=> index == 0 <=> eventable.is_some()")
                .clear_event()?;
            engine.borrow_mut().evented()?;
        }

        // Iterate through D-Bus file descriptors (if enabled)
        #[cfg(feature="dbus_enabled")]
        {
            for pfd in fds[engine_fds_end_idx..]
                    .iter()
                    .filter(|pfd| pfd.revents != 0) {
                for item in dbus_conn.watch_handle(pfd.fd, WatchEvent::from_revents(pfd.revents)) {
                    if let Err(r) = libstratis::dbus_api::handle(&dbus_conn,
                                                                 &item,
                                                                 &mut tree,
                                                                 &dbus_context) {
                        print_err(From::from(r));
                    }
                }
            }

            // Refresh list of dbus fds to poll for every time. This can change as
            // D-Bus clients come and go.
            fds.truncate(engine_fds_end_idx);

            fds.extend(dbus_conn.watch_fds().iter().map(|w| w.to_pollfd()));
        }

        let r = unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as libc::c_ulong, poll_timeout) };
        assert!(r >= 0);
    }
}

fn main() {
    let error_code = match run() {
        Ok(_) => 0,
        Err(err) => {
            print_err(err);
            1
        }
    };
    exit(error_code);
}
<commit_msg>Abstract configuring and initializing the logger<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate libstratis;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate clap;
#[cfg(feature="dbus_enabled")]
extern crate dbus;
extern crate libc;

#[cfg(test)]
extern crate quickcheck;

use std::env;
use std::error::Error;
use std::rc::Rc;
use std::cell::RefCell;
use std::process::exit;

use clap::{App, Arg};
use env_logger::LogBuilder;
use log::{LogLevelFilter, SetLoggerError};

#[cfg(feature="dbus_enabled")]
use dbus::WatchEvent;

use libstratis::engine::{Engine, SimEngine, StratEngine};
use libstratis::stratis::{StratisResult, StratisError, VERSION};

/// If writing a program error to stderr fails, panic.
fn print_err(err: StratisError) -> () {
    eprintln!("{}", err.description());
}

/// Configure and initialize the logger.
/// If debug is true, log at debug level. Otherwise read log configuration
/// parameters from the environment if RUST_LOG is set. Otherwise, just
/// accept the default configuration.
fn initialize_log(debug: bool) -> Result<(), SetLoggerError> {
    let mut builder = LogBuilder::new();
    if debug {
        builder.filter(Some("stratisd"), LogLevelFilter::Debug);
        builder.filter(Some("libstratis"), LogLevelFilter::Debug);
    } else {
        if let Ok(s) = env::var("RUST_LOG") {
            builder.parse(&s);
        }
    };

    builder.init()
}

fn run() -> StratisResult<()> {

    let matches = App::new("stratis")
        .version(VERSION)
        .about("Stratis storage management")
        .arg(Arg::with_name("debug")
                 .long("debug")
                 .help("Print additional output for debugging"))
        .arg(Arg::with_name("sim")
                 .long("sim")
                 .help("Use simulator engine"))
        .get_matches();

    initialize_log(matches.is_present("debug"))
        .expect("This is the first and only invocation of this method; it must succeed.");

    let engine: Rc<RefCell<Engine>> = {
        if matches.is_present("sim") {
            info!("Using SimEngine");
            Rc::new(RefCell::new(SimEngine::default()))
        } else {
            info!("Using StratEngine");
            Rc::new(RefCell::new(StratEngine::initialize()?))
        }
    };

    #[cfg(feature="dbus_enabled")]
    let (dbus_conn, mut tree, dbus_context) = libstratis::dbus_api::connect(Rc::clone(&engine))?;

    let mut fds = Vec::new();

    let mut eventable = engine.borrow_mut().get_eventable()?;
    let engine_fds_end_idx = match eventable {
        Some(ref mut evt) => {
            fds.push(libc::pollfd {
                         fd: evt.get_pollable_fd(),
                         revents: 0,
                         events: libc::POLLIN,
                     });
            1
        }
        None => 0,
    };

    // Don't timeout if eventable lets us be event-driven
    let poll_timeout = if engine_fds_end_idx != 0 { -1 } else { 10000 };

    loop {
        // Unconditionally call evented() if engine has no eventable.
        // This looks like a bad idea, but the only engine that has
        // no eventable is the sim engine, and for that engine, evented()
        // is essentially a no-op.
        if engine_fds_end_idx == 0 {
            engine.borrow_mut().evented()?;
        }

        // Handle engine fd, if there is one.
        // If engine has no eventable, there is no engine fd; in that case
        // the body of the loop is executed zero times.
        for pfd in fds[..engine_fds_end_idx]
                .iter_mut()
                .filter(|pfd| pfd.revents != 0) {
            pfd.revents = 0;
            eventable
                .as_mut()
                .expect("index < engine_fds_end_idx <=> index == 0 <=> eventable.is_some()")
                .clear_event()?;
            engine.borrow_mut().evented()?;
        }

        // Iterate through D-Bus file descriptors (if enabled)
        #[cfg(feature="dbus_enabled")]
        {
            for pfd in fds[engine_fds_end_idx..]
                    .iter()
                    .filter(|pfd| pfd.revents != 0) {
                for item in dbus_conn.watch_handle(pfd.fd, WatchEvent::from_revents(pfd.revents)) {
                    if let Err(r) = libstratis::dbus_api::handle(&dbus_conn,
                                                                 &item,
                                                                 &mut tree,
                                                                 &dbus_context) {
                        print_err(From::from(r));
                    }
                }
            }

            // Refresh list of dbus fds to poll for every time. This can change as
            // D-Bus clients come and go.
            fds.truncate(engine_fds_end_idx);

            fds.extend(dbus_conn.watch_fds().iter().map(|w| w.to_pollfd()));
        }

        let r = unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as libc::c_ulong, poll_timeout) };
        assert!(r >= 0);
    }
}

fn main() {
    let error_code = match run() {
        Ok(_) => 0,
        Err(err) => {
            print_err(err);
            1
        }
    };
    exit(error_code);
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(not(feature = "clippy"), allow(unknown_lints))]

#![allow(doc_markdown)]

extern crate devicemapper;
extern crate libstratis;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate clap;
#[cfg(feature="dbus_enabled")]
extern crate dbus;
extern crate libc;
extern crate libudev;
extern crate nix;

#[cfg(test)]
extern crate quickcheck;

use std::cell::RefCell;
use std::env;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;
use std::process::exit;
use std::rc::Rc;

use clap::{App, Arg};
use env_logger::LogBuilder;
use libc::pid_t;
use log::{LogLevelFilter, SetLoggerError};
use nix::fcntl::{flock, FlockArg};
use nix::unistd::getpid;

#[cfg(feature="dbus_enabled")]
use dbus::WatchEvent;

use devicemapper::Device;

use libstratis::engine::{Engine, SimEngine, StratEngine};
use libstratis::stratis::{StratisError, StratisResult, VERSION};

const STRATISD_PID_PATH: &str = "/var/run/stratisd.pid";

/// If writing a program error to stderr fails, panic.
fn print_err(err: StratisError) -> () {
    eprintln!("{}", err);
}

/// Configure and initialize the logger.
/// If debug is true, log at debug level. Otherwise read log configuration
/// parameters from the environment if RUST_LOG is set. Otherwise, just
/// accept the default configuration.
fn initialize_log(debug: bool) -> Result<(), SetLoggerError> {
    let mut builder = LogBuilder::new();
    if debug {
        builder.filter(Some("stratisd"), LogLevelFilter::Debug);
        builder.filter(Some("libstratis"), LogLevelFilter::Debug);
    } else if let Ok(s) = env::var("RUST_LOG") {
        builder.parse(&s);
    };

    builder.init()
}

/// Given a udev event check to see if it's an add and if it is return the device node and
/// devicemapper::Device.
fn handle_udev_add(event: &libudev::Event) -> Option<(Device, PathBuf)> {
    if event.event_type() == libudev::EventType::Add {
        let device = event.device();
        return device
                   .devnode()
                   .and_then(|devnode| {
                                 device
                                     .devnum()
                                     .and_then(|devnum| {
                                                   Some((Device::from(devnum),
                                                         PathBuf::from(devnode)))
                                               })
                             });
    }
    None
}

/// To ensure only one instance of stratisd runs at a time, acquire an
/// exclusive lock. Return an error if lock attempt fails.
fn create_pid_file() -> StratisResult<File> {
    let mut f = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(STRATISD_PID_PATH)?;
    match flock(f.as_raw_fd(), FlockArg::LockExclusiveNonblock) {
        Ok(_) => {
            f.write(format!("{}\n", getpid()).as_bytes())?;
            Ok(f)
        }
        Err(_) => {
            let mut buf = String::new();
            f.read_to_string(&mut buf)?;
            // pidfile is supposed to contain pid of holder. But you never
            // know so be paranoid.
            let pid_str = buf.split_whitespace()
                .next()
                .and_then(|s| s.parse::<pid_t>().ok())
                .map(|pid| format!("{}", pid))
                .unwrap_or_else(|| "<unknown>".into());
            Err(StratisError::Error(format!("Daemon already running with pid: {}", pid_str)))
        }
    }
}

fn run() -> StratisResult<()> {

    // Exit immediately if stratisd is already running
    let _ = create_pid_file()?;

    let matches = App::new("stratis")
        .version(VERSION)
        .about("Stratis storage management")
        .arg(Arg::with_name("debug")
                 .long("debug")
                 .help("Print additional output for debugging"))
        .arg(Arg::with_name("sim")
                 .long("sim")
                 .help("Use simulator engine"))
        .get_matches();

    initialize_log(matches.is_present("debug"))
        .expect("This is the first and only invocation of this method; it must succeed.");

    // We must setup a udev listener before we initialize the
    // engine. It is possible that a device may appear after the engine has read the
    // /dev directory but before it has completed initialization. Unless the udev
    // event has been recorded, the engine will be unaware of the existence of the
    // device.
    // This is especially important since stratisd is required to be able to run
    // during early boot.
    let context = libudev::Context::new()?;
    let mut monitor = libudev::Monitor::new(&context)?;
    monitor.match_subsystem_devtype("block", "disk")?;
    let mut udev = monitor.listen()?;

    let engine: Rc<RefCell<Engine>> = {
        if matches.is_present("sim") {
            info!("Using SimEngine");
            Rc::new(RefCell::new(SimEngine::default()))
        } else {
            info!("Using StratEngine");
            Rc::new(RefCell::new(StratEngine::initialize()?))
        }
    };

    /*
    The file descriptor array indexes are laid out in the following:

    0   == Always udev fd index
    1   == engine index if eventable
    1/2 == Start of dbus client file descriptor(s), 1 if engine is not eventable, else 2
    */
    const FD_INDEX_UDEV: usize = 0;
    const FD_INDEX_ENGINE: usize = 1;

    let mut fds = Vec::new();

    fds.push(libc::pollfd {
                 fd: udev.as_raw_fd(),
                 revents: 0,
                 events: libc::POLLIN,
             });

    let eventable = engine.borrow().get_eventable();

    // The variable _dbus_client_index_start is only used when dbus support is compiled in, thus
    // we denote the value as not needed to compile when dbus support is not included.
    let (engine_eventable, poll_timeout, _dbus_client_index_start) = match eventable {
        Some(ref evt) => {
            fds.push(libc::pollfd {
                         fd: evt.get_pollable_fd(),
                         revents: 0,
                         events: libc::POLLIN,
                     });

            // Don't timeout if eventable, we are event driven
            (true, -1, FD_INDEX_ENGINE + 1)
        }

        // We periodically need to timeout as we are not event driven
        None => (false, 10000, FD_INDEX_ENGINE),
    };

    #[cfg(feature="dbus_enabled")]
    let (mut dbus_conn, mut tree, base_object_path, mut dbus_context) =
        libstratis::dbus_api::connect(Rc::clone(&engine))?;

    loop {
        // Process any udev block events
        if fds[FD_INDEX_UDEV].revents != 0 {
            while let Some(event) = udev.receive_event() {
                if let Some((device, devnode)) = handle_udev_add(&event) {

                    // If block evaluate returns an error we are going to ignore it as
                    // there is nothing we can do for a device we are getting errors with.
                    let pool_uuid = engine
                        .borrow_mut()
                        .block_evaluate(device, devnode)
                        .unwrap_or(None);

                    // We need to pretend that we aren't using the variable _pool_uuid so
                    // that we can conditionally compile out the register_pool when dbus
                    // is not enabled.
                    if let Some(_pool_uuid) = pool_uuid {
                                #[cfg(feature="dbus_enabled")]
                        libstratis::dbus_api::register_pool(&mut dbus_conn,
                                                            &Rc::clone(&engine),
                                                            &mut dbus_context,
                                                            &mut tree,
                                                            _pool_uuid,
                                                            &base_object_path)?;
                    }
                }
            }
        }

        // Handle engine events, if the engine is eventable
        if engine_eventable {
            if fds[FD_INDEX_ENGINE].revents != 0 {
                fds[FD_INDEX_ENGINE].revents = 0;

                eventable
                    .as_ref()
                    .expect("eventable.is_some()")
                    .clear_event()?;

                engine.borrow_mut().evented()?;
            }
        } else {
            // Unconditionally call evented() if engine has no eventable.
            // This looks like a bad idea, but the only engine that has
            // no eventable is the sim engine, and for that engine, evented()
            // is essentially a no-op.
            engine.borrow_mut().evented()?;
        }

        // Iterate through D-Bus file descriptors (if enabled)
        #[cfg(feature="dbus_enabled")]
        {
            for pfd in fds[_dbus_client_index_start..]
                    .iter()
                    .filter(|pfd| pfd.revents != 0) {
                for item in dbus_conn.watch_handle(pfd.fd, WatchEvent::from_revents(pfd.revents)) {
                    if let Err(r) = libstratis::dbus_api::handle(&dbus_conn,
                                                                 &item,
                                                                 &mut tree,
                                                                 &dbus_context) {
                        print_err(From::from(r));
                    }
                }
            }

            // Refresh list of dbus fds to poll for every time. This can change as
            // D-Bus clients come and go.
            fds.truncate(_dbus_client_index_start);

            fds.extend(dbus_conn.watch_fds().iter().map(|w| w.to_pollfd()));
        }

        let r = unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as libc::c_ulong, poll_timeout) };
        assert!(r >= 0);
    }
}

fn main() {
    let error_code = match run() {
        Ok(_) => 0,
        Err(err) => {
            print_err(err);
            1
        }
    };
    exit(error_code);
}
<commit_msg>Do not pass a mutable argument where only immutable one is needed<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(not(feature = "clippy"), allow(unknown_lints))]

#![allow(doc_markdown)]

extern crate devicemapper;
extern crate libstratis;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate clap;
#[cfg(feature="dbus_enabled")]
extern crate dbus;
extern crate libc;
extern crate libudev;
extern crate nix;

#[cfg(test)]
extern crate quickcheck;

use std::cell::RefCell;
use std::env;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;
use std::process::exit;
use std::rc::Rc;

use clap::{App, Arg};
use env_logger::LogBuilder;
use libc::pid_t;
use log::{LogLevelFilter, SetLoggerError};
use nix::fcntl::{flock, FlockArg};
use nix::unistd::getpid;

#[cfg(feature="dbus_enabled")]
use dbus::WatchEvent;

use devicemapper::Device;

use libstratis::engine::{Engine, SimEngine, StratEngine};
use libstratis::stratis::{StratisError, StratisResult, VERSION};

const STRATISD_PID_PATH: &str = "/var/run/stratisd.pid";

/// If writing a program error to stderr fails, panic.
fn print_err(err: StratisError) -> () {
    eprintln!("{}", err);
}

/// Configure and initialize the logger.
/// If debug is true, log at debug level. Otherwise read log configuration
/// parameters from the environment if RUST_LOG is set. Otherwise, just
/// accept the default configuration.
fn initialize_log(debug: bool) -> Result<(), SetLoggerError> {
    let mut builder = LogBuilder::new();
    if debug {
        builder.filter(Some("stratisd"), LogLevelFilter::Debug);
        builder.filter(Some("libstratis"), LogLevelFilter::Debug);
    } else if let Ok(s) = env::var("RUST_LOG") {
        builder.parse(&s);
    };

    builder.init()
}

/// Given a udev event check to see if it's an add and if it is return the device node and
/// devicemapper::Device.
fn handle_udev_add(event: &libudev::Event) -> Option<(Device, PathBuf)> {
    if event.event_type() == libudev::EventType::Add {
        let device = event.device();
        return device
                   .devnode()
                   .and_then(|devnode| {
                                 device
                                     .devnum()
                                     .and_then(|devnum| {
                                                   Some((Device::from(devnum),
                                                         PathBuf::from(devnode)))
                                               })
                             });
    }
    None
}

/// To ensure only one instance of stratisd runs at a time, acquire an
/// exclusive lock. Return an error if lock attempt fails.
fn create_pid_file() -> StratisResult<File> {
    let mut f = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(STRATISD_PID_PATH)?;
    match flock(f.as_raw_fd(), FlockArg::LockExclusiveNonblock) {
        Ok(_) => {
            f.write(format!("{}\n", getpid()).as_bytes())?;
            Ok(f)
        }
        Err(_) => {
            let mut buf = String::new();
            f.read_to_string(&mut buf)?;
            // pidfile is supposed to contain pid of holder. But you never
            // know so be paranoid.
            let pid_str = buf.split_whitespace()
                .next()
                .and_then(|s| s.parse::<pid_t>().ok())
                .map(|pid| format!("{}", pid))
                .unwrap_or_else(|| "<unknown>".into());
            Err(StratisError::Error(format!("Daemon already running with pid: {}", pid_str)))
        }
    }
}

fn run() -> StratisResult<()> {

    // Exit immediately if stratisd is already running
    let _ = create_pid_file()?;

    let matches = App::new("stratis")
        .version(VERSION)
        .about("Stratis storage management")
        .arg(Arg::with_name("debug")
                 .long("debug")
                 .help("Print additional output for debugging"))
        .arg(Arg::with_name("sim")
                 .long("sim")
                 .help("Use simulator engine"))
        .get_matches();

    initialize_log(matches.is_present("debug"))
        .expect("This is the first and only invocation of this method; it must succeed.");

    // We must setup a udev listener before we initialize the
    // engine. It is possible that a device may appear after the engine has read the
    // /dev directory but before it has completed initialization. Unless the udev
    // event has been recorded, the engine will be unaware of the existence of the
    // device.
    // This is especially important since stratisd is required to be able to run
    // during early boot.
    let context = libudev::Context::new()?;
    let mut monitor = libudev::Monitor::new(&context)?;
    monitor.match_subsystem_devtype("block", "disk")?;
    let mut udev = monitor.listen()?;

    let engine: Rc<RefCell<Engine>> = {
        if matches.is_present("sim") {
            info!("Using SimEngine");
            Rc::new(RefCell::new(SimEngine::default()))
        } else {
            info!("Using StratEngine");
            Rc::new(RefCell::new(StratEngine::initialize()?))
        }
    };

    /*
    The file descriptor array indexes are laid out in the following:

    0   == Always udev fd index
    1   == engine index if eventable
    1/2 == Start of dbus client file descriptor(s), 1 if engine is not eventable, else 2
    */
    const FD_INDEX_UDEV: usize = 0;
    const FD_INDEX_ENGINE: usize = 1;

    let mut fds = Vec::new();

    fds.push(libc::pollfd {
                 fd: udev.as_raw_fd(),
                 revents: 0,
                 events: libc::POLLIN,
             });

    let eventable = engine.borrow().get_eventable();

    // The variable _dbus_client_index_start is only used when dbus support is compiled in, thus
    // we denote the value as not needed to compile when dbus support is not included.
    let (engine_eventable, poll_timeout, _dbus_client_index_start) = match eventable {
        Some(ref evt) => {
            fds.push(libc::pollfd {
                         fd: evt.get_pollable_fd(),
                         revents: 0,
                         events: libc::POLLIN,
                     });

            // Don't timeout if eventable, we are event driven
            (true, -1, FD_INDEX_ENGINE + 1)
        }

        // We periodically need to timeout as we are not event driven
        None => (false, 10000, FD_INDEX_ENGINE),
    };

    #[cfg(feature="dbus_enabled")]
    let (dbus_conn, mut tree, base_object_path, dbus_context) =
        libstratis::dbus_api::connect(Rc::clone(&engine))?;

    loop {
        // Process any udev block events
        if fds[FD_INDEX_UDEV].revents != 0 {
            while let Some(event) = udev.receive_event() {
                if let Some((device, devnode)) = handle_udev_add(&event) {

                    // If block evaluate returns an error we are going to ignore it as
                    // there is nothing we can do for a device we are getting errors with.
                    let pool_uuid = engine
                        .borrow_mut()
                        .block_evaluate(device, devnode)
                        .unwrap_or(None);

                    // We need to pretend that we aren't using the variable _pool_uuid so
                    // that we can conditionally compile out the register_pool when dbus
                    // is not enabled.
                    if let Some(_pool_uuid) = pool_uuid {
                                #[cfg(feature="dbus_enabled")]
                        libstratis::dbus_api::register_pool(&dbus_conn,
                                                            &Rc::clone(&engine),
                                                            &dbus_context,
                                                            &mut tree,
                                                            _pool_uuid,
                                                            &base_object_path)?;
                    }
                }
            }
        }

        // Handle engine events, if the engine is eventable
        if engine_eventable {
            if fds[FD_INDEX_ENGINE].revents != 0 {
                fds[FD_INDEX_ENGINE].revents = 0;

                eventable
                    .as_ref()
                    .expect("eventable.is_some()")
                    .clear_event()?;

                engine.borrow_mut().evented()?;
            }
        } else {
            // Unconditionally call evented() if engine has no eventable.
            // This looks like a bad idea, but the only engine that has
            // no eventable is the sim engine, and for that engine, evented()
            // is essentially a no-op.
            engine.borrow_mut().evented()?;
        }

        // Iterate through D-Bus file descriptors (if enabled)
        #[cfg(feature="dbus_enabled")]
        {
            for pfd in fds[_dbus_client_index_start..]
                    .iter()
                    .filter(|pfd| pfd.revents != 0) {
                for item in dbus_conn.watch_handle(pfd.fd, WatchEvent::from_revents(pfd.revents)) {
                    if let Err(r) = libstratis::dbus_api::handle(&dbus_conn,
                                                                 &item,
                                                                 &mut tree,
                                                                 &dbus_context) {
                        print_err(From::from(r));
                    }
                }
            }

            // Refresh list of dbus fds to poll for every time. This can change as
            // D-Bus clients come and go.
            fds.truncate(_dbus_client_index_start);

            fds.extend(dbus_conn.watch_fds().iter().map(|w| w.to_pollfd()));
        }

        let r = unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as libc::c_ulong, poll_timeout) };
        assert!(r >= 0);
    }
}

fn main() {
    let error_code = match run() {
        Ok(_) => 0,
        Err(err) => {
            print_err(err);
            1
        }
    };
    exit(error_code);
}
<|endoftext|>


<commit_before>#[macro_use] extern crate html5ever_atoms;
extern crate html5ever;
extern crate orbclient;
extern crate orbfont;
extern crate tendril;

use std::env;
use std::iter::repeat;
use std::default::Default;
use std::string::String;

use html5ever::parse_document;
use html5ever::rcdom::{Document, Doctype, Text, Comment, Element, RcDom, Handle};
use orbclient::{Color, Window, EventOption, K_ESC};
use orbfont::Font;
use tendril::TendrilSink;

// This is not proper HTML serialization, of course.

struct Block<'a> {
    x: i32,
    y: i32,
    w: i32,
    h: i32,
    color: Color,
    text: orbfont::Text<'a>
}

impl<'a> Block<'a> {
    fn draw(&self, window: &mut Window) {
        if self.x < window.width() as i32 && self.y < window.height() as i32 {
            self.text.draw(window, self.x, self.y, self.color);
        }
    }
}

fn walk<'a>(handle: Handle, indent: usize, x: &mut i32, y: &mut i32, mut size: f32, mut bold: bool, mut color: Color, mut ignore: bool, whitespace: &mut bool, font: &'a Font, font_bold: &'a Font, blocks: &mut Vec<Block<'a>>) {
    let node = handle.borrow();

    let mut new_line = false;

    print!("{}", repeat(" ").take(indent).collect::<String>());
    match node.node {
        Document
            => {
                println!("#Document")
            },

        Doctype(ref name, ref public, ref system)
            => {
                println!("<!DOCTYPE {} \"{}\" \"{}\">", *name, *public, *system);
            },

        Text(ref text)
            => {
                let mut block_text = String::new();

                for c in text.chars() {
                    match c {
                        ' ' | '\n' | '\r' => if *whitespace {
                            // Ignore
                        } else {
                            // Set whitespace
                            *whitespace = true;
                            block_text.push(' ');
                        },
                        _ => {
                            if *whitespace {
                                *whitespace = false;
                            }
                            block_text.push(c);
                        }
                    }
                }

                if ! block_text.is_empty() {
                    if ignore {
                        println!("#text: ignored");
                    } else {
                        let trimmed_left = block_text.trim_left();
                        let left_margin = block_text.len() as i32 - trimmed_left.len() as i32;
                        let trimmed_right = trimmed_left.trim_right();
                        let right_margin = trimmed_left.len() as i32 - trimmed_right.len() as i32;

                        let escaped_text = escape_default(&trimmed_right);
                        println!("#text: block {} at {}, {}: '{}'", blocks.len(), *x, *y, escaped_text);

                        *x += left_margin * 8;

                        for (word_i, word) in trimmed_right.split(' ').enumerate() {
                            if word_i > 0 {
                                *x += 8;
                            }

                            let text = if bold {
                                font_bold.render(word, size)
                            } else {
                                font.render(word, size)
                            };

                            let w = text.width() as i32;
                            let h = text.height() as i32;

                            if *x + w >= 640 && *x > 0 {
                                *x = 0;
                                *y += size.ceil() as i32;
                            }

                            blocks.push(Block {
                                x: *x,
                                y: *y,
                                w: w,
                                h: h,
                                color: color,
                                text: text
                            });

                            *x += w;
                        }

                        *x += right_margin * 8;
                    }
                } else {
                    println!("#text: empty");
                }
            },

        Comment(ref text)
            => {
                println!("<!-- {} -->", escape_default(text))
            },

        Element(ref name, _, ref _attrs) => {
            assert!(name.ns == ns!(html));
            print!("<{}", name.local);
            /*
            for attr in attrs.iter() {
                assert!(attr.name.ns == ns!());
                print!(" {}=\"{}\"", attr.name.local, attr.value);
            }
            */
            println!(">");

            match &*name.local {
                "a" => {
                    color = Color::rgb(0, 0, 255);
                },
                "b" => {
                    bold = true;
                },
                "br" => {
                    ignore = true;
                    new_line = true;
                },
                "div" => {
                    new_line = true;
                },
                "h1" => {
                    size = 32.0;
                    bold = true;
                    new_line = true;
                },
                "h2" => {
                    size = 24.0;
                    bold = true;
                    new_line = true;
                },
                "h3" => {
                    size = 18.0;
                    bold = true;
                    new_line = true;
                }
                "h4" => {
                    size = 16.0;
                    bold = true;
                    new_line = true;
                }
                "h5" => {
                    size = 14.0;
                    bold = true;
                    new_line = true;
                }
                "h6" => {
                    size = 10.0;
                    bold = true;
                    new_line = true;
                },
                "li" => {
                    new_line = true;
                },
                "p" => {
                    new_line = true;
                },

                "head" => ignore = true,
                "title" => ignore = true, //TODO: Grab title
                "link" => ignore = true,
                "meta" => ignore = true,
                "script" => ignore = true,
                _ => ()
            }
        }
    }

    for child in node.children.iter() {
        walk(child.clone(), indent + 4, x, y, size, bold, color, ignore, whitespace, font, font_bold, blocks);
    }

    if new_line {
        *whitespace = true;
        *x = 0;
        *y += size.ceil() as i32;
    }
}

// FIXME: Copy of str::escape_default from std, which is currently unstable
pub fn escape_default(s: &str) -> String {
    s.chars().flat_map(|c| c.escape_default()).collect()
}

fn event_loop(window: &mut Window){
    loop {
        for event in window.events() {
            if let EventOption::Key(key_event) = event.to_option() {
                if key_event.pressed && key_event.scancode == K_ESC {
                    return;
                }
            }
            if let EventOption::Quit(_) = event.to_option() {
                return;
            }
        }
    }
}

fn error_msg(window: &mut Window, msg: &str) {
    let mut x = 0;
    for c in msg.chars() {
        window.char(x, 0, c, Color::rgb(255, 255, 255));
        x += 8;
    }
}

fn main() {
    let title = match env::args().nth(1) {
        Some(arg) => arg.clone(),
        None => "".to_string(),
    };

    match Font::find(None, None, None) {
        Ok(font) => match Font::find(None, None, Some("Bold")) {
            Ok(font_bold) => {
                let dom = parse_document(RcDom::default(), Default::default())
                    .from_utf8()
                    .from_file(env::args().nth(1).expect("browser: no file provided"))
                    .unwrap();

                let mut blocks = vec![];
                let mut x = 0;
                let mut y = 0;
                let mut whitespace = false;
                walk(dom.document, 0, &mut x, &mut y, 16.0, false, Color::rgb(0, 0, 0), false, &mut whitespace, &font, &font_bold, &mut blocks);

                if !dom.errors.is_empty() {
                    /*
                    println!("\nParse errors:");
                    for err in dom.errors.into_iter() {
                        println!("    {}", err);
                    }
                    */
                }

                let mut window = Window::new(-1,
                                             -1,
                                             640,
                                             480,
                                             &("Browser (".to_string() + &title + ")"))
                                     .unwrap();
                window.set(Color::rgb(255, 255, 255));
                let block_len = blocks.len();
                for (block_i, block) in blocks.iter().enumerate() {
                    println!("Draw block {}/{}", block_i, block_len);
                    block.draw(&mut window);
                }
                window.sync();
                event_loop(&mut window);
            },
            Err(err) => {
                let mut window = Window::new(-1,
                                             -1,
                                             320,
                                             32,
                                             &("Browser (".to_string() + &title + ")"))
                                     .unwrap();
                window.set(Color::rgb(0, 0, 0));
                error_msg(&mut window, &format!("{}", err));
                window.sync();
                event_loop(&mut window);
            }
        },
        Err(err) => {
            let mut window = Window::new(-1,
                                         -1,
                                         320,
                                         32,
                                         &("Browser (".to_string() + &title + ")"))
                                 .unwrap();
            window.set(Color::rgb(0, 0, 0));
            error_msg(&mut window, &format!("{}", err));
            window.sync();
            event_loop(&mut window);
        }
    }
}
<commit_msg>Add scrolling<commit_after>#[macro_use] extern crate html5ever_atoms;
extern crate html5ever;
extern crate orbclient;
extern crate orbfont;
extern crate tendril;

use std::{cmp, env};
use std::iter::repeat;
use std::default::Default;
use std::string::String;

use html5ever::parse_document;
use html5ever::rcdom::{Document, Doctype, Text, Comment, Element, RcDom, Handle};
use orbclient::{Color, Window, EventOption, K_ESC, K_DOWN, K_UP};
use orbfont::Font;
use tendril::TendrilSink;

// This is not proper HTML serialization, of course.

struct Block<'a> {
    x: i32,
    y: i32,
    w: i32,
    h: i32,
    color: Color,
    text: orbfont::Text<'a>
}

impl<'a> Block<'a> {
    fn draw(&self, window: &mut Window, offset: i32) {
        let x = self.x;
        let y = self.y - offset;
        if x + self.w > 0 && x < window.width() as i32 && y + self.h > 0 && y < window.height() as i32 {
            self.text.draw(window, x, y, self.color);
        }
    }
}

fn walk<'a>(handle: Handle, indent: usize, x: &mut i32, y: &mut i32, mut size: f32, mut bold: bool, mut color: Color, mut ignore: bool, whitespace: &mut bool, font: &'a Font, font_bold: &'a Font, blocks: &mut Vec<Block<'a>>) {
    let node = handle.borrow();

    let mut new_line = false;

    print!("{}", repeat(" ").take(indent).collect::<String>());
    match node.node {
        Document
            => {
                println!("#Document")
            },

        Doctype(ref name, ref public, ref system)
            => {
                println!("<!DOCTYPE {} \"{}\" \"{}\">", *name, *public, *system);
            },

        Text(ref text)
            => {
                let mut block_text = String::new();

                for c in text.chars() {
                    match c {
                        ' ' | '\n' | '\r' => if *whitespace {
                            // Ignore
                        } else {
                            // Set whitespace
                            *whitespace = true;
                            block_text.push(' ');
                        },
                        _ => {
                            if *whitespace {
                                *whitespace = false;
                            }
                            block_text.push(c);
                        }
                    }
                }

                if ! block_text.is_empty() {
                    if ignore {
                        println!("#text: ignored");
                    } else {
                        let trimmed_left = block_text.trim_left();
                        let left_margin = block_text.len() as i32 - trimmed_left.len() as i32;
                        let trimmed_right = trimmed_left.trim_right();
                        let right_margin = trimmed_left.len() as i32 - trimmed_right.len() as i32;

                        let escaped_text = escape_default(&trimmed_right);
                        println!("#text: block {} at {}, {}: '{}'", blocks.len(), *x, *y, escaped_text);

                        *x += left_margin * 8;

                        for (word_i, word) in trimmed_right.split(' ').enumerate() {
                            if word_i > 0 {
                                *x += 8;
                            }

                            let text = if bold {
                                font_bold.render(word, size)
                            } else {
                                font.render(word, size)
                            };

                            let w = text.width() as i32;
                            let h = text.height() as i32;

                            if *x + w >= 640 && *x > 0 {
                                *x = 0;
                                *y += size.ceil() as i32;
                            }

                            blocks.push(Block {
                                x: *x,
                                y: *y,
                                w: w,
                                h: h,
                                color: color,
                                text: text
                            });

                            *x += w;
                        }

                        *x += right_margin * 8;
                    }
                } else {
                    println!("#text: empty");
                }
            },

        Comment(ref text)
            => {
                println!("<!-- {} -->", escape_default(text))
            },

        Element(ref name, _, ref _attrs) => {
            assert!(name.ns == ns!(html));
            print!("<{}", name.local);
            /*
            for attr in attrs.iter() {
                assert!(attr.name.ns == ns!());
                print!(" {}=\"{}\"", attr.name.local, attr.value);
            }
            */
            println!(">");

            match &*name.local {
                "a" => {
                    color = Color::rgb(0, 0, 255);
                },
                "b" => {
                    bold = true;
                },
                "br" => {
                    ignore = true;
                    new_line = true;
                },
                "div" => {
                    new_line = true;
                },
                "h1" => {
                    size = 32.0;
                    bold = true;
                    new_line = true;
                },
                "h2" => {
                    size = 24.0;
                    bold = true;
                    new_line = true;
                },
                "h3" => {
                    size = 18.0;
                    bold = true;
                    new_line = true;
                }
                "h4" => {
                    size = 16.0;
                    bold = true;
                    new_line = true;
                }
                "h5" => {
                    size = 14.0;
                    bold = true;
                    new_line = true;
                }
                "h6" => {
                    size = 10.0;
                    bold = true;
                    new_line = true;
                },
                "hr" => {
                    new_line = true;
                },
                "li" => {
                    new_line = true;
                },
                "p" => {
                    new_line = true;
                },

                "head" => ignore = true,
                "title" => ignore = true, //TODO: Grab title
                "link" => ignore = true,
                "meta" => ignore = true,
                "script" => ignore = true,
                "style" => ignore = true,
                _ => ()
            }
        }
    }

    for child in node.children.iter() {
        walk(child.clone(), indent + 4, x, y, size, bold, color, ignore, whitespace, font, font_bold, blocks);
    }

    if new_line {
        *whitespace = true;
        *x = 0;
        *y += size.ceil() as i32;
    }
}

// FIXME: Copy of str::escape_default from std, which is currently unstable
pub fn escape_default(s: &str) -> String {
    s.chars().flat_map(|c| c.escape_default()).collect()
}

fn event_loop(window: &mut Window){
    loop {
        for event in window.events() {
            if let EventOption::Key(key_event) = event.to_option() {
                if key_event.pressed && key_event.scancode == K_ESC {
                    return;
                }
            }
            if let EventOption::Quit(_) = event.to_option() {
                return;
            }
        }
    }
}

fn error_msg(window: &mut Window, msg: &str) {
    let mut x = 0;
    for c in msg.chars() {
        window.char(x, 0, c, Color::rgb(255, 255, 255));
        x += 8;
    }
}

fn main() {
    let title = match env::args().nth(1) {
        Some(arg) => arg.clone(),
        None => "".to_string(),
    };

    match Font::find(None, None, None) {
        Ok(font) => match Font::find(None, None, Some("Bold")) {
            Ok(font_bold) => {
                let dom = parse_document(RcDom::default(), Default::default())
                    .from_utf8()
                    .from_file(env::args().nth(1).expect("browser: no file provided"))
                    .unwrap();

                let mut blocks = vec![];
                let mut x = 0;
                let mut y = 0;
                let mut whitespace = false;
                walk(dom.document, 0, &mut x, &mut y, 16.0, false, Color::rgb(0, 0, 0), false, &mut whitespace, &font, &font_bold, &mut blocks);

                if !dom.errors.is_empty() {
                    /*
                    println!("\nParse errors:");
                    for err in dom.errors.into_iter() {
                        println!("    {}", err);
                    }
                    */
                }

                let mut window = Window::new(-1,
                                             -1,
                                             640,
                                             480,
                                             &("Browser (".to_string() + &title + ")"))
                                     .unwrap();

                let mut offset = 0;
                let mut max_offset = 0;
                for block in blocks.iter() {
                    if block.y + block.h > max_offset {
                        max_offset = block.y + block.h;
                    }
                }

                let mut redraw = true;
                loop {
                    if redraw {
                        redraw = false;

                        window.set(Color::rgb(255, 255, 255));
                        for block in blocks.iter() {
                            block.draw(&mut window, offset);
                        }
                        window.sync();
                    }

                    for event in window.events() {
                        if let EventOption::Key(key_event) = event.to_option() {
                            if key_event.pressed {
                                match key_event.scancode {
                                    K_ESC => return,
                                    K_UP => {
                                        redraw = true;
                                        offset = cmp::max(0, offset - 128);
                                    },
                                    K_DOWN => {
                                        redraw = true;
                                        offset = cmp::min(max_offset, offset + 128);
                                    },
                                    _ => ()
                                }
                            }
                        }
                        if let EventOption::Quit(_) = event.to_option() {
                            return;
                        }
                    }
                }
            },
            Err(err) => {
                let mut window = Window::new(-1,
                                             -1,
                                             320,
                                             32,
                                             &("Browser (".to_string() + &title + ")"))
                                     .unwrap();
                window.set(Color::rgb(0, 0, 0));
                error_msg(&mut window, &format!("{}", err));
                window.sync();
                event_loop(&mut window);
            }
        },
        Err(err) => {
            let mut window = Window::new(-1,
                                         -1,
                                         320,
                                         32,
                                         &("Browser (".to_string() + &title + ")"))
                                 .unwrap();
            window.set(Color::rgb(0, 0, 0));
            error_msg(&mut window, &format!("{}", err));
            window.sync();
            event_loop(&mut window);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 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.

//! # Translation of inline assembly.

use llvm::{self, ValueRef};
use common::*;
use type_::Type;
use type_of::LayoutLlvmExt;
use builder::Builder;

use rustc::hir;

use mir::place::PlaceRef;
use mir::operand::OperandValue;

use std::ffi::CString;
use syntax::ast::AsmDialect;
use libc::{c_uint, c_char};

// Take an inline assembly expression and splat it out via LLVM
pub fn trans_inline_asm<'a, 'tcx>(
    bx: &Builder<'a, 'tcx>,
    ia: &hir::InlineAsm,
    outputs: Vec<PlaceRef<'tcx>>,
    mut inputs: Vec<ValueRef>
) {
    let mut ext_constraints = vec![];
    let mut output_types = vec![];

    // Prepare the output operands
    let mut indirect_outputs = vec![];
    for (i, (out, place)) in ia.outputs.iter().zip(&outputs).enumerate() {
        if out.is_rw {
            inputs.push(place.load(bx).immediate());
            ext_constraints.push(i.to_string());
        }
        if out.is_indirect {
            indirect_outputs.push(place.load(bx).immediate());
        } else {
            output_types.push(place.layout.llvm_type(bx.cx));
        }
    }
    if !indirect_outputs.is_empty() {
        indirect_outputs.extend_from_slice(&inputs);
        inputs = indirect_outputs;
    }

    let clobbers = ia.clobbers.iter()
                              .map(|s| format!("~{{{}}}", &s));

    // Default per-arch clobbers
    // Basically what clang does
    let arch_clobbers = match &bx.sess().target.target.arch[..] {
        "x86" | "x86_64" => vec!["~{dirflag}", "~{fpsr}", "~{flags}"],
        _                => Vec::new()
    };

    let all_constraints =
        ia.outputs.iter().map(|out| out.constraint.to_string())
          .chain(ia.inputs.iter().map(|s| s.to_string()))
          .chain(ext_constraints)
          .chain(clobbers)
          .chain(arch_clobbers.iter().map(|s| s.to_string()))
          .collect::<Vec<String>>().join(",");

    debug!("Asm Constraints: {}", &all_constraints);

    // Depending on how many outputs we have, the return type is different
    let num_outputs = output_types.len();
    let output_type = match num_outputs {
        0 => Type::void(bx.cx),
        1 => output_types[0],
        _ => Type::struct_(bx.cx, &output_types, false)
    };

    let dialect = match ia.dialect {
        AsmDialect::Att   => llvm::AsmDialect::Att,
        AsmDialect::Intel => llvm::AsmDialect::Intel,
    };

    let asm = CString::new(ia.asm.as_str().as_bytes()).unwrap();
    let constraint_cstr = CString::new(all_constraints).unwrap();
    let r = bx.inline_asm_call(
        asm.as_ptr(),
        constraint_cstr.as_ptr(),
        &inputs,
        output_type,
        ia.volatile,
        ia.alignstack,
        dialect
    );

    // Again, based on how many outputs we have
    let outputs = ia.outputs.iter().zip(&outputs).filter(|&(ref o, _)| !o.is_indirect);
    for (i, (_, &place)) in outputs.enumerate() {
        let v = if num_outputs == 1 { r } else { bx.extract_value(r, i as u64) };
        OperandValue::Immediate(v).store(bx, place);
    }

    // Store mark in a metadata node so we can map LLVM errors
    // back to source locations.  See #17552.
    unsafe {
        let key = "srcloc";
        let kind = llvm::LLVMGetMDKindIDInContext(bx.cx.llcx,
            key.as_ptr() as *const c_char, key.len() as c_uint);

        let val: llvm::ValueRef = C_i32(bx.cx, ia.ctxt.outer().as_u32() as i32);

        llvm::LLVMSetMetadata(r, kind,
            llvm::LLVMMDNodeInContext(bx.cx.llcx, &val, 1));
    }
}

pub fn trans_global_asm<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
                                  ga: &hir::GlobalAsm) {
    let asm = CString::new(ga.asm.as_str().as_bytes()).unwrap();
    unsafe {
        llvm::LLVMRustAppendModuleInlineAsm(cx.llmod, asm.as_ptr());
    }
}
<commit_msg>rustc_trans: clobber $1 (aka $at) on mips<commit_after>// Copyright 2012-2015 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.

//! # Translation of inline assembly.

use llvm::{self, ValueRef};
use common::*;
use type_::Type;
use type_of::LayoutLlvmExt;
use builder::Builder;

use rustc::hir;

use mir::place::PlaceRef;
use mir::operand::OperandValue;

use std::ffi::CString;
use syntax::ast::AsmDialect;
use libc::{c_uint, c_char};

// Take an inline assembly expression and splat it out via LLVM
pub fn trans_inline_asm<'a, 'tcx>(
    bx: &Builder<'a, 'tcx>,
    ia: &hir::InlineAsm,
    outputs: Vec<PlaceRef<'tcx>>,
    mut inputs: Vec<ValueRef>
) {
    let mut ext_constraints = vec![];
    let mut output_types = vec![];

    // Prepare the output operands
    let mut indirect_outputs = vec![];
    for (i, (out, place)) in ia.outputs.iter().zip(&outputs).enumerate() {
        if out.is_rw {
            inputs.push(place.load(bx).immediate());
            ext_constraints.push(i.to_string());
        }
        if out.is_indirect {
            indirect_outputs.push(place.load(bx).immediate());
        } else {
            output_types.push(place.layout.llvm_type(bx.cx));
        }
    }
    if !indirect_outputs.is_empty() {
        indirect_outputs.extend_from_slice(&inputs);
        inputs = indirect_outputs;
    }

    let clobbers = ia.clobbers.iter()
                              .map(|s| format!("~{{{}}}", &s));

    // Default per-arch clobbers
    // Basically what clang does
    let arch_clobbers = match &bx.sess().target.target.arch[..] {
        "x86" | "x86_64"  => vec!["~{dirflag}", "~{fpsr}", "~{flags}"],
        "mips" | "mips64" => vec!["~{$1}"],
        _                 => Vec::new()
    };

    let all_constraints =
        ia.outputs.iter().map(|out| out.constraint.to_string())
          .chain(ia.inputs.iter().map(|s| s.to_string()))
          .chain(ext_constraints)
          .chain(clobbers)
          .chain(arch_clobbers.iter().map(|s| s.to_string()))
          .collect::<Vec<String>>().join(",");

    debug!("Asm Constraints: {}", &all_constraints);

    // Depending on how many outputs we have, the return type is different
    let num_outputs = output_types.len();
    let output_type = match num_outputs {
        0 => Type::void(bx.cx),
        1 => output_types[0],
        _ => Type::struct_(bx.cx, &output_types, false)
    };

    let dialect = match ia.dialect {
        AsmDialect::Att   => llvm::AsmDialect::Att,
        AsmDialect::Intel => llvm::AsmDialect::Intel,
    };

    let asm = CString::new(ia.asm.as_str().as_bytes()).unwrap();
    let constraint_cstr = CString::new(all_constraints).unwrap();
    let r = bx.inline_asm_call(
        asm.as_ptr(),
        constraint_cstr.as_ptr(),
        &inputs,
        output_type,
        ia.volatile,
        ia.alignstack,
        dialect
    );

    // Again, based on how many outputs we have
    let outputs = ia.outputs.iter().zip(&outputs).filter(|&(ref o, _)| !o.is_indirect);
    for (i, (_, &place)) in outputs.enumerate() {
        let v = if num_outputs == 1 { r } else { bx.extract_value(r, i as u64) };
        OperandValue::Immediate(v).store(bx, place);
    }

    // Store mark in a metadata node so we can map LLVM errors
    // back to source locations.  See #17552.
    unsafe {
        let key = "srcloc";
        let kind = llvm::LLVMGetMDKindIDInContext(bx.cx.llcx,
            key.as_ptr() as *const c_char, key.len() as c_uint);

        let val: llvm::ValueRef = C_i32(bx.cx, ia.ctxt.outer().as_u32() as i32);

        llvm::LLVMSetMetadata(r, kind,
            llvm::LLVMMDNodeInContext(bx.cx.llcx, &val, 1));
    }
}

pub fn trans_global_asm<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
                                  ga: &hir::GlobalAsm) {
    let asm = CString::new(ga.asm.as_str().as_bytes()).unwrap();
    unsafe {
        llvm::LLVMRustAppendModuleInlineAsm(cx.llmod, asm.as_ptr());
    }
}
<|endoftext|>