<commit_before>use std::fmt;
use memory::Memory;
use super::Size;
use PC;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Operand {
    DataRegisterDirect(u8),
    AddressRegisterDirect(u8),
    AddressRegisterIndirect(u8),
    AddressRegisterIndirectWithPredecrement(u8),
    AddressRegisterIndirectWithPostincrement(u8),
    AddressRegisterIndirectWithDisplacement(u8, i16),
    AddressRegisterIndirectWithIndex(u8, u8, i8),
    PcWithDisplacement(i16),
    PcWithIndex(u8, i8),
    AbsoluteWord(u16),
    AbsoluteLong(u32),
    Immediate(Size, u32),
    StatusRegister(Size),
    Displacement(Size, u32),
    Number(Size, u32),
    Registers(u16, bool), // reglist, reversed
}

fn encode_extension_word(xreg_ndx_size: u8, displacement: i8) -> u16 {
    // top four bits = (D/A RRR) matches our register array layout
    (((xreg_ndx_size as u16) << 12) | (displacement as u8 as u16)) as u16
}

impl Operand {
    pub fn extension_words(&self) -> u32 {
        match *self {
            Operand::DataRegisterDirect(_) => 0,
            Operand::AddressRegisterDirect(_) => 0,
            Operand::AddressRegisterIndirect(_) => 0,
            Operand::AddressRegisterIndirectWithPredecrement(_) => 0,
            Operand::AddressRegisterIndirectWithPostincrement(_) => 0,
            Operand::AddressRegisterIndirectWithDisplacement(_, _) => 1,
            Operand::AddressRegisterIndirectWithIndex(_, _, _) => 1,
            Operand::AbsoluteWord(_) => 1,
            Operand::AbsoluteLong(_) => 2,
            Operand::Displacement(Size::Byte, _) => 0,
            Operand::Displacement(Size::Word, _) => 1,
            Operand::Displacement(Size::Long, _) => 2,
            Operand::Displacement(Size::Unsized, _) => panic!("unsized {:?}", self),
            Operand::Number(_, _) => panic!("unsized {:?}", self),
            Operand::PcWithDisplacement(_) => 1,
            Operand::PcWithIndex(_, _) => 1,
            Operand::Immediate(Size::Byte, _) => 1,
            Operand::Immediate(Size::Word, _) => 1,
            Operand::Immediate(Size::Long, _) => 2,
            Operand::Immediate(Size::Unsized, _) => panic!("unsized {:?}", self),
            Operand::StatusRegister(_) => 0,
            Operand::Registers(_, _) => 1,
        }
    }

    pub fn add_extension_words(&self, pc: PC, mem: &mut Memory) -> PC {
        match *self {
            Operand::DataRegisterDirect(_) => pc,
            Operand::AddressRegisterDirect(_) => pc,
            Operand::AddressRegisterIndirect(_) => pc,
            Operand::AddressRegisterIndirectWithPredecrement(_) => pc,
            Operand::AddressRegisterIndirectWithPostincrement(_) => pc,
            Operand::AddressRegisterIndirectWithDisplacement(_, displacement) =>
                mem.write_word(pc, displacement as u16),
            Operand::AddressRegisterIndirectWithIndex(_, indexinfo, displacement) =>
                mem.write_word(pc, encode_extension_word(indexinfo, displacement)),
            Operand::AbsoluteWord(val) => mem.write_word(pc, val as u16),
            Operand::AbsoluteLong(val) => {
                mem.write_word(pc, (val >> 16) as u16);
                mem.write_word(pc + 2, val as u16)
            },
            Operand::Displacement(Size::Byte, _) => pc,
            Operand::Displacement(Size::Word, val) => mem.write_word(pc, val as u16),
            Operand::Displacement(Size::Long, val) => {
                mem.write_word(pc, (val >> 16) as u16);
                mem.write_word(pc + 2, val as u16)
            },
            Operand::Displacement(Size::Unsized, _) => panic!("unsized {:?}", self),
            Operand::Number(_, _) => panic!("unsized {:?}", self),
            Operand::PcWithDisplacement(displacement) => mem.write_word(pc, displacement as u16),
            Operand::PcWithIndex(indexinfo, displacement) => mem.write_word(pc, encode_extension_word(indexinfo, displacement)),
            Operand::Immediate(Size::Byte, val) => mem.write_word(pc, (val & 0xff) as u16),
            Operand::Immediate(Size::Word, val) => mem.write_word(pc, val as u16),
            Operand::Immediate(Size::Long, val) => {
                mem.write_word(pc, (val >> 16) as u16);
                mem.write_word(pc + 2, val as u16)
            }
            Operand::Immediate(Size::Unsized, _) => panic!("unsized {:?}", self),
            Operand::StatusRegister(_) => pc,
            Operand::Registers(reglist, false) => mem.write_word(pc, reglist),
            Operand::Registers(reglist, true) => mem.write_word(pc, bit_reverse(reglist)),
        }
    }
}

fn bit_reverse(x: u16) -> u16 {
    let x = (x & 0b1010_1010_1010_1010) >> 1 | (x & 0b0101_0101_0101_0101) << 1;
    let x = (x & 0b1100_1100_1100_1100) >> 2 | (x & 0b0011_0011_0011_0011) << 2;
    let x = (x & 0b1111_0000_1111_0000) >> 4 | (x & 0b0000_1111_0000_1111) << 4;
    (x >> 8 | x << 8)
}

impl fmt::Display for Operand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fn write_registers(f: &mut fmt::Formatter, reglist: u16) -> fmt::Result {
            let mut result: fmt::Result = Ok(());
            let mut reglist = reglist;
            let mut first = true;
            for bit in 0..16u16 {
                if (1 << bit) & reglist != 0 {
                    let mut span = bit;
                    let span = loop {
                        if span < 16 {
                            let spanbit = (1 << span);
                            if spanbit & reglist != 0 {
                                reglist &= !spanbit;
                                span += 1;
                                continue;
                            }
                        }
                        break span - 1;
                    };
                    if !first {
                        result = write!(f, "/");
                    };
                    first = false;
                    if span == bit {
                        if bit > 7 {
                            result = write!(f, "A{}", bit-8);
                        } else {
                            result = write!(f, "D{}", bit);
                        }
                    } else {
                        if bit > 7 {
                            result = write!(f, "A{}-", bit-8);
                        } else {
                            result = write!(f, "D{}-", bit);
                        }
                        if span > 7 {
                            result = write!(f, "A{}", span-8);
                        } else {
                            result = write!(f, "D{}", span);
                        }
                    }
                }
            };
            result
        };
        match *self {
            Operand::DataRegisterDirect(reg) => write!(f, "D{}", reg),
            Operand::AddressRegisterDirect(reg) => write!(f, "A{}", reg),
            Operand::AddressRegisterIndirect(reg) => write!(f, "(A{})", reg),
            Operand::AddressRegisterIndirectWithPredecrement(reg) => write!(f, "-(A{})", reg),
            Operand::AddressRegisterIndirectWithPostincrement(reg) => write!(f, "(A{})+", reg),
            Operand::AddressRegisterIndirectWithDisplacement(reg, dis) => write!(f, "{}(A{})", dis, reg),
            Operand::AddressRegisterIndirectWithIndex(reg, ireg, dis) => write!(f, "{}(A{},{})", dis, reg, xreg(ireg)),
            Operand::PcWithDisplacement(dis) => write!(f, "{}(PC)", dis),
            Operand::PcWithIndex(ireg, dis) => write!(f, "{}(PC,{})", dis, xreg(ireg)),
            Operand::AbsoluteWord(val) => write!(f, "${:04X}", val),
            Operand::AbsoluteLong(val) => write!(f, "${:08X}", val),
            Operand::Number(Size::Byte, val) => write!(f, "${:02X}", val),
            Operand::Number(Size::Word, val) => write!(f, "${:04X}", val),
            Operand::Number(Size::Long, val) => write!(f, "${:08X}", val),
            Operand::Number(Size::Unsized, val) => write!(f, "${:08X}.?", val),
            Operand::Displacement(Size::Byte, val) => write!(f, "${:02X}", val),
            Operand::Displacement(Size::Word, val) => write!(f, "${:04X}", val),
            Operand::Displacement(Size::Long, val) => write!(f, "${:08X}", val),
            Operand::Displacement(Size::Unsized, val) => write!(f, "${:08X}.?", val),
            Operand::Immediate(Size::Byte, val) => write!(f, "#${:02X}", val),
            Operand::Immediate(Size::Word, val) => write!(f, "#${:04X}", val),
            Operand::Immediate(Size::Long, val) => write!(f, "#${:08X}", val),
            Operand::Immediate(Size::Unsized, val) => write!(f, "#${:08X}.?", val),
            Operand::StatusRegister(Size::Byte) => write!(f, "CCR"),
            Operand::StatusRegister(_) => write!(f, "SR"),
            Operand::Registers(reglist, false) => write_registers(f, reglist),
            Operand::Registers(reglist, true) => write_registers(f, bit_reverse(reglist)),
         }
    }
}

fn xreg(xreg: u8) -> Operand {
    if xreg & 8 > 0 {
        Operand::AddressRegisterDirect(xreg & 7)
    } else {
        Operand::DataRegisterDirect(xreg & 7)
    }
}

#[cfg(test)]
mod tests {
    use operand::bit_reverse;
    extern crate rand;
    use self::rand::Rng;
    use operand::Operand;

    #[test]
    fn simple_bit_reversal() {
        assert_eq!(0b1101_0011_1010_0001, bit_reverse(0b1000_0101_1100_1011));
    }

    #[test]
    fn bit_reversal() {
        let mut r = rand::thread_rng();
        for _ in 0..1000 {
            let v = r.gen();
            assert_eq!(v, bit_reverse(bit_reverse(v)));
        }
    }

    #[test]
    fn single_bit_registers_operand() {
        for bit in 0..16 {
            let expected = if bit < 8 {
                format!("D{}", bit)
            } else {
                format!("A{}", bit-8)
            };
            assert_eq!(expected, format!("{}", Operand::Registers(1 << bit, false)));
        }
    }
    #[test]
    fn separate_registers_operand() {
        assert_eq!("A1/A4", format!("{}", Operand::Registers(0b0001_0010_0000_0000, false)));
        assert_eq!("D5/A2", format!("{}", Operand::Registers(0b0000_0100_0010_0000, false)));
    }
    #[test]
    fn spanning_registers_operand() {
        assert_eq!("A1-A4", format!("{}", Operand::Registers(0b0001_1110_0000_0000, false)));
        assert_eq!("D5-A2", format!("{}", Operand::Registers(0b0000_0111_1110_0000, false)));
    }
    #[test]
    fn combined_registers_operand() {
        assert_eq!("D4/A1-A4", format!("{}", Operand::Registers(0b0001_1110_0001_0000, false)));
        assert_eq!("D5-A2/A5", format!("{}", Operand::Registers(0b0010_0111_1110_0000, false)));
    }
}<commit_msg>Add UserStackPointer operand<commit_after>use std::fmt;
use memory::Memory;
use super::Size;
use PC;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Operand {
    DataRegisterDirect(u8),
    AddressRegisterDirect(u8),
    AddressRegisterIndirect(u8),
    AddressRegisterIndirectWithPredecrement(u8),
    AddressRegisterIndirectWithPostincrement(u8),
    AddressRegisterIndirectWithDisplacement(u8, i16),
    AddressRegisterIndirectWithIndex(u8, u8, i8),
    PcWithDisplacement(i16),
    PcWithIndex(u8, i8),
    AbsoluteWord(u16),
    AbsoluteLong(u32),
    Immediate(Size, u32),
    StatusRegister(Size),
    Displacement(Size, u32),
    Number(Size, u32),
    Registers(u16, bool), // reglist, reversed
    UserStackPointer,
}

fn encode_extension_word(xreg_ndx_size: u8, displacement: i8) -> u16 {
    // top four bits = (D/A RRR) matches our register array layout
    (((xreg_ndx_size as u16) << 12) | (displacement as u8 as u16)) as u16
}

impl Operand {
    pub fn extension_words(&self) -> u32 {
        match *self {
            Operand::DataRegisterDirect(_) => 0,
            Operand::AddressRegisterDirect(_) => 0,
            Operand::AddressRegisterIndirect(_) => 0,
            Operand::AddressRegisterIndirectWithPredecrement(_) => 0,
            Operand::AddressRegisterIndirectWithPostincrement(_) => 0,
            Operand::AddressRegisterIndirectWithDisplacement(_, _) => 1,
            Operand::AddressRegisterIndirectWithIndex(_, _, _) => 1,
            Operand::AbsoluteWord(_) => 1,
            Operand::AbsoluteLong(_) => 2,
            Operand::Displacement(Size::Byte, _) => 0,
            Operand::Displacement(Size::Word, _) => 1,
            Operand::Displacement(Size::Long, _) => 2,
            Operand::Displacement(Size::Unsized, _) => panic!("unsized {:?}", self),
            Operand::Number(_, _) => panic!("unsized {:?}", self),
            Operand::PcWithDisplacement(_) => 1,
            Operand::PcWithIndex(_, _) => 1,
            Operand::Immediate(Size::Byte, _) => 1,
            Operand::Immediate(Size::Word, _) => 1,
            Operand::Immediate(Size::Long, _) => 2,
            Operand::Immediate(Size::Unsized, _) => panic!("unsized {:?}", self),
            Operand::StatusRegister(_) => 0,
            Operand::Registers(_, _) => 1,
            Operand::UserStackPointer => 0,
        }
    }

    pub fn add_extension_words(&self, pc: PC, mem: &mut Memory) -> PC {
        match *self {
            Operand::DataRegisterDirect(_) => pc,
            Operand::AddressRegisterDirect(_) => pc,
            Operand::AddressRegisterIndirect(_) => pc,
            Operand::AddressRegisterIndirectWithPredecrement(_) => pc,
            Operand::AddressRegisterIndirectWithPostincrement(_) => pc,
            Operand::AddressRegisterIndirectWithDisplacement(_, displacement) =>
                mem.write_word(pc, displacement as u16),
            Operand::AddressRegisterIndirectWithIndex(_, indexinfo, displacement) =>
                mem.write_word(pc, encode_extension_word(indexinfo, displacement)),
            Operand::AbsoluteWord(val) => mem.write_word(pc, val as u16),
            Operand::AbsoluteLong(val) => {
                mem.write_word(pc, (val >> 16) as u16);
                mem.write_word(pc + 2, val as u16)
            },
            Operand::Displacement(Size::Byte, _) => pc,
            Operand::Displacement(Size::Word, val) => mem.write_word(pc, val as u16),
            Operand::Displacement(Size::Long, val) => {
                mem.write_word(pc, (val >> 16) as u16);
                mem.write_word(pc + 2, val as u16)
            },
            Operand::Displacement(Size::Unsized, _) => panic!("unsized {:?}", self),
            Operand::Number(_, _) => panic!("unsized {:?}", self),
            Operand::PcWithDisplacement(displacement) => mem.write_word(pc, displacement as u16),
            Operand::PcWithIndex(indexinfo, displacement) => mem.write_word(pc, encode_extension_word(indexinfo, displacement)),
            Operand::Immediate(Size::Byte, val) => mem.write_word(pc, (val & 0xff) as u16),
            Operand::Immediate(Size::Word, val) => mem.write_word(pc, val as u16),
            Operand::Immediate(Size::Long, val) => {
                mem.write_word(pc, (val >> 16) as u16);
                mem.write_word(pc + 2, val as u16)
            }
            Operand::Immediate(Size::Unsized, _) => panic!("unsized {:?}", self),
            Operand::StatusRegister(_) => pc,
            Operand::Registers(reglist, false) => mem.write_word(pc, reglist),
            Operand::Registers(reglist, true) => mem.write_word(pc, bit_reverse(reglist)),
            Operand::UserStackPointer => pc,
        }
    }
}

fn bit_reverse(x: u16) -> u16 {
    let x = (x & 0b1010_1010_1010_1010) >> 1 | (x & 0b0101_0101_0101_0101) << 1;
    let x = (x & 0b1100_1100_1100_1100) >> 2 | (x & 0b0011_0011_0011_0011) << 2;
    let x = (x & 0b1111_0000_1111_0000) >> 4 | (x & 0b0000_1111_0000_1111) << 4;
    (x >> 8 | x << 8)
}

impl fmt::Display for Operand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fn write_registers(f: &mut fmt::Formatter, reglist: u16) -> fmt::Result {
            let mut result: fmt::Result = Ok(());
            let mut reglist = reglist;
            let mut first = true;
            for bit in 0..16u16 {
                if (1 << bit) & reglist != 0 {
                    let mut span = bit;
                    let span = loop {
                        if span < 16 {
                            let spanbit = (1 << span);
                            if spanbit & reglist != 0 {
                                reglist &= !spanbit;
                                span += 1;
                                continue;
                            }
                        }
                        break span - 1;
                    };
                    if !first {
                        result = write!(f, "/");
                    };
                    first = false;
                    if span == bit {
                        if bit > 7 {
                            result = write!(f, "A{}", bit-8);
                        } else {
                            result = write!(f, "D{}", bit);
                        }
                    } else {
                        if bit > 7 {
                            result = write!(f, "A{}-", bit-8);
                        } else {
                            result = write!(f, "D{}-", bit);
                        }
                        if span > 7 {
                            result = write!(f, "A{}", span-8);
                        } else {
                            result = write!(f, "D{}", span);
                        }
                    }
                }
            };
            result
        };
        match *self {
            Operand::DataRegisterDirect(reg) => write!(f, "D{}", reg),
            Operand::AddressRegisterDirect(reg) => write!(f, "A{}", reg),
            Operand::AddressRegisterIndirect(reg) => write!(f, "(A{})", reg),
            Operand::AddressRegisterIndirectWithPredecrement(reg) => write!(f, "-(A{})", reg),
            Operand::AddressRegisterIndirectWithPostincrement(reg) => write!(f, "(A{})+", reg),
            Operand::AddressRegisterIndirectWithDisplacement(reg, dis) => write!(f, "{}(A{})", dis, reg),
            Operand::AddressRegisterIndirectWithIndex(reg, ireg, dis) => write!(f, "{}(A{},{})", dis, reg, xreg(ireg)),
            Operand::PcWithDisplacement(dis) => write!(f, "{}(PC)", dis),
            Operand::PcWithIndex(ireg, dis) => write!(f, "{}(PC,{})", dis, xreg(ireg)),
            Operand::AbsoluteWord(val) => write!(f, "${:04X}", val),
            Operand::AbsoluteLong(val) => write!(f, "${:08X}", val),
            Operand::Number(Size::Byte, val) => write!(f, "${:02X}", val),
            Operand::Number(Size::Word, val) => write!(f, "${:04X}", val),
            Operand::Number(Size::Long, val) => write!(f, "${:08X}", val),
            Operand::Number(Size::Unsized, val) => write!(f, "${:08X}.?", val),
            Operand::Displacement(Size::Byte, val) => write!(f, "${:02X}", val),
            Operand::Displacement(Size::Word, val) => write!(f, "${:04X}", val),
            Operand::Displacement(Size::Long, val) => write!(f, "${:08X}", val),
            Operand::Displacement(Size::Unsized, val) => write!(f, "${:08X}.?", val),
            Operand::Immediate(Size::Byte, val) => write!(f, "#${:02X}", val),
            Operand::Immediate(Size::Word, val) => write!(f, "#${:04X}", val),
            Operand::Immediate(Size::Long, val) => write!(f, "#${:08X}", val),
            Operand::Immediate(Size::Unsized, val) => write!(f, "#${:08X}.?", val),
            Operand::StatusRegister(Size::Byte) => write!(f, "CCR"),
            Operand::StatusRegister(_) => write!(f, "SR"),
            Operand::Registers(reglist, false) => write_registers(f, reglist),
            Operand::Registers(reglist, true) => write_registers(f, bit_reverse(reglist)),
            Operand::UserStackPointer => write!(f, "USP"),
         }
    }
}

fn xreg(xreg: u8) -> Operand {
    if xreg & 8 > 0 {
        Operand::AddressRegisterDirect(xreg & 7)
    } else {
        Operand::DataRegisterDirect(xreg & 7)
    }
}

#[cfg(test)]
mod tests {
    use operand::bit_reverse;
    extern crate rand;
    use self::rand::Rng;
    use operand::Operand;

    #[test]
    fn simple_bit_reversal() {
        assert_eq!(0b1101_0011_1010_0001, bit_reverse(0b1000_0101_1100_1011));
    }

    #[test]
    fn bit_reversal() {
        let mut r = rand::thread_rng();
        for _ in 0..1000 {
            let v = r.gen();
            assert_eq!(v, bit_reverse(bit_reverse(v)));
        }
    }

    #[test]
    fn single_bit_registers_operand() {
        for bit in 0..16 {
            let expected = if bit < 8 {
                format!("D{}", bit)
            } else {
                format!("A{}", bit-8)
            };
            assert_eq!(expected, format!("{}", Operand::Registers(1 << bit, false)));
        }
    }
    #[test]
    fn separate_registers_operand() {
        assert_eq!("A1/A4", format!("{}", Operand::Registers(0b0001_0010_0000_0000, false)));
        assert_eq!("D5/A2", format!("{}", Operand::Registers(0b0000_0100_0010_0000, false)));
    }
    #[test]
    fn spanning_registers_operand() {
        assert_eq!("A1-A4", format!("{}", Operand::Registers(0b0001_1110_0000_0000, false)));
        assert_eq!("D5-A2", format!("{}", Operand::Registers(0b0000_0111_1110_0000, false)));
    }
    #[test]
    fn combined_registers_operand() {
        assert_eq!("D4/A1-A4", format!("{}", Operand::Registers(0b0001_1110_0001_0000, false)));
        assert_eq!("D5-A2/A5", format!("{}", Operand::Registers(0b0010_0111_1110_0000, false)));
    }
}<|endoftext|>


<commit_before>//! Checks the licenses of third-party dependencies.

use cargo_metadata::{Metadata, Package, PackageId};
use std::collections::{BTreeSet, HashSet};
use std::path::Path;

const LICENSES: &[&str] = &[
    "MIT/Apache-2.0",
    "MIT / Apache-2.0",
    "Apache-2.0/MIT",
    "Apache-2.0 / MIT",
    "MIT OR Apache-2.0",
    "Apache-2.0 OR MIT",
    "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", // wasi license
    "MIT",
    "Unlicense/MIT",
    "Unlicense OR MIT",
];

/// These are exceptions to Rust's permissive licensing policy, and
/// should be considered bugs. Exceptions are only allowed in Rust
/// tooling. It is _crucial_ that no exception crates be dependencies
/// of the Rust runtime (std/test).
const EXCEPTIONS: &[&str] = &[
    "mdbook",             // MPL2, mdbook
    "openssl",            // BSD+advertising clause, cargo, mdbook
    "pest",               // MPL2, mdbook via handlebars
    "arrayref",           // BSD-2-Clause, mdbook via handlebars via pest
    "toml-query",         // MPL-2.0, mdbook
    "toml-query_derive",  // MPL-2.0, mdbook
    "is-match",           // MPL-2.0, mdbook
    "smallvec",           // MPL-2.0, rustdoc
    "rdrand",             // ISC, mdbook, rustfmt
    "fuchsia-cprng",      // BSD-3-Clause, mdbook, rustfmt
    "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo
    "fuchsia-zircon",     // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir)
    "clippy_lints",       // MPL-2.0, rls
    "colored",            // MPL-2.0, rustfmt
    "ordslice",           // Apache-2.0, rls
    "cloudabi",           // BSD-2-Clause, (rls -> crossbeam-channel 0.2 -> rand 0.5)
    "ryu",                // Apache-2.0, rls/cargo/... (because of serde)
    "bytesize",           // Apache-2.0, cargo
    "im-rc",              // MPL-2.0+, cargo
    "adler32",            // BSD-3-Clause AND Zlib, cargo dep that isn't used
    "constant_time_eq",   // CC0-1.0, rustfmt
    "utf8parse",          // Apache-2.0 OR MIT, cargo via strip-ansi-escapes
    "vte",                // Apache-2.0 OR MIT, cargo via strip-ansi-escapes
    "sized-chunks",       // MPL-2.0+, cargo via im-rc
    "bitmaps",            // MPL-2.0+, cargo via im-rc
    // FIXME: this dependency violates the documentation comment above:
    "fortanix-sgx-abi",   // MPL-2.0+, libstd but only for `sgx` target
    "dunce",              // CC0-1.0 mdbook-linkcheck
    "codespan-reporting", // Apache-2.0 mdbook-linkcheck
    "codespan",           // Apache-2.0 mdbook-linkcheck
    "crossbeam-channel",  // MIT/Apache-2.0 AND BSD-2-Clause, cargo
];

/// Which crates to check against the whitelist?
const WHITELIST_CRATES: &[&str] = &["rustc", "rustc_codegen_llvm"];

/// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible.
const WHITELIST: &[&str] = &[
    "adler32",
    "aho-corasick",
    "annotate-snippets",
    "ansi_term",
    "arrayvec",
    "atty",
    "autocfg",
    "backtrace",
    "backtrace-sys",
    "bitflags",
    "byteorder",
    "c2-chacha",
    "cc",
    "cfg-if",
    "chalk-engine",
    "chalk-macros",
    "cloudabi",
    "cmake",
    "compiler_builtins",
    "crc32fast",
    "crossbeam-deque",
    "crossbeam-epoch",
    "crossbeam-queue",
    "crossbeam-utils",
    "datafrog",
    "dlmalloc",
    "either",
    "ena",
    "env_logger",
    "filetime",
    "flate2",
    "fortanix-sgx-abi",
    "fuchsia-zircon",
    "fuchsia-zircon-sys",
    "getopts",
    "getrandom",
    "hashbrown",
    "humantime",
    "indexmap",
    "itertools",
    "jobserver",
    "kernel32-sys",
    "lazy_static",
    "libc",
    "libz-sys",
    "lock_api",
    "log",
    "log_settings",
    "measureme",
    "memchr",
    "memmap",
    "memoffset",
    "miniz_oxide",
    "nodrop",
    "num_cpus",
    "parking_lot",
    "parking_lot_core",
    "pkg-config",
    "polonius-engine",
    "ppv-lite86",
    "proc-macro2",
    "punycode",
    "quick-error",
    "quote",
    "rand",
    "rand_chacha",
    "rand_core",
    "rand_hc",
    "rand_isaac",
    "rand_pcg",
    "rand_xorshift",
    "redox_syscall",
    "redox_termios",
    "regex",
    "regex-syntax",
    "remove_dir_all",
    "rustc-demangle",
    "rustc-hash",
    "rustc-rayon",
    "rustc-rayon-core",
    "rustc_version",
    "scoped-tls",
    "scopeguard",
    "semver",
    "semver-parser",
    "serde",
    "serde_derive",
    "smallvec",
    "stable_deref_trait",
    "syn",
    "synstructure",
    "tempfile",
    "termcolor",
    "termion",
    "termize",
    "thread_local",
    "ucd-util",
    "unicode-normalization",
    "unicode-script",
    "unicode-security",
    "unicode-width",
    "unicode-xid",
    "utf8-ranges",
    "vcpkg",
    "version_check",
    "wasi",
    "winapi",
    "winapi-build",
    "winapi-i686-pc-windows-gnu",
    "winapi-util",
    "winapi-x86_64-pc-windows-gnu",
    "wincolor",
    "hermit-abi",
];

/// Dependency checks.
///
/// `path` is path to the `src` directory, `cargo` is path to the cargo executable.
pub fn check(path: &Path, cargo: &Path, bad: &mut bool) {
    let mut cmd = cargo_metadata::MetadataCommand::new();
    cmd.cargo_path(cargo)
        .manifest_path(path.parent().unwrap().join("Cargo.toml"))
        .features(cargo_metadata::CargoOpt::AllFeatures);
    let metadata = t!(cmd.exec());
    check_exceptions(&metadata, bad);
    check_whitelist(&metadata, bad);
    check_crate_duplicate(&metadata, bad);
}

/// Check that all licenses are in the valid list in `LICENSES`.
///
/// Packages listed in `EXCEPTIONS` are allowed for tools.
fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
    // Check that the EXCEPTIONS list does not have unused entries.
    for exception in EXCEPTIONS {
        if !metadata.packages.iter().any(|p| p.name == *exception) {
            println!(
                "could not find exception package `{}`\n\
                Remove from EXCEPTIONS list if it is no longer used.",
                exception
            );
            *bad = true;
        }
    }
    // Check if any package does not have a valid license.
    for pkg in &metadata.packages {
        if pkg.source.is_none() {
            // No need to check local packages.
            continue;
        }
        if EXCEPTIONS.contains(&pkg.name.as_str()) {
            continue;
        }
        let license = match &pkg.license {
            Some(license) => license,
            None => {
                println!("dependency `{}` does not define a license expression", pkg.id,);
                *bad = true;
                continue;
            }
        };
        if !LICENSES.contains(&license.as_str()) {
            println!("invalid license `{}` in `{}`", license, pkg.id);
            *bad = true;
        }
    }
}

/// Checks the dependency of `WHITELIST_CRATES` at the given path. Changes `bad` to `true` if a
/// check failed.
///
/// Specifically, this checks that the dependencies are on the `WHITELIST`.
fn check_whitelist(metadata: &Metadata, bad: &mut bool) {
    // Check that the WHITELIST does not have unused entries.
    for name in WHITELIST {
        if !metadata.packages.iter().any(|p| p.name == *name) {
            println!(
                "could not find whitelisted package `{}`\n\
                Remove from WHITELIST list if it is no longer used.",
                name
            );
            *bad = true;
        }
    }
    // Get the whitelist in a convenient form.
    let whitelist: HashSet<_> = WHITELIST.iter().cloned().collect();

    // Check dependencies.
    let mut visited = BTreeSet::new();
    let mut unapproved = BTreeSet::new();
    for &krate in WHITELIST_CRATES.iter() {
        let pkg = pkg_from_name(metadata, krate);
        let mut bad = check_crate_whitelist(&whitelist, metadata, &mut visited, pkg);
        unapproved.append(&mut bad);
    }

    if !unapproved.is_empty() {
        println!("Dependencies not on the whitelist:");
        for dep in unapproved {
            println!("* {}", dep);
        }
        *bad = true;
    }
}

/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
/// the whitelist. Returns a list of illegal dependencies.
fn check_crate_whitelist<'a>(
    whitelist: &'a HashSet<&'static str>,
    metadata: &'a Metadata,
    visited: &mut BTreeSet<&'a PackageId>,
    krate: &'a Package,
) -> BTreeSet<&'a PackageId> {
    // This will contain bad deps.
    let mut unapproved = BTreeSet::new();

    // Check if we have already visited this crate.
    if visited.contains(&krate.id) {
        return unapproved;
    }

    visited.insert(&krate.id);

    // If this path is in-tree, we don't require it to be on the whitelist.
    if krate.source.is_some() {
        // If this dependency is not on `WHITELIST`, add to bad set.
        if !whitelist.contains(krate.name.as_str()) {
            unapproved.insert(&krate.id);
        }
    }

    // Do a DFS in the crate graph.
    let to_check = deps_of(metadata, &krate.id);

    for dep in to_check {
        let mut bad = check_crate_whitelist(whitelist, metadata, visited, dep);
        unapproved.append(&mut bad);
    }

    unapproved
}

/// Prevents multiple versions of some expensive crates.
fn check_crate_duplicate(metadata: &Metadata, bad: &mut bool) {
    const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[
        // These two crates take quite a long time to build, so don't allow two versions of them
        // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times
        // under control.
        "cargo",
        "rustc-ap-syntax",
    ];

    for &name in FORBIDDEN_TO_HAVE_DUPLICATES {
        let matches: Vec<_> = metadata.packages.iter().filter(|pkg| pkg.name == name).collect();
        match matches.len() {
            0 => {
                println!(
                    "crate `{}` is missing, update `check_crate_duplicate` \
                    if it is no longer used",
                    name
                );
                *bad = true;
            }
            1 => {}
            _ => {
                println!(
                    "crate `{}` is duplicated in `Cargo.lock`, \
                    it is too expensive to build multiple times, \
                    so make sure only one version appears across all dependencies",
                    name
                );
                for pkg in matches {
                    println!("  * {}", pkg.id);
                }
                *bad = true;
            }
        }
    }
}

/// Returns a list of dependencies for the given package.
fn deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package> {
    let node = metadata
        .resolve
        .as_ref()
        .unwrap()
        .nodes
        .iter()
        .find(|n| &n.id == pkg_id)
        .unwrap_or_else(|| panic!("could not find `{}` in resolve", pkg_id));
    node.deps
        .iter()
        .map(|dep| {
            metadata.packages.iter().find(|pkg| pkg.id == dep.pkg).unwrap_or_else(|| {
                panic!("could not find dep `{}` for pkg `{}` in resolve", dep.pkg, pkg_id)
            })
        })
        .collect()
}

/// Finds a package with the given name.
fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package {
    let mut i = metadata.packages.iter().filter(|p| p.name == name);
    let result =
        i.next().unwrap_or_else(|| panic!("could not find package `{}` in package list", name));
    assert!(i.next().is_none(), "more than one package found for `{}`", name);
    result
}
<commit_msg>tidy: check the licenses don't change<commit_after>//! Checks the licenses of third-party dependencies.

use cargo_metadata::{Metadata, Package, PackageId};
use std::collections::{BTreeSet, HashSet};
use std::path::Path;

const LICENSES: &[&str] = &[
    "MIT/Apache-2.0",
    "MIT / Apache-2.0",
    "Apache-2.0/MIT",
    "Apache-2.0 / MIT",
    "MIT OR Apache-2.0",
    "Apache-2.0 OR MIT",
    "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", // wasi license
    "MIT",
    "Unlicense/MIT",
    "Unlicense OR MIT",
];

/// These are exceptions to Rust's permissive licensing policy, and
/// should be considered bugs. Exceptions are only allowed in Rust
/// tooling. It is _crucial_ that no exception crates be dependencies
/// of the Rust runtime (std/test).
const EXCEPTIONS: &[(&str, &str)] = &[
    ("mdbook", "MPL-2.0"),                  // mdbook
    ("openssl", "Apache-2.0"),              // cargo, mdbook
    ("arrayref", "BSD-2-Clause"),           // mdbook via handlebars via pest
    ("toml-query", "MPL-2.0"),              // mdbook
    ("toml-query_derive", "MPL-2.0"),       // mdbook
    ("is-match", "MPL-2.0"),                // mdbook
    ("rdrand", "ISC"),                      // mdbook, rustfmt
    ("fuchsia-cprng", "BSD-3-Clause"),      // mdbook, rustfmt
    ("fuchsia-zircon-sys", "BSD-3-Clause"), // rustdoc, rustc, cargo
    ("fuchsia-zircon", "BSD-3-Clause"),     // rustdoc, rustc, cargo (jobserver & tempdir)
    ("colored", "MPL-2.0"),                 // rustfmt
    ("ordslice", "Apache-2.0"),             // rls
    ("cloudabi", "BSD-2-Clause"),           // (rls -> crossbeam-channel 0.2 -> rand 0.5)
    ("ryu", "Apache-2.0 OR BSL-1.0"),       // rls/cargo/... (because of serde)
    ("bytesize", "Apache-2.0"),             // cargo
    ("im-rc", "MPL-2.0+"),                  // cargo
    ("adler32", "BSD-3-Clause AND Zlib"),   // cargo dep that isn't used
    ("constant_time_eq", "CC0-1.0"),        // rustfmt
    ("sized-chunks", "MPL-2.0+"),           // cargo via im-rc
    ("bitmaps", "MPL-2.0+"),                // cargo via im-rc
    // FIXME: this dependency violates the documentation comment above:
    ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target
    ("dunce", "CC0-1.0"),            // mdbook-linkcheck
    ("codespan-reporting", "Apache-2.0"), // mdbook-linkcheck
    ("codespan", "Apache-2.0"),      // mdbook-linkcheck
    ("crossbeam-channel", "MIT/Apache-2.0 AND BSD-2-Clause"), // cargo
];

/// Which crates to check against the whitelist?
const WHITELIST_CRATES: &[&str] = &["rustc", "rustc_codegen_llvm"];

/// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible.
const WHITELIST: &[&str] = &[
    "adler32",
    "aho-corasick",
    "annotate-snippets",
    "ansi_term",
    "arrayvec",
    "atty",
    "autocfg",
    "backtrace",
    "backtrace-sys",
    "bitflags",
    "byteorder",
    "c2-chacha",
    "cc",
    "cfg-if",
    "chalk-engine",
    "chalk-macros",
    "cloudabi",
    "cmake",
    "compiler_builtins",
    "crc32fast",
    "crossbeam-deque",
    "crossbeam-epoch",
    "crossbeam-queue",
    "crossbeam-utils",
    "datafrog",
    "dlmalloc",
    "either",
    "ena",
    "env_logger",
    "filetime",
    "flate2",
    "fortanix-sgx-abi",
    "fuchsia-zircon",
    "fuchsia-zircon-sys",
    "getopts",
    "getrandom",
    "hashbrown",
    "humantime",
    "indexmap",
    "itertools",
    "jobserver",
    "kernel32-sys",
    "lazy_static",
    "libc",
    "libz-sys",
    "lock_api",
    "log",
    "log_settings",
    "measureme",
    "memchr",
    "memmap",
    "memoffset",
    "miniz_oxide",
    "nodrop",
    "num_cpus",
    "parking_lot",
    "parking_lot_core",
    "pkg-config",
    "polonius-engine",
    "ppv-lite86",
    "proc-macro2",
    "punycode",
    "quick-error",
    "quote",
    "rand",
    "rand_chacha",
    "rand_core",
    "rand_hc",
    "rand_isaac",
    "rand_pcg",
    "rand_xorshift",
    "redox_syscall",
    "redox_termios",
    "regex",
    "regex-syntax",
    "remove_dir_all",
    "rustc-demangle",
    "rustc-hash",
    "rustc-rayon",
    "rustc-rayon-core",
    "rustc_version",
    "scoped-tls",
    "scopeguard",
    "semver",
    "semver-parser",
    "serde",
    "serde_derive",
    "smallvec",
    "stable_deref_trait",
    "syn",
    "synstructure",
    "tempfile",
    "termcolor",
    "termion",
    "termize",
    "thread_local",
    "ucd-util",
    "unicode-normalization",
    "unicode-script",
    "unicode-security",
    "unicode-width",
    "unicode-xid",
    "utf8-ranges",
    "vcpkg",
    "version_check",
    "wasi",
    "winapi",
    "winapi-build",
    "winapi-i686-pc-windows-gnu",
    "winapi-util",
    "winapi-x86_64-pc-windows-gnu",
    "wincolor",
    "hermit-abi",
];

/// Dependency checks.
///
/// `path` is path to the `src` directory, `cargo` is path to the cargo executable.
pub fn check(path: &Path, cargo: &Path, bad: &mut bool) {
    let mut cmd = cargo_metadata::MetadataCommand::new();
    cmd.cargo_path(cargo)
        .manifest_path(path.parent().unwrap().join("Cargo.toml"))
        .features(cargo_metadata::CargoOpt::AllFeatures);
    let metadata = t!(cmd.exec());
    check_exceptions(&metadata, bad);
    check_whitelist(&metadata, bad);
    check_crate_duplicate(&metadata, bad);
}

/// Check that all licenses are in the valid list in `LICENSES`.
///
/// Packages listed in `EXCEPTIONS` are allowed for tools.
fn check_exceptions(metadata: &Metadata, bad: &mut bool) {
    // Validate the EXCEPTIONS list hasn't changed.
    for (name, license) in EXCEPTIONS {
        // Check that the package actually exists.
        if !metadata.packages.iter().any(|p| p.name == *name) {
            println!(
                "could not find exception package `{}`\n\
                Remove from EXCEPTIONS list if it is no longer used.",
                name
            );
            *bad = true;
        }
        // Check that the license hasn't changed.
        for pkg in metadata.packages.iter().filter(|p| p.name == *name) {
            if pkg.name == "fuchsia-cprng" {
                // This package doesn't declare a license expression. Manual
                // inspection of the license file is necessary, which appears
                // to be BSD-3-Clause.
                assert!(pkg.license.is_none());
                continue;
            }
            match &pkg.license {
                None => {
                    println!(
                        "dependency exception `{}` does not declare a license expression",
                        pkg.id
                    );
                    *bad = true;
                }
                Some(pkg_license) => {
                    if pkg_license.as_str() != *license {
                        println!("dependency exception `{}` license has changed", name);
                        println!("    previously `{}` now `{}`", license, pkg_license);
                        println!("    update EXCEPTIONS for the new license");
                        *bad = true;
                    }
                }
            }
        }
    }
    let exception_names: Vec<_> = EXCEPTIONS.iter().map(|(name, _license)| *name).collect();
    // Check if any package does not have a valid license.
    for pkg in &metadata.packages {
        if pkg.source.is_none() {
            // No need to check local packages.
            continue;
        }
        if exception_names.contains(&pkg.name.as_str()) {
            continue;
        }
        let license = match &pkg.license {
            Some(license) => license,
            None => {
                println!("dependency `{}` does not define a license expression", pkg.id,);
                *bad = true;
                continue;
            }
        };
        if !LICENSES.contains(&license.as_str()) {
            println!("invalid license `{}` in `{}`", license, pkg.id);
            *bad = true;
        }
    }
}

/// Checks the dependency of `WHITELIST_CRATES` at the given path. Changes `bad` to `true` if a
/// check failed.
///
/// Specifically, this checks that the dependencies are on the `WHITELIST`.
fn check_whitelist(metadata: &Metadata, bad: &mut bool) {
    // Check that the WHITELIST does not have unused entries.
    for name in WHITELIST {
        if !metadata.packages.iter().any(|p| p.name == *name) {
            println!(
                "could not find whitelisted package `{}`\n\
                Remove from WHITELIST list if it is no longer used.",
                name
            );
            *bad = true;
        }
    }
    // Get the whitelist in a convenient form.
    let whitelist: HashSet<_> = WHITELIST.iter().cloned().collect();

    // Check dependencies.
    let mut visited = BTreeSet::new();
    let mut unapproved = BTreeSet::new();
    for &krate in WHITELIST_CRATES.iter() {
        let pkg = pkg_from_name(metadata, krate);
        let mut bad = check_crate_whitelist(&whitelist, metadata, &mut visited, pkg);
        unapproved.append(&mut bad);
    }

    if !unapproved.is_empty() {
        println!("Dependencies not on the whitelist:");
        for dep in unapproved {
            println!("* {}", dep);
        }
        *bad = true;
    }
}

/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
/// the whitelist. Returns a list of illegal dependencies.
fn check_crate_whitelist<'a>(
    whitelist: &'a HashSet<&'static str>,
    metadata: &'a Metadata,
    visited: &mut BTreeSet<&'a PackageId>,
    krate: &'a Package,
) -> BTreeSet<&'a PackageId> {
    // This will contain bad deps.
    let mut unapproved = BTreeSet::new();

    // Check if we have already visited this crate.
    if visited.contains(&krate.id) {
        return unapproved;
    }

    visited.insert(&krate.id);

    // If this path is in-tree, we don't require it to be on the whitelist.
    if krate.source.is_some() {
        // If this dependency is not on `WHITELIST`, add to bad set.
        if !whitelist.contains(krate.name.as_str()) {
            unapproved.insert(&krate.id);
        }
    }

    // Do a DFS in the crate graph.
    let to_check = deps_of(metadata, &krate.id);

    for dep in to_check {
        let mut bad = check_crate_whitelist(whitelist, metadata, visited, dep);
        unapproved.append(&mut bad);
    }

    unapproved
}

/// Prevents multiple versions of some expensive crates.
fn check_crate_duplicate(metadata: &Metadata, bad: &mut bool) {
    const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[
        // These two crates take quite a long time to build, so don't allow two versions of them
        // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times
        // under control.
        "cargo",
        "rustc-ap-syntax",
    ];

    for &name in FORBIDDEN_TO_HAVE_DUPLICATES {
        let matches: Vec<_> = metadata.packages.iter().filter(|pkg| pkg.name == name).collect();
        match matches.len() {
            0 => {
                println!(
                    "crate `{}` is missing, update `check_crate_duplicate` \
                    if it is no longer used",
                    name
                );
                *bad = true;
            }
            1 => {}
            _ => {
                println!(
                    "crate `{}` is duplicated in `Cargo.lock`, \
                    it is too expensive to build multiple times, \
                    so make sure only one version appears across all dependencies",
                    name
                );
                for pkg in matches {
                    println!("  * {}", pkg.id);
                }
                *bad = true;
            }
        }
    }
}

/// Returns a list of dependencies for the given package.
fn deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package> {
    let node = metadata
        .resolve
        .as_ref()
        .unwrap()
        .nodes
        .iter()
        .find(|n| &n.id == pkg_id)
        .unwrap_or_else(|| panic!("could not find `{}` in resolve", pkg_id));
    node.deps
        .iter()
        .map(|dep| {
            metadata.packages.iter().find(|pkg| pkg.id == dep.pkg).unwrap_or_else(|| {
                panic!("could not find dep `{}` for pkg `{}` in resolve", dep.pkg, pkg_id)
            })
        })
        .collect()
}

/// Finds a package with the given name.
fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package {
    let mut i = metadata.packages.iter().filter(|p| p.name == name);
    let result =
        i.next().unwrap_or_else(|| panic!("could not find package `{}` in package list", name));
    assert!(i.next().is_none(), "more than one package found for `{}`", name);
    result
}
<|endoftext|>


<commit_before>use libc;
use std;
use std::ptr;
use std::rc::Rc;
use std::str;

use handle::{self, RsvgHandle};
use load::rsvg_load_new_node;
use node::{node_new, Node, NodeType};
use property_bag::PropertyBag;
use structure::NodeSvg;
use text::NodeChars;
use tree::{RsvgTree, Tree};
use util::utf8_cstr;

/// A trait for processing a certain kind of XML subtree
///
/// In the "normal" state of processing, an `XmlHandler` may create an RsvgNode
/// for each SVG element it finds, and create NodeChars inside those nodes when it
/// encounters character data.
///
/// There may be other, special contexts for different subtrees, for example,
/// for the `<style>` element.
trait XmlHandler {
    /// Called when the XML parser sees the beginning of an element
    fn start_element(
        &self,
        parent: Option<&Rc<Node>>,
        handle: *mut RsvgHandle,
        name: &str,
        pbag: &PropertyBag,
    ) -> Box<XmlHandler>;

    /// Called when the XML parser sees the end of an element.
    fn end_element(&self, handle: *mut RsvgHandle, name: &str) -> Rc<Node>;

    /// Called when the XML parser sees character data or CDATA
    fn characters(&self, text: &str);

    fn get_node(&self) -> Rc<Node>;
}

struct NodeCreationContext {
    node: Option<Rc<Node>>,
}

impl XmlHandler for NodeCreationContext {
    fn start_element(
        &self,
        parent: Option<&Rc<Node>>,
        handle: *mut RsvgHandle,
        name: &str,
        pbag: &PropertyBag,
    ) -> Box<XmlHandler> {
        if name == "style" {
            unimplemented!();
        } else {
            let node = self.create_node(parent, handle, name, pbag);

            Box::new(NodeCreationContext { node: Some(node) })
        }
    }

    fn end_element(&self, handle: *mut RsvgHandle, _name: &str) -> Rc<Node> {
        let node = self.node.as_ref().unwrap().clone();

        // The "svg" node is special; it parses its style attributes
        // here, not during element creation.
        if node.get_type() == NodeType::Svg {
            node.with_impl(|svg: &NodeSvg| {
                svg.parse_style_attributes(&node, handle);
            });
        }

        node
    }

    fn characters(&self, text: &str) {
        let node = self.node.as_ref().unwrap();

        if text.len() == 0 {
            return;
        }

        if node.accept_chars() {
            let chars_node = if let Some(child) = node.find_last_chars_child() {
                child
            } else {
                let child = node_new(
                    NodeType::Chars,
                    Some(&node),
                    None,
                    None,
                    Box::new(NodeChars::new()),
                );
                node.add_child(&child);
                child
            };

            chars_node.with_impl(|chars: &NodeChars| {
                chars.append(text);
            });
        }
    }

    fn get_node(&self) -> Rc<Node> {
        self.node.as_ref().unwrap().clone()
    }
}

impl NodeCreationContext {
    fn empty() -> NodeCreationContext {
        NodeCreationContext { node: None }
    }

    fn create_node(
        &self,
        parent: Option<&Rc<Node>>,
        handle: *const RsvgHandle,
        name: &str,
        pbag: &PropertyBag,
    ) -> Rc<Node> {
        let mut defs = handle::get_defs(handle);

        let new_node = rsvg_load_new_node(name, parent, pbag, &mut defs);

        if let Some(parent) = parent {
            parent.add_child(&new_node);
        }

        new_node.set_atts(&new_node, handle, pbag);

        // The "svg" node is special; it will parse its style attributes
        // until the end, in standard_element_end().
        if new_node.get_type() != NodeType::Svg {
            new_node.parse_style_attributes(handle, name, pbag);
        }

        new_node.set_overridden_properties();

        new_node
    }
}

/// A concrete parsing context for a surrounding `element_name` and its XML event handlers
struct Context {
    element_name: String,
    handler: Box<XmlHandler>,
}

// A *const RsvgXmlState is just the type that we export to C
pub enum RsvgXmlState {}

/// Holds the state used for XML processing
///
/// These methods are called when an XML event is parsed out of the XML stream: `start_element`,
/// `end_element`, `characters`.
///
/// When an element starts, we push a corresponding `Context` into the `context_stack`.  Within
/// that context, all XML events will be forwarded to it, and processed in one of the `XmlHandler`
/// trait objects. Normally the context refers to a `NodeCreationContext` implementation which is
/// what creates normal graphical elements.
///
/// When we get to a `<style>` element, we push a `StyleContext`, which processes its contents
/// specially.
struct XmlState {
    tree: Option<Box<Tree>>,

    context_stack: Vec<Context>,
}

impl XmlState {
    fn new() -> XmlState {
        XmlState {
            tree: None,
            context_stack: Vec::new(),
        }
    }

    pub fn set_root(&mut self, root: &Rc<Node>) {
        if self.tree.is_some() {
            panic!("The tree root has already been set");
        }

        self.tree = Some(Box::new(Tree::new(root)));
    }

    pub fn steal_tree(&mut self) -> Option<Box<Tree>> {
        self.tree.take()
    }

    pub fn start_element(&mut self, handle: *mut RsvgHandle, name: &str, pbag: &PropertyBag) {
        let next_context = if let Some(top) = self.context_stack.last() {
            top.handler
                .start_element(Some(&top.handler.get_node()), handle, name, pbag)
        } else {
            let default_context = NodeCreationContext::empty();

            default_context.start_element(None, handle, name, pbag)
        };

        let context = Context {
            element_name: name.to_string(),
            handler: next_context,
        };

        self.context_stack.push(context);
    }

    pub fn end_element(&mut self, handle: *mut RsvgHandle, name: &str) {
        if let Some(top) = self.context_stack.pop() {
            assert!(name == top.element_name);

            let node = top.handler.end_element(handle, name);

            if self.context_stack.is_empty() {
                self.set_root(&node);
            }
        } else {
            panic!("end_element: XML handler stack is empty!?");
        }
    }

    pub fn characters(&mut self, text: &str) {
        if let Some(top) = self.context_stack.last() {
            top.handler.characters(text);
        } else {
            panic!("characters: XML handler stack is empty!?");
        }
    }
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_new() -> *mut RsvgXmlState {
    Box::into_raw(Box::new(XmlState::new())) as *mut RsvgXmlState
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_free(xml: *mut RsvgXmlState) {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };
    unsafe {
        Box::from_raw(xml);
    }
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_steal_tree(xml: *mut RsvgXmlState) -> *mut RsvgTree {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };

    if let Some(tree) = xml.steal_tree() {
        Box::into_raw(tree) as *mut RsvgTree
    } else {
        ptr::null_mut()
    }
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_start_element(
    xml: *mut RsvgXmlState,
    handle: *mut RsvgHandle,
    name: *const libc::c_char,
    pbag: *const PropertyBag,
) {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };

    assert!(!name.is_null());
    let name = unsafe { utf8_cstr(name) };

    assert!(!pbag.is_null());
    let pbag = unsafe { &*pbag };

    xml.start_element(handle, name, pbag);
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_end_element(
    xml: *mut RsvgXmlState,
    handle: *mut RsvgHandle,
    name: *const libc::c_char,
) {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };

    assert!(!name.is_null());
    let name = unsafe { utf8_cstr(name) };

    xml.end_element(handle, name);
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_characters(
    xml: *mut RsvgXmlState,
    unterminated_text: *const libc::c_char,
    len: usize,
) {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };

    assert!(!unterminated_text.is_null());

    // libxml2 already validated the incoming string as UTF-8.  Note that
    // it is *not* nul-terminated; this is why we create a byte slice first.
    let bytes = unsafe { std::slice::from_raw_parts(unterminated_text as *const u8, len) };
    let utf8 = unsafe { str::from_utf8_unchecked(bytes) };

    xml.characters(utf8);
}
<commit_msg>Return Option from end_element() and get_node() in XmlHandler<commit_after>use libc;
use std;
use std::ptr;
use std::rc::Rc;
use std::str;

use handle::{self, RsvgHandle};
use load::rsvg_load_new_node;
use node::{node_new, Node, NodeType};
use property_bag::PropertyBag;
use structure::NodeSvg;
use text::NodeChars;
use tree::{RsvgTree, Tree};
use util::utf8_cstr;

/// A trait for processing a certain kind of XML subtree
///
/// In the "normal" state of processing, an `XmlHandler` may create an RsvgNode
/// for each SVG element it finds, and create NodeChars inside those nodes when it
/// encounters character data.
///
/// There may be other, special contexts for different subtrees, for example,
/// for the `<style>` element.
trait XmlHandler {
    /// Called when the XML parser sees the beginning of an element
    fn start_element(
        &self,
        parent: Option<&Rc<Node>>,
        handle: *mut RsvgHandle,
        name: &str,
        pbag: &PropertyBag,
    ) -> Box<XmlHandler>;

    /// Called when the XML parser sees the end of an element.
    fn end_element(&self, handle: *mut RsvgHandle, name: &str) -> Option<Rc<Node>>;

    /// Called when the XML parser sees character data or CDATA
    fn characters(&self, text: &str);

    fn get_node(&self) -> Option<Rc<Node>> {
        None
    }
}

struct NodeCreationContext {
    node: Option<Rc<Node>>,
}

impl XmlHandler for NodeCreationContext {
    fn start_element(
        &self,
        parent: Option<&Rc<Node>>,
        handle: *mut RsvgHandle,
        name: &str,
        pbag: &PropertyBag,
    ) -> Box<XmlHandler> {
        if name == "style" {
            unimplemented!();
        } else {
            let node = self.create_node(parent, handle, name, pbag);

            Box::new(NodeCreationContext { node: Some(node) })
        }
    }

    fn end_element(&self, handle: *mut RsvgHandle, _name: &str) -> Option<Rc<Node>> {
        let node = self.node.as_ref().unwrap().clone();

        // The "svg" node is special; it parses its style attributes
        // here, not during element creation.
        if node.get_type() == NodeType::Svg {
            node.with_impl(|svg: &NodeSvg| {
                svg.parse_style_attributes(&node, handle);
            });
        }

        Some(node)
    }

    fn characters(&self, text: &str) {
        let node = self.node.as_ref().unwrap();

        if text.len() == 0 {
            return;
        }

        if node.accept_chars() {
            let chars_node = if let Some(child) = node.find_last_chars_child() {
                child
            } else {
                let child = node_new(
                    NodeType::Chars,
                    Some(&node),
                    None,
                    None,
                    Box::new(NodeChars::new()),
                );
                node.add_child(&child);
                child
            };

            chars_node.with_impl(|chars: &NodeChars| {
                chars.append(text);
            });
        }
    }

    fn get_node(&self) -> Option<Rc<Node>> {
        Some(self.node.as_ref().unwrap().clone())
    }
}

impl NodeCreationContext {
    fn empty() -> NodeCreationContext {
        NodeCreationContext { node: None }
    }

    fn create_node(
        &self,
        parent: Option<&Rc<Node>>,
        handle: *mut RsvgHandle,
        name: &str,
        pbag: &PropertyBag,
    ) -> Rc<Node> {
        let mut defs = handle::get_defs(handle);

        let new_node = rsvg_load_new_node(name, parent, pbag, &mut defs);

        if let Some(parent) = parent {
            parent.add_child(&new_node);
        }

        new_node.set_atts(&new_node, handle, pbag);

        // The "svg" node is special; it will parse its style attributes
        // until the end, in standard_element_end().
        if new_node.get_type() != NodeType::Svg {
            new_node.parse_style_attributes(handle, name, pbag);
        }

        new_node.set_overridden_properties();

        new_node
    }
}

/// Handles the `<style>` element by parsing its character contents as CSS
struct StyleContext {}

impl XmlHandler for StyleContext {
    fn start_element(
        &self,
        parent: Option<&Rc<Node>>,
        handle: *mut RsvgHandle,
        name: &str,
        pbag: &PropertyBag,
    ) -> Box<XmlHandler> {
        Box::new(StyleContext {})
    }

    fn end_element(&self, handle: *mut RsvgHandle, _name: &str) -> Option<Rc<Node>> {
        unimplemented!();
    }

    fn characters(&self, text: &str) {
        unimplemented!();
    }
}

/// A concrete parsing context for a surrounding `element_name` and its XML event handlers
struct Context {
    element_name: String,
    handler: Box<XmlHandler>,
}

// A *const RsvgXmlState is just the type that we export to C
pub enum RsvgXmlState {}

/// Holds the state used for XML processing
///
/// These methods are called when an XML event is parsed out of the XML stream: `start_element`,
/// `end_element`, `characters`.
///
/// When an element starts, we push a corresponding `Context` into the `context_stack`.  Within
/// that context, all XML events will be forwarded to it, and processed in one of the `XmlHandler`
/// trait objects. Normally the context refers to a `NodeCreationContext` implementation which is
/// what creates normal graphical elements.
///
/// When we get to a `<style>` element, we push a `StyleContext`, which processes its contents
/// specially.
struct XmlState {
    tree: Option<Box<Tree>>,

    context_stack: Vec<Context>,
}

impl XmlState {
    fn new() -> XmlState {
        XmlState {
            tree: None,
            context_stack: Vec::new(),
        }
    }

    pub fn set_root(&mut self, root: &Rc<Node>) {
        if self.tree.is_some() {
            panic!("The tree root has already been set");
        }

        self.tree = Some(Box::new(Tree::new(root)));
    }

    pub fn steal_tree(&mut self) -> Option<Box<Tree>> {
        self.tree.take()
    }

    pub fn start_element(&mut self, handle: *mut RsvgHandle, name: &str, pbag: &PropertyBag) {
        let next_context = if let Some(top) = self.context_stack.last() {
            top.handler
                .start_element(top.handler.get_node().as_ref(), handle, name, pbag)
        } else {
            let default_context = NodeCreationContext::empty();

            default_context.start_element(None, handle, name, pbag)
        };

        let context = Context {
            element_name: name.to_string(),
            handler: next_context,
        };

        self.context_stack.push(context);
    }

    pub fn end_element(&mut self, handle: *mut RsvgHandle, name: &str) {
        if let Some(top) = self.context_stack.pop() {
            assert!(name == top.element_name);

            if let Some(node) = top.handler.end_element(handle, name) {
                if self.context_stack.is_empty() {
                    self.set_root(&node);
                }
            }
        } else {
            panic!("end_element: XML handler stack is empty!?");
        }
    }

    pub fn characters(&mut self, text: &str) {
        if let Some(top) = self.context_stack.last() {
            top.handler.characters(text);
        } else {
            panic!("characters: XML handler stack is empty!?");
        }
    }
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_new() -> *mut RsvgXmlState {
    Box::into_raw(Box::new(XmlState::new())) as *mut RsvgXmlState
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_free(xml: *mut RsvgXmlState) {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };
    unsafe {
        Box::from_raw(xml);
    }
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_steal_tree(xml: *mut RsvgXmlState) -> *mut RsvgTree {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };

    if let Some(tree) = xml.steal_tree() {
        Box::into_raw(tree) as *mut RsvgTree
    } else {
        ptr::null_mut()
    }
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_start_element(
    xml: *mut RsvgXmlState,
    handle: *mut RsvgHandle,
    name: *const libc::c_char,
    pbag: *const PropertyBag,
) {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };

    assert!(!name.is_null());
    let name = unsafe { utf8_cstr(name) };

    assert!(!pbag.is_null());
    let pbag = unsafe { &*pbag };

    xml.start_element(handle, name, pbag);
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_end_element(
    xml: *mut RsvgXmlState,
    handle: *mut RsvgHandle,
    name: *const libc::c_char,
) {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };

    assert!(!name.is_null());
    let name = unsafe { utf8_cstr(name) };

    xml.end_element(handle, name);
}

#[no_mangle]
pub extern "C" fn rsvg_xml_state_characters(
    xml: *mut RsvgXmlState,
    unterminated_text: *const libc::c_char,
    len: usize,
) {
    assert!(!xml.is_null());
    let xml = unsafe { &mut *(xml as *mut XmlState) };

    assert!(!unterminated_text.is_null());

    // libxml2 already validated the incoming string as UTF-8.  Note that
    // it is *not* nul-terminated; this is why we create a byte slice first.
    let bytes = unsafe { std::slice::from_raw_parts(unterminated_text as *const u8, len) };
    let utf8 = unsafe { str::from_utf8_unchecked(bytes) };

    xml.characters(utf8);
}
<|endoftext|>


<commit_before>// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#[cfg(feature = "virgl_renderer")]
use std::env;
#[cfg(feature = "virgl_renderer")]
use std::fs;
#[cfg(feature = "virgl_renderer")]
use std::path::Path;
#[cfg(feature = "virgl_renderer")]
use std::path::PathBuf;
#[cfg(feature = "virgl_renderer")]
use std::process::Command;

#[cfg(feature = "virgl_renderer")]
use anyhow::bail;
use anyhow::Result;

#[cfg(feature = "virgl_renderer")]
const MINIGBM_SRC: &str = "../third_party/minigbm";
#[cfg(feature = "virgl_renderer")]
const VIRGLRENDERER_SRC: &str = "../third_party/virglrenderer";

#[cfg(feature = "virgl_renderer")]
fn is_native_build() -> bool {
    env::var("HOST").unwrap() == env::var("TARGET").unwrap()
}

/// Returns the target triplet prefix for gcc commands. No prefix is required
/// for native builds.
#[cfg(feature = "virgl_renderer")]
fn get_cross_compile_prefix() -> String {
    if is_native_build() {
        return String::from("");
    }

    let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
    let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
    let env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
    return format!("{}-{}-{}-", arch, os, env);
}

/// For cross-compilation with meson, we need to pick a cross-file, which
/// live in /usr/local/share/meson/cross.
#[cfg(feature = "virgl_renderer")]
fn get_meson_cross_args() -> Vec<String> {
    if is_native_build() {
        Vec::new()
    } else {
        vec![
            "--cross-file".to_string(),
            env::var("CARGO_CFG_TARGET_ARCH").unwrap(),
        ]
    }
}

#[cfg(feature = "virgl_renderer")]
fn build_minigbm(out_dir: &Path) -> Result<()> {
    let lib_path = out_dir.join("libgbm.a");
    if lib_path.exists() {
        return Ok(());
    }

    if !Path::new(MINIGBM_SRC).join(".git").exists() {
        bail!(
            "{} source does not exist, did you forget to \
            `git submodule update --init`?",
            MINIGBM_SRC
        );
    }

    let make_flags = env::var("CARGO_MAKEFLAGS").unwrap();
    let status = Command::new("make")
        .env("MAKEFLAGS", make_flags)
        .env("CROSS_COMPILE", get_cross_compile_prefix())
        .arg(format!("OUT={}", out_dir.display()))
        .arg("CC_STATIC_LIBRARY(libminigbm.pie.a)")
        .current_dir(MINIGBM_SRC)
        .status()?;
    if !status.success() {
        bail!("make failed with status: {}", status);
    }

    // minigbm will be linked using the name gbm, make sure it can be found.
    fs::copy(out_dir.join("libminigbm.pie.a"), out_dir.join("libgbm.a"))?;
    Ok(())
}

#[cfg(feature = "virgl_renderer")]
fn build_virglrenderer(out_dir: &Path) -> Result<()> {
    let lib_path = out_dir.join("src/libvirglrenderer.a");
    if lib_path.exists() {
        return Ok(());
    }

    if !Path::new(VIRGLRENDERER_SRC).join(".git").exists() {
        bail!(
            "{} source does not exist, did you forget to \
            `git submodule update --init`?",
            VIRGLRENDERER_SRC
        );
    }

    let platforms = [
        "egl",
        #[cfg(feature = "x")]
        "glx",
    ];

    let minigbm_src_abs = PathBuf::from(MINIGBM_SRC).canonicalize()?;
    let status = Command::new("meson")
        .env("PKG_CONFIG_PATH", &minigbm_src_abs)
        .arg("setup")
        .arg(format!("-Dplatforms={}", platforms.join(",")))
        .arg("-Ddefault_library=static")
        .args(get_meson_cross_args())
        .arg(out_dir.as_os_str())
        .current_dir(VIRGLRENDERER_SRC)
        .status()?;
    if !status.success() {
        bail!("meson setup failed with status: {}", status);
    }

    // Add local minigbm paths to make sure virglrenderer can build against it.
    let mut cmd = Command::new("meson");
    cmd.env("CPATH", &minigbm_src_abs)
        .arg("compile")
        .arg("src/virglrenderer")
        .current_dir(out_dir);

    let status = cmd.status()?;
    if !status.success() {
        bail!("meson compile failed with status: {}", status);
    }
    Ok(())
}

#[cfg(feature = "virgl_renderer")]
fn virglrenderer() -> Result<()> {
    // System provided runtime dependencies.
    pkg_config::Config::new().probe("epoxy")?;
    pkg_config::Config::new().probe("libdrm")?;

    // Use virglrenderer package from the standard system location if available.
    if pkg_config::Config::new().probe("virglrenderer").is_ok() {
        return Ok(());
    }

    // Otherwise build from source.
    let out_dir = PathBuf::from(env::var("OUT_DIR")?);
    let minigbm_out = out_dir.join("minigbm");
    let virglrenderer_out = out_dir.join("virglrenderer");
    build_minigbm(&minigbm_out)?;
    build_virglrenderer(&virglrenderer_out)?;

    println!(
        "cargo:rustc-link-search={}/src",
        virglrenderer_out.display()
    );
    println!("cargo:rustc-link-search={}", minigbm_out.display());
    println!("cargo:rustc-link-lib=static=virglrenderer");
    println!("cargo:rustc-link-lib=static=gbm");
    Ok(())
}

#[cfg(feature = "gfxstream")]
fn gfxstream() -> Result<()> {
    let gfxstream_path = std::env::var("GFXSTREAM_PATH")?;
    println!("cargo:rustc-link-search={}", gfxstream_path);
    Ok(())
}

fn main() -> Result<()> {
    // Skip installing dependencies when generating documents.
    if std::env::var("CARGO_DOC").is_ok() {
        return Ok(());
    }

    #[cfg(feature = "virgl_renderer")]
    virglrenderer()?;
    #[cfg(feature = "gfxstream")]
    gfxstream()?;

    Ok(())
}
<commit_msg>rutabaga_gfx: add virglrenderer deps later<commit_after>// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#[cfg(feature = "virgl_renderer")]
use std::env;
#[cfg(feature = "virgl_renderer")]
use std::fs;
#[cfg(feature = "virgl_renderer")]
use std::path::Path;
#[cfg(feature = "virgl_renderer")]
use std::path::PathBuf;
#[cfg(feature = "virgl_renderer")]
use std::process::Command;

#[cfg(feature = "virgl_renderer")]
use anyhow::bail;
use anyhow::Result;

#[cfg(feature = "virgl_renderer")]
const MINIGBM_SRC: &str = "../third_party/minigbm";
#[cfg(feature = "virgl_renderer")]
const VIRGLRENDERER_SRC: &str = "../third_party/virglrenderer";

#[cfg(feature = "virgl_renderer")]
fn is_native_build() -> bool {
    env::var("HOST").unwrap() == env::var("TARGET").unwrap()
}

/// Returns the target triplet prefix for gcc commands. No prefix is required
/// for native builds.
#[cfg(feature = "virgl_renderer")]
fn get_cross_compile_prefix() -> String {
    if is_native_build() {
        return String::from("");
    }

    let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
    let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
    let env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
    return format!("{}-{}-{}-", arch, os, env);
}

/// For cross-compilation with meson, we need to pick a cross-file, which
/// live in /usr/local/share/meson/cross.
#[cfg(feature = "virgl_renderer")]
fn get_meson_cross_args() -> Vec<String> {
    if is_native_build() {
        Vec::new()
    } else {
        vec![
            "--cross-file".to_string(),
            env::var("CARGO_CFG_TARGET_ARCH").unwrap(),
        ]
    }
}

#[cfg(feature = "virgl_renderer")]
fn build_minigbm(out_dir: &Path) -> Result<()> {
    let lib_path = out_dir.join("libgbm.a");
    if lib_path.exists() {
        return Ok(());
    }

    if !Path::new(MINIGBM_SRC).join(".git").exists() {
        bail!(
            "{} source does not exist, did you forget to \
            `git submodule update --init`?",
            MINIGBM_SRC
        );
    }

    let make_flags = env::var("CARGO_MAKEFLAGS").unwrap();
    let status = Command::new("make")
        .env("MAKEFLAGS", make_flags)
        .env("CROSS_COMPILE", get_cross_compile_prefix())
        .arg(format!("OUT={}", out_dir.display()))
        .arg("CC_STATIC_LIBRARY(libminigbm.pie.a)")
        .current_dir(MINIGBM_SRC)
        .status()?;
    if !status.success() {
        bail!("make failed with status: {}", status);
    }

    // minigbm will be linked using the name gbm, make sure it can be found.
    fs::copy(out_dir.join("libminigbm.pie.a"), out_dir.join("libgbm.a"))?;
    Ok(())
}

#[cfg(feature = "virgl_renderer")]
fn build_virglrenderer(out_dir: &Path) -> Result<()> {
    let lib_path = out_dir.join("src/libvirglrenderer.a");
    if lib_path.exists() {
        return Ok(());
    }

    if !Path::new(VIRGLRENDERER_SRC).join(".git").exists() {
        bail!(
            "{} source does not exist, did you forget to \
            `git submodule update --init`?",
            VIRGLRENDERER_SRC
        );
    }

    let platforms = [
        "egl",
        #[cfg(feature = "x")]
        "glx",
    ];

    let minigbm_src_abs = PathBuf::from(MINIGBM_SRC).canonicalize()?;
    let status = Command::new("meson")
        .env("PKG_CONFIG_PATH", &minigbm_src_abs)
        .arg("setup")
        .arg(format!("-Dplatforms={}", platforms.join(",")))
        .arg("-Ddefault_library=static")
        .args(get_meson_cross_args())
        .arg(out_dir.as_os_str())
        .current_dir(VIRGLRENDERER_SRC)
        .status()?;
    if !status.success() {
        bail!("meson setup failed with status: {}", status);
    }

    // Add local minigbm paths to make sure virglrenderer can build against it.
    let mut cmd = Command::new("meson");
    cmd.env("CPATH", &minigbm_src_abs)
        .arg("compile")
        .arg("src/virglrenderer")
        .current_dir(out_dir);

    let status = cmd.status()?;
    if !status.success() {
        bail!("meson compile failed with status: {}", status);
    }
    Ok(())
}

#[cfg(feature = "virgl_renderer")]
fn virglrenderer_deps() -> Result<()> {
    // System provided runtime dependencies.
    pkg_config::Config::new().probe("epoxy")?;
    pkg_config::Config::new().probe("libdrm")?;
    Ok(())
}

#[cfg(feature = "virgl_renderer")]
fn virglrenderer() -> Result<()> {
    // Use virglrenderer package from the standard system location if available.
    if pkg_config::Config::new().probe("virglrenderer").is_ok() {
        virglrenderer_deps()?;
        return Ok(());
    }

    // Otherwise build from source.
    let out_dir = PathBuf::from(env::var("OUT_DIR")?);
    let minigbm_out = out_dir.join("minigbm");
    let virglrenderer_out = out_dir.join("virglrenderer");
    build_minigbm(&minigbm_out)?;
    build_virglrenderer(&virglrenderer_out)?;

    println!(
        "cargo:rustc-link-search={}/src",
        virglrenderer_out.display()
    );
    println!("cargo:rustc-link-search={}", minigbm_out.display());
    println!("cargo:rustc-link-lib=static=virglrenderer");
    println!("cargo:rustc-link-lib=static=gbm");

    virglrenderer_deps()?;

    Ok(())
}

#[cfg(feature = "gfxstream")]
fn gfxstream() -> Result<()> {
    let gfxstream_path = std::env::var("GFXSTREAM_PATH")?;
    println!("cargo:rustc-link-search={}", gfxstream_path);
    Ok(())
}

fn main() -> Result<()> {
    // Skip installing dependencies when generating documents.
    if std::env::var("CARGO_DOC").is_ok() {
        return Ok(());
    }

    #[cfg(feature = "virgl_renderer")]
    virglrenderer()?;
    #[cfg(feature = "gfxstream")]
    gfxstream()?;

    Ok(())
}
<|endoftext|>


<commit_before>use std::str;
use nom::{self, is_alphanumeric, multispace};

use super::Error;

#[derive(Debug)]
enum Expr {
  Token(String),
  Array(Vec<Expr>),
}

#[inline]
fn is_tokenchar(c: u8) -> bool {
  is_alphanumeric(c) || c == '+' as u8 || c == '-' as u8 || c == '*' as u8 || c == '/' as u8 ||
  c == '=' as u8 || c == '!' as u8
}

named!(tokenchar, take_while_s!(is_tokenchar));

named!(token<&str>, map_res!(call!(tokenchar), str::from_utf8));

named!(array< Vec<Expr> >,
  delimited!(
    tag!("("),
    chain!(e:separated_list!(multispace, expr) ~ opt!(multispace), ||{ e }),
    tag!(")")
  )
);

named!(expr<Expr>,
  alt!(
      array => { |v| Expr::Array(v)               }
    | token => { |s| Expr::Token(String::from(s)) }
  )
);

#[derive(Debug)]
pub enum Ast {
  Nil,
  Symbol(String),
  Number(i64),
  Step(Vec<Box<Ast>>),
  Set(String, Box<Ast>),
  Until(Box<Ast>, Box<Ast>),
  Print(Box<Ast>),
  Eq(Box<Ast>, Box<Ast>),
  Plus(Box<Ast>, Box<Ast>),
}

impl Ast {
  pub fn from_str(s: &str) -> Result<Ast, Error> {
    let expr = match expr(s.trim().as_bytes()) {
      nom::IResult::Done(_, expr) => expr,
      _ => return Err(Error::NomParse),
    };
    expr_to_ast(&expr)
  }
}

fn expr_to_ast(expr: &Expr) -> Result<Ast, Error> {
  match *expr {
    Expr::Token(ref s) if s.trim() == "nil" => Ok(Ast::Nil),
    Expr::Token(ref s) => {
      Ok(s.parse::<i64>().map(Ast::Number).unwrap_or(Ast::Symbol((*s).clone())))
    }
    Expr::Array(ref arr) if arr.len() > 1 => {
      match arr[0] {
        Expr::Token(ref s) => {
          let s: &str = s;
          match s {
            "step" => {
              let mut lines = Vec::with_capacity(arr.len() - 1);
              for line in &arr[1..] {
                let line = expr_to_ast(line)?;
                lines.push(Box::new(line));
              }
              Ok(Ast::Step(lines))
            }
            "set" => {
              let symbol: Ast = arr.iter().nth(1).ok_or(Error::BuildAst).and_then(expr_to_ast)?;
              let value: Ast = arr.iter().nth(2).ok_or(Error::BuildAst).and_then(expr_to_ast)?;
              if let Ast::Symbol(s) = symbol {
                Ok(Ast::Set(s, Box::new(value)))
              } else {
                Err(Error::BuildAst)
              }
            }
            "until" => {
              let pred: Ast = arr.iter().nth(1).ok_or(Error::BuildAst).and_then(expr_to_ast)?;
              let expr: Ast = arr.iter().nth(2).ok_or(Error::BuildAst).and_then(expr_to_ast)?;
              Ok(Ast::Until(Box::new(pred), Box::new(expr)))
            }
            "print" => {
              let expr: Ast = arr.iter().nth(1).ok_or(Error::BuildAst).and_then(expr_to_ast)?;
              Ok(Ast::Print(Box::new(expr)))
            }
            "=" => {
              let lhs: Ast = arr.iter().nth(1).ok_or(Error::BuildAst).and_then(expr_to_ast)?;
              let rhs: Ast = arr.iter().nth(2).ok_or(Error::BuildAst).and_then(expr_to_ast)?;
              Ok(Ast::Eq(Box::new(lhs), Box::new(rhs)))
            }
            "+" => {
              let lhs: Ast = arr.iter().nth(1).ok_or(Error::BuildAst).and_then(expr_to_ast)?;
              let rhs: Ast = arr.iter().nth(2).ok_or(Error::BuildAst).and_then(expr_to_ast)?;
              Ok(Ast::Plus(Box::new(lhs), Box::new(rhs)))
            }
            _ => Err(Error::BuildAst),
          }
        }
        _ => Err(Error::BuildAst),
      }
    }
    _ => Err(Error::BuildAst),
  }
}
<commit_msg>rust: simplify ast & fix parser<commit_after>use std::str;
use nom::{self, is_alphanumeric, multispace};

use super::Error;

#[derive(Debug)]
enum Expr {
  Token(String),
  Array(Vec<Expr>),
}

#[inline]
fn is_tokenchar(c: u8) -> bool {
  is_alphanumeric(c) || c == '+' as u8 || c == '-' as u8 || c == '*' as u8 || c == '/' as u8 ||
  c == '=' as u8 || c == '!' as u8
}

named!(tokenchar, take_while_s!(is_tokenchar));

named!(token<&str>, map_res!(call!(tokenchar), str::from_utf8));

named!(array< Vec<Expr> >,
  delimited!(
    tag!("("),
    chain!(opt!(multispace) ~ e:separated_list!(multispace, expr) ~ opt!(multispace), ||{ e }),
    tag!(")")
  )
);

named!(expr<Expr>,
  alt!(
      array => { |v| Expr::Array(v)               }
    | token => { |s| Expr::Token(String::from(s)) }
  )
);

#[derive(Debug)]
pub enum Ast {
  Nil,
  Symbol(String),
  Number(i64),
  Command(String, Vec<Ast>),
}

impl Ast {
  pub fn from_str(s: &str) -> Result<Ast, Error> {
    let expr = match expr(s.trim().as_bytes()) {
      nom::IResult::Done(_, expr) => expr,
      _ => return Err(Error::NomParse),
    };
    expr_to_ast(&expr)
  }
}

fn expr_to_ast(expr: &Expr) -> Result<Ast, Error> {
  match *expr {
    Expr::Token(ref s) if s.trim() == "nil" => Ok(Ast::Nil),
    Expr::Token(ref s) => {
      Ok(s.parse::<i64>().map(Ast::Number).unwrap_or(Ast::Symbol((*s).clone())))
    }
    Expr::Array(ref arr) if arr.len() > 1 => {
      match arr[0] {
        Expr::Token(ref s) => {
          let mut args = Vec::with_capacity(arr.len() - 1);
          for arg in &arr[1..] {
            let arg = expr_to_ast(arg)?;
            args.push(arg);
          }
          Ok(Ast::Command(s.to_owned(), args))
        }
        _ => Err(Error::BuildAst),
      }
    }
    _ => Err(Error::BuildAst),
  }
}
<|endoftext|>


<commit_before>use state::State;
use context::BaseContext;

use self::message::Action as MessageAction;
use self::message::Command as MessageCommand;
pub use self::message::MessageActionHandler;

#[derive(Debug)]
pub enum Action {
    Message(MessageAction)
}

impl Action {
    pub fn execute(&self, state: &State, context: &BaseContext) -> ActionCommand {
        match *self {
            Action::Message(ref action) => action.execute(state, context)
        }
    }
}

#[derive(Debug)]
pub enum ActionCommand {
    Message(MessageCommand)
}

pub struct ActionHandlers {
    message_handler: Box<MessageActionHandler>
}

impl ActionHandlers {
    pub fn handle(&mut self, command: ActionCommand) {
        match command {
            ActionCommand::Message(message) => self.message_handler.handle(message)
        }
    }
}

pub mod message {
    use context::BaseContext;
    use state::State;
    use Message;
    use super::ActionCommand;

    #[derive(Debug)]
    pub struct Action;

    impl Action {
        pub fn execute(&self, _: &State, _: &BaseContext) -> ActionCommand {
            ActionCommand::Message(Command(Message::new("".to_string())))
        }
    }

    #[derive(Debug)]
    pub struct Command(Message);

    pub trait MessageActionHandler {
        fn handle(&mut self, command: Command);
    }
}
<commit_msg>ActionHandlers: create constructor<commit_after>use state::State;
use context::BaseContext;

use self::message::Action as MessageAction;
use self::message::Command as MessageCommand;
pub use self::message::MessageActionHandler;

#[derive(Debug)]
pub enum Action {
    Message(MessageAction)
}

impl Action {
    pub fn execute(&self, state: &State, context: &BaseContext) -> ActionCommand {
        match *self {
            Action::Message(ref action) => action.execute(state, context)
        }
    }
}

#[derive(Debug)]
pub enum ActionCommand {
    Message(MessageCommand)
}

pub struct ActionHandlers {
    message_handler: Box<MessageActionHandler>
}

impl ActionHandlers {
    pub fn new(message: Box<MessageActionHandler>) -> ActionHandlers {
        ActionHandlers {
            message_handler: message
        }
    }

    pub fn handle(&mut self, command: ActionCommand) {
        match command {
            ActionCommand::Message(message) => self.message_handler.handle(message)
        }
    }
}

pub mod message {
    use context::BaseContext;
    use state::State;
    use Message;
    use super::ActionCommand;

    #[derive(Debug)]
    pub struct Action;

    impl Action {
        pub fn execute(&self, _: &State, _: &BaseContext) -> ActionCommand {
            ActionCommand::Message(Command(Message::new("".to_string())))
        }
    }

    #[derive(Debug)]
    pub struct Command(Message);

    pub trait MessageActionHandler {
        fn handle(&mut self, command: Command);
    }
}
<|endoftext|>