<commit_before>use alloc::boxed::Box;

use core::cmp;

use common::event::{KeyEvent, MouseEvent};

use drivers::pio::*;

use schemes::KScheme;

/// PS2
pub struct Ps2 {
    /// The data
    data: Pio8,
    /// The command
    cmd: Pio8,
    /// Left shift?
    lshift: bool,
    /// Right shift?
    rshift: bool,
    /// Caps lock?
    caps_lock: bool,
    /// Caps lock toggle
    caps_lock_toggle: bool,
    /// The mouse packet
    mouse_packet: [u8; 4],
    /// Mouse packet index
    mouse_i: usize,
    /// Mouse point x
    mouse_x: isize,
    /// Mouse point y
    mouse_y: isize,
    /// Layout for keyboard
    /// Currently : 0 = EN / 1 = FR
    layout: usize,
}

impl Ps2 {
    /// Create new PS2 data
    pub fn new() -> Box<Self> {
        let mut module = box Ps2 {
            data: Pio8::new(0x60),
            cmd: Pio8::new(0x64),
            lshift: false,
            rshift: false,
            caps_lock: false,
            caps_lock_toggle: false,
            mouse_packet: [0; 4],
            mouse_i: 0,
            mouse_x: 0,
            mouse_y: 0,
            layout: 0,
        };

        unsafe {
            module.keyboard_init();
            module.mouse_init();
        }

        module
    }

    unsafe fn wait0(&self) {
        while (self.cmd.read() & 1) == 0 {}
    }

    unsafe fn wait1(&self) {
        while (self.cmd.read() & 2) == 2 {}
    }

    unsafe fn keyboard_init(&mut self) {
        while (self.cmd.read() & 0x1) == 1 {
            self.data.read();
        }

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let flags = (self.data.read() & 0b00110111) | 1 | 0b10000;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(flags);

        // Set Defaults
        self.wait1();
        self.data.write(0xF6);
        self.wait0();
        self.data.read();

        // Set LEDS
        self.wait1();
        self.data.write(0xED);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(0);
        self.wait0();
        self.data.read();

        // Set Scancode Map:
        self.wait1();
        self.data.write(0xF0);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(1);
        self.wait0();
        self.data.read();
    }

    /// Keyboard interrupt
    pub fn keyboard_interrupt(&mut self) -> Option<KeyEvent> {
        let scancode = unsafe { self.data.read() };

        if scancode == 0 {
            return None;
        } else if scancode == 0x2A {
            self.lshift = true;
        } else if scancode == 0xAA {
            self.lshift = false;
        } else if scancode == 0x36 {
            self.rshift = true;
        } else if scancode == 0xB6 {
            self.rshift = false;
        } else if scancode == 0x3A {
            if !self.caps_lock {
                self.caps_lock = true;
                self.caps_lock_toggle = true;
            } else {
                self.caps_lock_toggle = false;
            }
        } else if scancode == 0xBA {
            if self.caps_lock && !self.caps_lock_toggle {
                self.caps_lock = false;
            }
        }

        let shift;
        if self.caps_lock {
            shift = !(self.lshift || self.rshift);
        } else {
            shift = self.lshift || self.rshift;
        }

        return Some(KeyEvent {
            character: char_for_scancode(scancode & 0x7F, shift, self.layout),
            scancode: scancode & 0x7F,
            pressed: scancode < 0x80,
        });
    }

    unsafe fn mouse_cmd(&mut self, byte: u8) -> u8 {
        self.wait1();
        self.cmd.write(0xD4);
        self.wait1();
        self.data.write(byte);

        self.wait0();
        self.data.read()
    }

    /// Initialize mouse
    pub unsafe fn mouse_init(&mut self) {
        // The Init Dance
        self.wait1();
        self.cmd.write(0xA8);

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let status = self.data.read() | 2;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(status);

        // Set defaults
        self.mouse_cmd(0xF6);

        // Enable Streaming
        self.mouse_cmd(0xF4);
    }

    /// Mouse interrupt
    pub fn mouse_interrupt(&mut self) -> Option<MouseEvent> {
        let byte = unsafe { self.data.read() };
        if self.mouse_i == 0 {
            if byte & 0x8 == 0x8 {
                self.mouse_packet[0] = byte;
                self.mouse_i += 1;
            }
        } else if self.mouse_i == 1 {
            self.mouse_packet[1] = byte;

            self.mouse_i += 1;
        } else {
            self.mouse_packet[2] = byte;

            let left_button = (self.mouse_packet[0] & 1) == 1;
            let right_button = (self.mouse_packet[0] & 2) == 2;
            let middle_button = (self.mouse_packet[0] & 4) == 4;

            let x;
            if (self.mouse_packet[0] & 0x40) != 0x40 && self.mouse_packet[1] != 0 {
                x = self.mouse_packet[1] as isize -
                    (((self.mouse_packet[0] as isize) << 4) & 0x100);
            } else {
                x = 0;
            }

            let y;
            if (self.mouse_packet[0] & 0x80) != 0x80 && self.mouse_packet[2] != 0 {
                y = (((self.mouse_packet[0] as isize) << 3) & 0x100) -
                    self.mouse_packet[2] as isize;
            } else {
                y = 0;
            }

            unsafe {
                self.mouse_x = cmp::max(0,
                                        cmp::min((*::console).display.width as isize,
                                                 self.mouse_x + x));
                self.mouse_y = cmp::max(0,
                                        cmp::min((*::console).display.height as isize,
                                                 self.mouse_y + y));
            }

            self.mouse_i = 0;

            return Some(MouseEvent {
                x: self.mouse_x,
                y: self.mouse_y,
                left_button: left_button,
                right_button: right_button,
                middle_button: middle_button,
            });
        }

        return None;
    }

    /// Function to change the layout of the keyboard
    pub fn change_layout(&mut self, layout: usize) {
        self.layout = layout;
    }

}

impl KScheme for Ps2 {
    fn on_irq(&mut self, irq: u8) {
        if irq == 0x1 || irq == 0xC {
            self.on_poll();
        }
    }

    fn on_poll(&mut self) {
        loop {
            let status = unsafe { self.cmd.read() };
            if status & 0x21 == 1 {
                if let Some(key_event) = self.keyboard_interrupt() {
                    key_event.trigger();
                }
            } else if status & 0x21 == 0x21 {
                if let Some(mouse_event) = self.mouse_interrupt() {
                    mouse_event.trigger();
                }
            } else {
                break;
            }
        }
    }
}

/// Function to return the character associated with the scancode, and the layout
fn char_for_scancode(scancode: u8, shift: bool, layout: usize) -> char {
    let mut character = '\x00';
    if scancode < 58 {
        let characters: [char; 2] =
            match layout {
                0 => SCANCODES_EN[scancode as usize],
                1 => SCANCODES_FR[scancode as usize],
                _ => SCANCODES_EN[scancode as usize],
            };
        if shift {
            character = characters[1]
        }
        //Else...
        character = characters[0]
    }
    character
}

static SCANCODES_EN: [[char; 2]; 58] = [['\0', '\0'],
                                     ['\x1B', '\x1B'],
                                     ['1', '!'],
                                     ['2', '@'],
                                     ['3', '#'],
                                     ['4', '$'],
                                     ['5', '%'],
                                     ['6', '^'],
                                     ['7', '&'],
                                     ['8', '*'],
                                     ['9', '('],
                                     ['0', ')'],
                                     ['-', '_'],
                                     ['=', '+'],
                                     ['\0', '\0'],
                                     ['\t', '\t'],
                                     ['q', 'Q'],
                                     ['w', 'W'],
                                     ['e', 'E'],
                                     ['r', 'R'],
                                     ['t', 'T'],
                                     ['y', 'Y'],
                                     ['u', 'U'],
                                     ['i', 'I'],
                                     ['o', 'O'],
                                     ['p', 'P'],
                                     ['[', '{'],
                                     [']', '}'],
                                     ['\n', '\n'],
                                     ['\0', '\0'],
                                     ['a', 'A'],
                                     ['s', 'S'],
                                     ['d', 'D'],
                                     ['f', 'F'],
                                     ['g', 'G'],
                                     ['h', 'H'],
                                     ['j', 'J'],
                                     ['k', 'K'],
                                     ['l', 'L'],
                                     [';', ':'],
                                     ['\'', '"'],
                                     ['`', '~'],
                                     ['\0', '\0'],
                                     ['\\', '|'],
                                     ['z', 'Z'],
                                     ['x', 'X'],
                                     ['c', 'C'],
                                     ['v', 'V'],
                                     ['b', 'B'],
                                     ['n', 'N'],
                                     ['m', 'M'],
                                     [',', '<'],
                                     ['.', '>'],
                                     ['/', '?'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     [' ', ' ']];

 static SCANCODES_FR: [[char; 2]; 58] = [['\0', '\0'],
                                      ['\x1B', '\x1B'],
                                      ['1', '&'],
                                      ['2', 'é'],
                                      ['3', '"'],
                                      ['4', '\''],
                                      ['5', '('],
                                      ['6', '-'],
                                      ['7', 'è'],
                                      ['8', '_'],
                                      ['9', 'ç'],
                                      ['0', 'à'],
                                      ['-', ')'],
                                      ['=', '='],
                                      ['\0', '\0'],
                                      ['\t', '\t'],
                                      ['a', 'A'],
                                      ['z', 'Z'],
                                      ['e', 'E'],
                                      ['r', 'R'],
                                      ['t', 'T'],
                                      ['y', 'Y'],
                                      ['u', 'U'],
                                      ['i', 'I'],
                                      ['o', 'O'],
                                      ['p', 'P'],
                                      ['^', '¨'],
                                      ['$', '£'],
                                      ['\n', '\n'],
                                      ['\0', '\0'],
                                      ['q', 'Q'],
                                      ['s', 'S'],
                                      ['d', 'D'],
                                      ['f', 'F'],
                                      ['g', 'G'],
                                      ['h', 'H'],
                                      ['j', 'J'],
                                      ['k', 'K'],
                                      ['l', 'L'],
                                      ['m', 'M'],
                                      ['ù', '%'],
                                      ['*', 'µ'],
                                      ['\0', '\0'],
                                      ['<', '>'],
                                      ['w', 'W'],
                                      ['x', 'X'],
                                      ['c', 'C'],
                                      ['v', 'V'],
                                      ['b', 'B'],
                                      ['n', 'N'],
                                      [',', '?'],
                                      [';', '.'],
                                      [':', '/'],
                                      ['!', '§'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      [' ', ' ']];
<commit_msg>layout module added as field of ps2<commit_after>use alloc::boxed::Box;

use core::cmp;

use common::event::{KeyEvent, MouseEvent};

use drivers::pio::*;

use schemes::KScheme;

use drivers::kb_layouts::layouts;

/// PS2
pub struct Ps2 {
    /// The data
    data: Pio8,
    /// The command
    cmd: Pio8,
    /// Left shift?
    lshift: bool,
    /// Right shift?
    rshift: bool,
    /// Caps lock?
    caps_lock: bool,
    /// Caps lock toggle
    caps_lock_toggle: bool,
    /// The mouse packet
    mouse_packet: [u8; 4],
    /// Mouse packet index
    mouse_i: usize,
    /// Mouse point x
    mouse_x: isize,
    /// Mouse point y
    mouse_y: isize,
    /// Layout for keyboard
    /// Currently : 0 = EN / 1 = FR
    layout: usize,
}

impl Ps2 {
    /// Create new PS2 data
    pub fn new() -> Box<Self> {
        let mut module = box Ps2 {
            data: Pio8::new(0x60),
            cmd: Pio8::new(0x64),
            lshift: false,
            rshift: false,
            caps_lock: false,
            caps_lock_toggle: false,
            mouse_packet: [0; 4],
            mouse_i: 0,
            mouse_x: 0,
            mouse_y: 0,
            layout: 0,
        };

        unsafe {
            module.keyboard_init();
            module.mouse_init();
        }

        module
    }

    unsafe fn wait0(&self) {
        while (self.cmd.read() & 1) == 0 {}
    }

    unsafe fn wait1(&self) {
        while (self.cmd.read() & 2) == 2 {}
    }

    unsafe fn keyboard_init(&mut self) {
        while (self.cmd.read() & 0x1) == 1 {
            self.data.read();
        }

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let flags = (self.data.read() & 0b00110111) | 1 | 0b10000;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(flags);

        // Set Defaults
        self.wait1();
        self.data.write(0xF6);
        self.wait0();
        self.data.read();

        // Set LEDS
        self.wait1();
        self.data.write(0xED);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(0);
        self.wait0();
        self.data.read();

        // Set Scancode Map:
        self.wait1();
        self.data.write(0xF0);
        self.wait0();
        self.data.read();

        self.wait1();
        self.data.write(1);
        self.wait0();
        self.data.read();
    }

    /// Keyboard interrupt
    pub fn keyboard_interrupt(&mut self) -> Option<KeyEvent> {
        let scancode = unsafe { self.data.read() };

        if scancode == 0 {
            return None;
        } else if scancode == 0x2A {
            self.lshift = true;
        } else if scancode == 0xAA {
            self.lshift = false;
        } else if scancode == 0x36 {
            self.rshift = true;
        } else if scancode == 0xB6 {
            self.rshift = false;
        } else if scancode == 0x3A {
            if !self.caps_lock {
                self.caps_lock = true;
                self.caps_lock_toggle = true;
            } else {
                self.caps_lock_toggle = false;
            }
        } else if scancode == 0xBA {
            if self.caps_lock && !self.caps_lock_toggle {
                self.caps_lock = false;
            }
        }

        let shift;
        if self.caps_lock {
            shift = !(self.lshift || self.rshift);
        } else {
            shift = self.lshift || self.rshift;
        }

        return Some(KeyEvent {
            character: char_for_scancode(scancode & 0x7F, shift, self.layout),
            scancode: scancode & 0x7F,
            pressed: scancode < 0x80,
        });
    }

    unsafe fn mouse_cmd(&mut self, byte: u8) -> u8 {
        self.wait1();
        self.cmd.write(0xD4);
        self.wait1();
        self.data.write(byte);

        self.wait0();
        self.data.read()
    }

    /// Initialize mouse
    pub unsafe fn mouse_init(&mut self) {
        // The Init Dance
        self.wait1();
        self.cmd.write(0xA8);

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let status = self.data.read() | 2;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(status);

        // Set defaults
        self.mouse_cmd(0xF6);

        // Enable Streaming
        self.mouse_cmd(0xF4);
    }

    /// Mouse interrupt
    pub fn mouse_interrupt(&mut self) -> Option<MouseEvent> {
        let byte = unsafe { self.data.read() };
        if self.mouse_i == 0 {
            if byte & 0x8 == 0x8 {
                self.mouse_packet[0] = byte;
                self.mouse_i += 1;
            }
        } else if self.mouse_i == 1 {
            self.mouse_packet[1] = byte;

            self.mouse_i += 1;
        } else {
            self.mouse_packet[2] = byte;

            let left_button = (self.mouse_packet[0] & 1) == 1;
            let right_button = (self.mouse_packet[0] & 2) == 2;
            let middle_button = (self.mouse_packet[0] & 4) == 4;

            let x;
            if (self.mouse_packet[0] & 0x40) != 0x40 && self.mouse_packet[1] != 0 {
                x = self.mouse_packet[1] as isize -
                    (((self.mouse_packet[0] as isize) << 4) & 0x100);
            } else {
                x = 0;
            }

            let y;
            if (self.mouse_packet[0] & 0x80) != 0x80 && self.mouse_packet[2] != 0 {
                y = (((self.mouse_packet[0] as isize) << 3) & 0x100) -
                    self.mouse_packet[2] as isize;
            } else {
                y = 0;
            }

            unsafe {
                self.mouse_x = cmp::max(0,
                                        cmp::min((*::console).display.width as isize,
                                                 self.mouse_x + x));
                self.mouse_y = cmp::max(0,
                                        cmp::min((*::console).display.height as isize,
                                                 self.mouse_y + y));
            }

            self.mouse_i = 0;

            return Some(MouseEvent {
                x: self.mouse_x,
                y: self.mouse_y,
                left_button: left_button,
                right_button: right_button,
                middle_button: middle_button,
            });
        }

        return None;
    }

    /// Function to change the layout of the keyboard
    pub fn change_layout(&mut self, layout: usize) {
        self.layout = layout;
    }

}

impl KScheme for Ps2 {
    fn on_irq(&mut self, irq: u8) {
        if irq == 0x1 || irq == 0xC {
            self.on_poll();
        }
    }

    fn on_poll(&mut self) {
        loop {
            let status = unsafe { self.cmd.read() };
            if status & 0x21 == 1 {
                if let Some(key_event) = self.keyboard_interrupt() {
                    key_event.trigger();
                }
            } else if status & 0x21 == 0x21 {
                if let Some(mouse_event) = self.mouse_interrupt() {
                    mouse_event.trigger();
                }
            } else {
                break;
            }
        }
    }
}

/// Function to return the character associated with the scancode, and the layout
fn char_for_scancode(scancode: u8, shift: bool, layout: usize) -> char {
    let mut character = '\x00';
    if scancode < 58 {
        let characters: [char; 2] =
            match layout {
                0 => SCANCODES_EN[scancode as usize],
                1 => SCANCODES_FR[scancode as usize],
                _ => SCANCODES_EN[scancode as usize],
            };
        if shift {
            character = characters[1]
        }
        //Else...
        character = characters[0]
    }
    character
}

static SCANCODES_EN: [[char; 2]; 58] = [['\0', '\0'],
                                     ['\x1B', '\x1B'],
                                     ['1', '!'],
                                     ['2', '@'],
                                     ['3', '#'],
                                     ['4', '$'],
                                     ['5', '%'],
                                     ['6', '^'],
                                     ['7', '&'],
                                     ['8', '*'],
                                     ['9', '('],
                                     ['0', ')'],
                                     ['-', '_'],
                                     ['=', '+'],
                                     ['\0', '\0'],
                                     ['\t', '\t'],
                                     ['q', 'Q'],
                                     ['w', 'W'],
                                     ['e', 'E'],
                                     ['r', 'R'],
                                     ['t', 'T'],
                                     ['y', 'Y'],
                                     ['u', 'U'],
                                     ['i', 'I'],
                                     ['o', 'O'],
                                     ['p', 'P'],
                                     ['[', '{'],
                                     [']', '}'],
                                     ['\n', '\n'],
                                     ['\0', '\0'],
                                     ['a', 'A'],
                                     ['s', 'S'],
                                     ['d', 'D'],
                                     ['f', 'F'],
                                     ['g', 'G'],
                                     ['h', 'H'],
                                     ['j', 'J'],
                                     ['k', 'K'],
                                     ['l', 'L'],
                                     [';', ':'],
                                     ['\'', '"'],
                                     ['`', '~'],
                                     ['\0', '\0'],
                                     ['\\', '|'],
                                     ['z', 'Z'],
                                     ['x', 'X'],
                                     ['c', 'C'],
                                     ['v', 'V'],
                                     ['b', 'B'],
                                     ['n', 'N'],
                                     ['m', 'M'],
                                     [',', '<'],
                                     ['.', '>'],
                                     ['/', '?'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     ['\0', '\0'],
                                     [' ', ' ']];

 static SCANCODES_FR: [[char; 2]; 58] = [['\0', '\0'],
                                      ['\x1B', '\x1B'],
                                      ['1', '&'],
                                      ['2', 'é'],
                                      ['3', '"'],
                                      ['4', '\''],
                                      ['5', '('],
                                      ['6', '-'],
                                      ['7', 'è'],
                                      ['8', '_'],
                                      ['9', 'ç'],
                                      ['0', 'à'],
                                      ['-', ')'],
                                      ['=', '='],
                                      ['\0', '\0'],
                                      ['\t', '\t'],
                                      ['a', 'A'],
                                      ['z', 'Z'],
                                      ['e', 'E'],
                                      ['r', 'R'],
                                      ['t', 'T'],
                                      ['y', 'Y'],
                                      ['u', 'U'],
                                      ['i', 'I'],
                                      ['o', 'O'],
                                      ['p', 'P'],
                                      ['^', '¨'],
                                      ['$', '£'],
                                      ['\n', '\n'],
                                      ['\0', '\0'],
                                      ['q', 'Q'],
                                      ['s', 'S'],
                                      ['d', 'D'],
                                      ['f', 'F'],
                                      ['g', 'G'],
                                      ['h', 'H'],
                                      ['j', 'J'],
                                      ['k', 'K'],
                                      ['l', 'L'],
                                      ['m', 'M'],
                                      ['ù', '%'],
                                      ['*', 'µ'],
                                      ['\0', '\0'],
                                      ['<', '>'],
                                      ['w', 'W'],
                                      ['x', 'X'],
                                      ['c', 'C'],
                                      ['v', 'V'],
                                      ['b', 'B'],
                                      ['n', 'N'],
                                      [',', '?'],
                                      [';', '.'],
                                      [':', '/'],
                                      ['!', '§'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      ['\0', '\0'],
                                      [' ', ' ']];
<|endoftext|>


<commit_before>#[cfg(feature = "egl")]
use std::{cell::RefCell, rc::Rc, sync::mpsc::Sender};

#[cfg(feature = "udev")]
use smithay::backend::renderer::{Renderer, Texture};
#[cfg(feature = "udev")]
use smithay::reexports::nix::libc::dev_t;
#[cfg(feature = "udev")]
use std::collections::HashMap;

#[cfg(feature = "egl")]
use smithay::backend::egl::{display::EGLBufferReader, BufferAccessError as EGLBufferAccessError, EGLBuffer};
use smithay::{
    reexports::wayland_server::protocol::wl_buffer::WlBuffer,
    wayland::shm::{with_buffer_contents as shm_buffer_contents, BufferAccessError},
};

/// Utilities for working with `WlBuffer`s.
#[derive(Clone)]
pub struct BufferUtils {
    #[cfg(feature = "egl")]
    egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>,
    log: ::slog::Logger,
}

impl BufferUtils {
    /// Creates a new `BufferUtils`.
    #[cfg(feature = "egl")]
    pub fn new(egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>, log: ::slog::Logger) -> Self {
        Self {
            egl_buffer_reader,
            log,
        }
    }

    /// Creates a new `BufferUtils`.
    #[cfg(not(feature = "egl"))]
    pub fn new(log: ::slog::Logger) -> Self {
        Self { log }
    }

    /// Returns the dimensions of an image stored in the buffer.
    #[cfg(feature = "egl")]
    pub fn dimensions(&self, buffer: &WlBuffer) -> Option<(i32, i32)> {
        // Try to retrieve the EGL dimensions of this buffer, and, if that fails, the shm dimensions.
        self.egl_buffer_reader
            .borrow()
            .as_ref()
            .and_then(|display| display.egl_buffer_dimensions(buffer))
            .or_else(|| self.shm_buffer_dimensions(buffer).ok())
    }

    /// Returns the dimensions of an image stored in the buffer.
    #[cfg(not(feature = "egl"))]
    pub fn dimensions(&self, buffer: &WlBuffer) -> Option<(i32, i32)> {
        self.shm_buffer_dimensions(buffer).ok()
    }

    /// Returns the dimensions of an image stored in the shm buffer.
    fn shm_buffer_dimensions(&self, buffer: &WlBuffer) -> Result<(i32, i32), BufferAccessError> {
        shm_buffer_contents(buffer, |_, data| (data.width, data.height)).map_err(|err| {
            warn!(self.log, "Unable to load buffer contents"; "err" => format!("{:?}", err));
            err
        })
    }

    #[cfg(feature = "egl")]
    pub fn load_buffer<T>(&self, buffer: WlBuffer) -> Result<BufferTextures<T>, WlBuffer> {
        let result = if let Some(reader) = &self.egl_buffer_reader.borrow().as_ref() {
            reader.egl_buffer_contents(&buffer)
        } else {
            return Err(buffer);
        };

        let egl_buffer = match result {
            Ok(egl) => Some(egl),
            Err(EGLBufferAccessError::NotManaged(_)) => None,
            Err(err) => {
                error!(self.log, "EGL error"; "err" => format!("{:?}", err));
                return Err(buffer);
            }
        };

        Ok(BufferTextures {
            buffer,
            textures: HashMap::new(),
            callbacks: HashMap::new(),
            egl: egl_buffer, // I guess we need to keep this alive ?
        })
    }

    #[cfg(not(feature = "egl"))]
    pub fn load_buffer<T>(&self, buffer: WlBuffer) -> Result<BufferTextures<T>, WlBuffer> {
        Ok(BufferTextures {
            buffer,
            textures: HashMap::new(),
        })
    }
}

#[cfg(feature = "udev")]
pub struct BufferTextures<T> {
    buffer: WlBuffer,
    pub textures: HashMap<dev_t, T>,
    callbacks: HashMap<dev_t, Sender<T>>,
    #[cfg(feature = "egl")]
    egl: Option<EGLBuffer>,
}

#[cfg(feature = "udev")]
impl<T: Texture> BufferTextures<T> {
    #[cfg(feature = "egl")]
    pub fn load_texture<'a, R: Renderer<TextureId = T>>(
        &'a mut self,
        id: u64,
        renderer: &mut R,
        texture_destruction_callback: &Sender<T>,
    ) -> Result<&'a T, R::Error> {
        if self.textures.contains_key(&id) {
            return Ok(&self.textures[&id]);
        }

        if let Some(buffer) = self.egl.as_ref() {
            //EGL buffer
            let texture = renderer.import_egl(&buffer)?;
            if let Some(old_texture) = self.textures.insert(id, texture) {
                let _ = renderer.destroy_texture(old_texture);
            }
            self.callbacks.insert(id, texture_destruction_callback.clone());
            Ok(&self.textures[&id])
        } else {
            self.load_shm_texture(id, renderer, texture_destruction_callback)
        }
    }

    #[cfg(not(feature = "egl"))]
    pub fn load_texture<'a, R: Renderer<Texture = T>>(
        &'a mut self,
        id: u64,
        renderer: &mut R,
        texture_destruction_callback: &Sender<T>,
    ) -> Result<&'a T, R::Error> {
        if self.textures.contains_key(&id) {
            return Ok(&self.textures[&id]);
        }

        self.load_shm_texture(id, renderer, texture_destruction_callback)
    }

    fn load_shm_texture<'a, R: Renderer<TextureId = T>>(
        &'a mut self,
        id: u64,
        renderer: &mut R,
        texture_destruction_callback: &Sender<T>,
    ) -> Result<&'a T, R::Error> {
        let texture = renderer.import_shm(&self.buffer)?;

        if let Some(old_texture) = self.textures.insert(id, texture) {
            let _ = renderer.destroy_texture(old_texture)?;
        }
        self.callbacks.insert(id, texture_destruction_callback.clone());
        Ok(&self.textures[&id])
    }
}

#[cfg(feature = "udev")]
impl<T> Drop for BufferTextures<T> {
    fn drop(&mut self) {
        self.buffer.release();
        for (id, texture) in self.textures.drain() {
            self.callbacks.get(&id).unwrap().send(texture).unwrap();
        }
    }
}
<commit_msg>fix: Try shm-buffer imports, even if we do not have an egl-buffer reader...<commit_after>#[cfg(feature = "egl")]
use std::{cell::RefCell, rc::Rc, sync::mpsc::Sender};

#[cfg(feature = "udev")]
use smithay::backend::renderer::{Renderer, Texture};
#[cfg(feature = "udev")]
use smithay::reexports::nix::libc::dev_t;
#[cfg(feature = "udev")]
use std::collections::HashMap;

#[cfg(feature = "egl")]
use smithay::backend::egl::{display::EGLBufferReader, BufferAccessError as EGLBufferAccessError, EGLBuffer};
use smithay::{
    reexports::wayland_server::protocol::wl_buffer::WlBuffer,
    wayland::shm::{with_buffer_contents as shm_buffer_contents, BufferAccessError},
};

/// Utilities for working with `WlBuffer`s.
#[derive(Clone)]
pub struct BufferUtils {
    #[cfg(feature = "egl")]
    egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>,
    log: ::slog::Logger,
}

impl BufferUtils {
    /// Creates a new `BufferUtils`.
    #[cfg(feature = "egl")]
    pub fn new(egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>, log: ::slog::Logger) -> Self {
        Self {
            egl_buffer_reader,
            log,
        }
    }

    /// Creates a new `BufferUtils`.
    #[cfg(not(feature = "egl"))]
    pub fn new(log: ::slog::Logger) -> Self {
        Self { log }
    }

    /// Returns the dimensions of an image stored in the buffer.
    #[cfg(feature = "egl")]
    pub fn dimensions(&self, buffer: &WlBuffer) -> Option<(i32, i32)> {
        // Try to retrieve the EGL dimensions of this buffer, and, if that fails, the shm dimensions.
        self.egl_buffer_reader
            .borrow()
            .as_ref()
            .and_then(|display| display.egl_buffer_dimensions(buffer))
            .or_else(|| self.shm_buffer_dimensions(buffer).ok())
    }

    /// Returns the dimensions of an image stored in the buffer.
    #[cfg(not(feature = "egl"))]
    pub fn dimensions(&self, buffer: &WlBuffer) -> Option<(i32, i32)> {
        self.shm_buffer_dimensions(buffer).ok()
    }

    /// Returns the dimensions of an image stored in the shm buffer.
    fn shm_buffer_dimensions(&self, buffer: &WlBuffer) -> Result<(i32, i32), BufferAccessError> {
        shm_buffer_contents(buffer, |_, data| (data.width, data.height)).map_err(|err| {
            warn!(self.log, "Unable to load buffer contents"; "err" => format!("{:?}", err));
            err
        })
    }

    #[cfg(feature = "egl")]
    pub fn load_buffer<T>(&self, buffer: WlBuffer) -> Result<BufferTextures<T>, WlBuffer> {
        let egl_buffer = if let Some(reader) = &self.egl_buffer_reader.borrow().as_ref() {
            match reader.egl_buffer_contents(&buffer) {
                Ok(egl) => Some(egl),
                Err(EGLBufferAccessError::NotManaged(_)) => None,
                Err(err) => {
                    error!(self.log, "EGL error"; "err" => format!("{:?}", err));
                    return Err(buffer);
                }
            }
        } else { None };

        Ok(BufferTextures {
            buffer,
            textures: HashMap::new(),
            callbacks: HashMap::new(),
            egl: egl_buffer, // I guess we need to keep this alive ?
        })
    }

    #[cfg(not(feature = "egl"))]
    pub fn load_buffer<T>(&self, buffer: WlBuffer) -> Result<BufferTextures<T>, WlBuffer> {
        Ok(BufferTextures {
            buffer,
            textures: HashMap::new(),
        })
    }
}

#[cfg(feature = "udev")]
pub struct BufferTextures<T> {
    buffer: WlBuffer,
    pub textures: HashMap<dev_t, T>,
    callbacks: HashMap<dev_t, Sender<T>>,
    #[cfg(feature = "egl")]
    egl: Option<EGLBuffer>,
}

#[cfg(feature = "udev")]
impl<T: Texture> BufferTextures<T> {
    #[cfg(feature = "egl")]
    pub fn load_texture<'a, R: Renderer<TextureId = T>>(
        &'a mut self,
        id: u64,
        renderer: &mut R,
        texture_destruction_callback: &Sender<T>,
    ) -> Result<&'a T, R::Error> {
        if self.textures.contains_key(&id) {
            return Ok(&self.textures[&id]);
        }

        if let Some(buffer) = self.egl.as_ref() {
            //EGL buffer
            let texture = renderer.import_egl(&buffer)?;
            if let Some(old_texture) = self.textures.insert(id, texture) {
                let _ = renderer.destroy_texture(old_texture);
            }
            self.callbacks.insert(id, texture_destruction_callback.clone());
            Ok(&self.textures[&id])
        } else {
            self.load_shm_texture(id, renderer, texture_destruction_callback)
        }
    }

    #[cfg(not(feature = "egl"))]
    pub fn load_texture<'a, R: Renderer<Texture = T>>(
        &'a mut self,
        id: u64,
        renderer: &mut R,
        texture_destruction_callback: &Sender<T>,
    ) -> Result<&'a T, R::Error> {
        if self.textures.contains_key(&id) {
            return Ok(&self.textures[&id]);
        }

        self.load_shm_texture(id, renderer, texture_destruction_callback)
    }

    fn load_shm_texture<'a, R: Renderer<TextureId = T>>(
        &'a mut self,
        id: u64,
        renderer: &mut R,
        texture_destruction_callback: &Sender<T>,
    ) -> Result<&'a T, R::Error> {
        let texture = renderer.import_shm(&self.buffer)?;

        if let Some(old_texture) = self.textures.insert(id, texture) {
            let _ = renderer.destroy_texture(old_texture)?;
        }
        self.callbacks.insert(id, texture_destruction_callback.clone());
        Ok(&self.textures[&id])
    }
}

#[cfg(feature = "udev")]
impl<T> Drop for BufferTextures<T> {
    fn drop(&mut self) {
        self.buffer.release();
        for (id, texture) in self.textures.drain() {
            self.callbacks.get(&id).unwrap().send(texture).unwrap();
        }
    }
}
<|endoftext|>


<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::libc::funcs::posix88;
use std::io::signal::{Listener, Interrupt};
use std::{io, run, os, str, vec, clone};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use std::io::fs::File;
use extra::getopts;

struct Shell {
	cmd_prompt: ~str,
	history: ~[~str],
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            history: ~[],
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let writeRedirect = cmd_line.find_str(" > ");
            let readRedirect = cmd_line.find_str(" < ");
            if(writeRedirect == None && readRedirect == None) {
            	let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");
            	self.history.push(cmd_line.clone());
            	match cmd_line.slice_from(cmd_line.len() - 2) {
            		" &"    => { self.run_background(program, cmd_line.slice(0, cmd_line.len() - 2));
            			continue; }
                	_	=> { }
            	}
            	match program {
			""           =>  { continue; }
			"exit"       =>  { return; }
			"cd"	     =>  { self.run_cd(cmd_line); }
			"history"    =>  { self.run_history(); }
			_            =>  { self.run_cmdline(cmd_line); }
            	}
            }
            else if (readRedirect == None) {
            	let cmd1 = cmd_line.slice(0, writeRedirect.unwrap());
            	let cmd2 = cmd_line.slice_from(writeRedirect.unwrap()+3);
            	let program = cmd1.splitn(' ', 1).nth(0).expect("no program");
            	let args : ~[&str] = if (cmd1.splitn(' ', 1).nth(1) != None) {cmd1.splitn(' ', 1).nth(1).unwrap().split(' ').collect()} else {~[]};
            	let mut argsOwned : ~[~str] = ~[];
            	for i in range (0, args.len()) {
            		argsOwned.push(args[i].to_owned());
            	}
		let newStdOut = File::create(&Path::new(cmd2));
            	match newStdOut {
            		Some(mut x) => {
            			let process = run::Process::new(program, argsOwned, run::ProcessOptions::new());
            			let output = process.unwrap().finish_with_output();
            			x.write(output.output);
            		}
            		None => { println("shouldnt be here");}
            	}
            }
            else if (writeRedirect == None) {
            	let cmd1 = cmd_line.slice(0, readRedirect.unwrap());
            	let cmd2 = cmd_line.slice_from(readRedirect.unwrap()+3);
            	let program = cmd1.splitn(' ', 1).nth(0).expect("no program");
            	let args : ~[&str] = if (cmd1.splitn(' ', 1).nth(1) != None) {cmd1.splitn(' ', 1).nth(1).unwrap().split(' ').collect()} else {~[]};
            	let mut argsOwned : ~[~str] = ~[];
            	for i in range (0, args.len()) {
            		argsOwned.push(args[i].to_owned());
            	}
           	let path = &Path::new(cmd2);
            	if (path.exists()) {
		let input = File::open(path);
            		match input {
            			Some(mut x) => {
            				let inputBytes = x.read_to_end();
            				let process = run::Process::new(program, argsOwned, run::ProcessOptions::new());
            				match(process) {
            					Some(mut toWrite) => {
            						toWrite.input().write(inputBytes);
            						let output = toWrite.finish_with_output();
            						print!("{:s}", str::from_utf8(output.output));
            					}
            					None => {}
        				}
            			}
            			None => { println!("gash: {:s}: No such file or directory", cmd2);}
            		}
            	}
                else {
           		println!("gash: {:s}: No such file or directory", cmd2);
           	}
            }
        }
    }

	fn decompose_Cmdline (cmd_line: &str) -> ~[DecomposedCmd]{
		let mut decomposed = ~[];

		let pipe = cmd_line.find_str("|");
		match pipe {
			Some(index)	=> {
				let cmd1 = cmd_line.slice(0, index);
				let cmd2 = cmd_line.slice_from(index+1);
				decomposed = Shell::decompose_Cmdline(cmd1);
				decomposed = vec::append(decomposed, Shell::decompose_Cmdline(cmd2));
				return decomposed;
			}
			_		=> {
			}
		}

		let decomposedCmd = DecomposedCmd {
			cmd_line: ~"",
			program: ~"",
			args: ~[],
			background: false,
			inputFile: None,
			outputFile: None,
			pipeToNext: false,
		};

		let writeRedirect = cmd_line.find_str(">");
		let readRedirect = cmd_line.find_str("<");
		match (readRedirect, writeRedirect) {
			(Some(read), Some(write))	=> {}
			(Some(read), _)			=> {}
			(_, Some(write))		=> {}
			(_, _)				=> {}
		}

		decomposed
	}

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        if self.cmd_exists(program) {
            run::process_status(program, argv);
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn run_cd(&mut self, program: &str) {
        let mut argv: ~[~str] =
            program.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

    	let mut programs : ~str = ~"";
            if argv.len() > 1 {
                programs = argv.remove(1);
            }
    	os::change_dir(&Path::new(programs.clone()));
    }

    fn run_history(&mut self) {
        for c in range(0, self.history.len()) {
            println!("{:s}", self.history[c]);
        }
    }

    fn run_background(&mut self, program: &str, cmd_line: &str) {
		let (portSelf, chanSelf): (Port<~Shell>, Chan<~Shell>) = Chan::new();
		let (portProg, chanProg): (Port<~str>, Chan<~str>) = Chan::new();
		let (portLine, chanLine): (Port<~str>, Chan<~str>) = Chan::new();

		let mut sendShell = ~(Shell::new("gash > "));
		sendShell.history = self.history.clone();
		chanSelf.send(sendShell);
		chanProg.send(program.to_owned());
		chanLine.send(cmd_line.to_owned());

		do spawn {
		let program : ~str = portProg.recv();
		let cmd_line : ~str = portLine.recv();
		let mut selfV : ~Shell = portSelf.recv();
                match program {
             	   ~""           =>  { }
              	  ~"exit"       =>  { }
		  ~"cd"	     =>  { selfV.run_cd(cmd_line); }
                  ~"history"    =>  { selfV.run_history(); }
                  _            =>  { selfV.run_cmdline(cmd_line); }
                }
            };
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    let mut listener = Listener::new();
    listener.register(Interrupt);

    let (portSelf, chanSelf): (Port<Listener>, Chan<Listener>) = Chan::new();
    chanSelf.send(listener);

    do spawn{
        loop {
            let listener = portSelf.recv();
            match listener.port.recv() {
                Interrupt => { println!("Got Interrupt'ed");
                                unsafe { posix88::signal::kill(std::libc::getpid() , std::libc::SIGINT); }
                            }
                _ => (),
            }
        }
    };

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}

struct DecomposedCmd {
	cmd_line: ~str,
	program: ~str,
	args: ~[~str],
	background: bool,
	inputFile: Option<~str>,
	outputFile: Option<~str>,
	pipeToNext: bool,
}

impl clone::Clone for DecomposedCmd {
	fn clone(&self) -> DecomposedCmd {
		DecomposedCmd {
			cmd_line: self.cmd_line.clone(),
			program: self.program.clone(),
			args: self.args.clone(),
			background : self.background,
			inputFile: self.inputFile.clone(),
			outputFile: self.outputFile.clone(),
			pipeToNext: self.pipeToNext,
		}
	}
}
<commit_msg>Finished method that parses input cmd into the struct<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::libc::funcs::posix88;
use std::io::signal::{Listener, Interrupt};
use std::{io, run, os, str, vec, clone};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use std::io::fs::File;
use extra::getopts;

struct Shell {
	cmd_prompt: ~str,
	history: ~[~str],
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            history: ~[],
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
		let decomposed = Shell::decompose_Cmdline(cmd_line);
		for j in range(0, decomposed.len()) {
			decomposed[j].print();
		}
            let writeRedirect = cmd_line.find_str(" > ");
            let readRedirect = cmd_line.find_str(" < ");
            if(writeRedirect == None && readRedirect == None) {
            	let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");
            	self.history.push(cmd_line.clone());
            	match cmd_line.slice_from(cmd_line.len() - 2) {
            		" &"    => { self.run_background(program, cmd_line.slice(0, cmd_line.len() - 2));
            			continue; }
                	_	=> { }
            	}
            	match program {
			""           =>  { continue; }
			"exit"       =>  { return; }
			"cd"	     =>  { self.run_cd(cmd_line); }
			"history"    =>  { self.run_history(); }
			_            =>  { self.run_cmdline(cmd_line); }
            	}
            }
            else if (readRedirect == None) {
            	let cmd1 = cmd_line.slice(0, writeRedirect.unwrap());
            	let cmd2 = cmd_line.slice_from(writeRedirect.unwrap()+3);
            	let program = cmd1.splitn(' ', 1).nth(0).expect("no program");
            	let args : ~[&str] = if (cmd1.splitn(' ', 1).nth(1) != None) {cmd1.splitn(' ', 1).nth(1).unwrap().split(' ').collect()} else {~[]};
            	let mut argsOwned : ~[~str] = ~[];
            	for i in range (0, args.len()) {
            		argsOwned.push(args[i].to_owned());
            	}
		let newStdOut = File::create(&Path::new(cmd2));
            	match newStdOut {
            		Some(mut x) => {
            			let process = run::Process::new(program, argsOwned, run::ProcessOptions::new());
            			let output = process.unwrap().finish_with_output();
            			x.write(output.output);
            		}
            		None => { println("shouldnt be here");}
            	}
            }
            else if (writeRedirect == None) {
            	let cmd1 = cmd_line.slice(0, readRedirect.unwrap());
            	let cmd2 = cmd_line.slice_from(readRedirect.unwrap()+3);
            	let program = cmd1.splitn(' ', 1).nth(0).expect("no program");
            	let args : ~[&str] = if (cmd1.splitn(' ', 1).nth(1) != None) {cmd1.splitn(' ', 1).nth(1).unwrap().split(' ').collect()} else {~[]};
            	let mut argsOwned : ~[~str] = ~[];
            	for i in range (0, args.len()) {
            		argsOwned.push(args[i].to_owned());
            	}
           	let path = &Path::new(cmd2);
            	if (path.exists()) {
		let input = File::open(path);
            		match input {
            			Some(mut x) => {
            				let inputBytes = x.read_to_end();
            				let process = run::Process::new(program, argsOwned, run::ProcessOptions::new());
            				match(process) {
            					Some(mut toWrite) => {
            						toWrite.input().write(inputBytes);
            						let output = toWrite.finish_with_output();
            						print!("{:s}", str::from_utf8(output.output));
            					}
            					None => {}
        				}
            			}
            			None => { println!("gash: {:s}: No such file or directory", cmd2);}
            		}
            	}
                else {
           		println!("gash: {:s}: No such file or directory", cmd2);
           	}
            }
        }
    }

	fn decompose_Cmdline (cmd_line: &str) -> ~[DecomposedCmd]{
		let mut decomposed = ~[];
		let mut decomposedCmd = DecomposedCmd {
			cmd_line: ~"",
			program: ~"",
			args: ~[],
			background: false,
			inputFile: None,
			outputFile: None,
			pipeToNext: None,
			error: false,
		};

		let background = cmd_line.find_str("&");
		match background {
			Some(index)	=> {
				let cmd1 = cmd_line.slice(0, index).trim();
				let cmd2 = if(index < cmd_line.len()) {cmd_line.slice_from(index+1).trim()} else {""};
				decomposed = Shell::decompose_Cmdline(cmd1);
				decomposed[0].background = true;
				if(cmd2!="") {
					decomposed = vec::append(decomposed, Shell::decompose_Cmdline(cmd2));
				}
				return decomposed;
			}
			_		=> {
			}
		}

		let pipe = cmd_line.find_str("|");
		match pipe {
			Some(index)	=> {
				if(index==0 || index == cmd_line.len()-1) {
					println("Syntax error near '|'");
					decomposedCmd.error = true;
					decomposed.push(decomposedCmd);
					return decomposed;
				}
				let cmd1 = cmd_line.slice(0, index).trim();
				let cmd2 = cmd_line.slice_from(index+1).trim();
				decomposed = Shell::decompose_Cmdline(cmd1);
				decomposed[decomposed.len() - 1].pipeToNext = Some(~Shell::decompose_Cmdline(cmd2)[0]);
				return decomposed;
			}
			_		=> {
			}
		}

		let writeRedirect = cmd_line.find_str(">");
		let readRedirect = cmd_line.find_str("<");
		match (readRedirect, writeRedirect) {
			(Some(read), Some(write))	=> {
				if(read>write) {
					let cmd = cmd_line.slice(0, write).trim().to_owned();
					let output = cmd_line.slice(write+1, read).trim().to_owned();
					let input = cmd_line.slice_from(read+1).to_owned();
					decomposedCmd.outputFile = Some(output);
					decomposedCmd.inputFile = Some(input);
					decomposedCmd.cmd_line = cmd.clone();
					decomposedCmd.program = cmd_line.splitn(' ', 1).nth(0).expect("no program").to_owned();
					let mut args : ~[~str] = cmd.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
					args.remove(0);
				}
				else {
					let cmd = cmd_line.slice(0, read).trim().to_owned();
					let input = cmd_line.slice(read+1, write).trim().to_owned();
					let output = cmd_line.slice_from(write+1).trim().to_owned();
					decomposedCmd.inputFile = Some(input);
					decomposedCmd.outputFile = Some(output);
					decomposedCmd.cmd_line = cmd.clone();
					decomposedCmd.program = cmd_line.splitn(' ', 1).nth(0).expect("no program").to_owned();
					let mut args : ~[~str] = cmd.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
					args.remove(0);
					decomposedCmd.args = args;
				}
			}
			(Some(read), _)			=> {
				let cmd = cmd_line.slice(0, read).trim().to_owned();
				let input = cmd_line.slice_from(read+1).trim().to_owned();
				decomposedCmd.inputFile = Some(input);
				decomposedCmd.cmd_line = cmd.clone();
				decomposedCmd.program = cmd_line.splitn(' ', 1).nth(0).expect("no program").to_owned();
				let mut args : ~[~str] = cmd.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
				args.remove(0);
				decomposedCmd.args = args;
			}
			(_, Some(write))		=> {
				let cmd = cmd_line.slice(0, write).trim().to_owned();
				let output = cmd_line.slice_from(write+1).trim().to_owned();
				decomposedCmd.outputFile = Some(output);
				decomposedCmd.cmd_line = cmd.clone();
				decomposedCmd.program = cmd_line.splitn(' ', 1).nth(0).expect("no program").to_owned();
				let mut args : ~[~str] = cmd.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
				args.remove(0);
				decomposedCmd.args = args;
			}
			(_, _)				=> {
				decomposedCmd.cmd_line = cmd_line.to_owned();
				decomposedCmd.program = cmd_line.splitn(' ', 1).nth(0).expect("no program").to_owned();
				let mut args : ~[~str] = cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
				args.remove(0);
				decomposedCmd.args = args;
			}
		}

		decomposed.push(decomposedCmd);
		return decomposed;
	}

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        if self.cmd_exists(program) {
            run::process_status(program, argv);
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn run_cd(&mut self, program: &str) {
        let mut argv: ~[~str] =
            program.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

    	let mut programs : ~str = ~"";
            if argv.len() > 1 {
                programs = argv.remove(1);
            }
    	os::change_dir(&Path::new(programs.clone()));
    }

    fn run_history(&mut self) {
        for c in range(0, self.history.len()) {
            println!("{:s}", self.history[c]);
        }
    }

    fn run_background(&mut self, program: &str, cmd_line: &str) {
		let (portSelf, chanSelf): (Port<~Shell>, Chan<~Shell>) = Chan::new();
		let (portProg, chanProg): (Port<~str>, Chan<~str>) = Chan::new();
		let (portLine, chanLine): (Port<~str>, Chan<~str>) = Chan::new();

		let mut sendShell = ~(Shell::new("gash > "));
		sendShell.history = self.history.clone();
		chanSelf.send(sendShell);
		chanProg.send(program.to_owned());
		chanLine.send(cmd_line.to_owned());

		do spawn {
		let program : ~str = portProg.recv();
		let cmd_line : ~str = portLine.recv();
		let mut selfV : ~Shell = portSelf.recv();
                match program {
             	   ~""           =>  { }
              	  ~"exit"       =>  { }
		  ~"cd"	     =>  { selfV.run_cd(cmd_line); }
                  ~"history"    =>  { selfV.run_history(); }
                  _            =>  { selfV.run_cmdline(cmd_line); }
                }
            };
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    let mut listener = Listener::new();
    listener.register(Interrupt);

    let (portSelf, chanSelf): (Port<Listener>, Chan<Listener>) = Chan::new();
    chanSelf.send(listener);

    do spawn{
        loop {
            let listener = portSelf.recv();
            match listener.port.recv() {
                Interrupt => { println!("Got Interrupt'ed");
                                unsafe { posix88::signal::kill(std::libc::getpid() , std::libc::SIGINT); }
                            }
                _ => (),
            }
        }
    };

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}

struct DecomposedCmd {
	cmd_line: ~str,
	program: ~str,
	args: ~[~str],
	background: bool,
	inputFile: Option<~str>,
	outputFile: Option<~str>,
	pipeToNext: Option<~DecomposedCmd>,
	error: bool,
}

impl clone::Clone for DecomposedCmd {
	fn clone(&self) -> DecomposedCmd {
		DecomposedCmd {
			cmd_line: self.cmd_line.clone(),
			program: self.program.clone(),
			args: self.args.clone(),
			background : self.background,
			inputFile: self.inputFile.clone(),
			outputFile: self.outputFile.clone(),
			pipeToNext: self.pipeToNext.clone(),
			error: self.error,
		}
	}
}

impl DecomposedCmd {
	fn print(&self) {
		print!("cmd_line: {:s}\nprogram: {:s}\nargs:", self.cmd_line, self.program);
		if self.args.len() > 0 {
			for i in range(0, self.args.len()) {
				print!("\n\t{:s}", self.args[i]);
			}
		}
		println!("\nbackground: {:b}\ninputFile: {:s}\noutputFile: {:s}\nerror: {:b}", self.background,
			match self.clone().inputFile { Some(name) => {name} _ => {~""} }, match self.clone().outputFile { Some(name) => {name} _ => {~""} }, self.error);
		match self.clone().pipeToNext {
			Some(next) => {
				println("Pipe to:");
				next.print();
			}
			_ => {}
		}
	}
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use par_exec::{Executor, LocalContextBuilder, ExecutorNewError};

use super::Algorithm;
use super::super::pop::individual::{Individual, IndividualManager, IndividualManagerMut};
use super::super::pop::init::PopulationInit;
use super::super::pop::init::limited;
use super::super::set::{Set, SetManager, SetManagerMut};

// common policy
pub trait Policy {
    // individual config
    type Indiv: Individual;
    type IndivME: Send + 'static;
    type IndivM: IndividualManager<I = Self::Indiv, E = Self::IndivME>;

    // init population config
    type PopInitSE: Send + 'static;
    type PopInitS: Set<T = Self::Indiv, E = Self::PopInitSE> + Send + 'static;
    type PopInitSME: Send + 'static;
    type PopInitSM: SetManager<S = Self::PopInitS, E = Self::PopInitSME>;
}

pub struct LocalContext<P> where P: Policy {
    indiv_manager: P::IndivM,
    pop_init_set_manager: P::PopInitSM,
}

impl<P> SetManagerMut for LocalContext<P> where P: Policy {
    type SM = P::PopInitSM;

    fn set_manager_mut(&mut self) -> &mut Self::SM {
        &mut self.pop_init_set_manager
    }
}

impl<P> IndividualManagerMut for LocalContext<P> where P: Policy {
    type IM = P::IndivM;

    fn individual_manager_mut(&mut self) -> &mut Self::IM {
        &mut self.indiv_manager
    }
}

// algorithm policy
pub trait APolicy {
    type P: Policy;
    type LCBuilder: LocalContextBuilder<LC = LocalContext<Self::P>>;
    type Exec: Executor<LC = LocalContext<Self::P>>;
}

pub struct PopInitPolicy<AP>(PhantomData<AP>) where AP: APolicy;

impl<AP> limited::Policy for PopInitPolicy<AP> where AP: APolicy {
    type LocalContext = LocalContext<AP::P>;
    type Exec = AP::Exec;
    type Indiv = <AP::P as Policy>::Indiv;
    type IndivME = <AP::P as Policy>::IndivME;
    type IndivM = <AP::P as Policy>::IndivM;
    type PopE = <AP::P as Policy>::PopInitSE;
    type Pop = <AP::P as Policy>::PopInitS;
    type PopSME = <AP::P as Policy>::PopInitSME;
    type PopSM = <AP::P as Policy>::PopInitSM;
}

pub struct MuCommaLambda<AP> where AP: APolicy {
    lc_builder: AP::LCBuilder,
    pop_init: limited::LimitedPopulationInit<PopInitPolicy<AP>>,
}

impl<AP> MuCommaLambda<AP> where AP: APolicy {
    pub fn new(lc_builder: AP::LCBuilder, lambda: usize) -> MuCommaLambda<AP> {
        MuCommaLambda {
            lc_builder: lc_builder,
            pop_init: limited::LimitedPopulationInit::new(lambda),
        }
    }
}

pub enum Error<AP> where AP: APolicy {
    ExecutorStart(ExecutorNewError<<AP::Exec as Executor>::E, <AP::LCBuilder as LocalContextBuilder>::E>),
    PopulationInit(limited::Error<PopInitPolicy<AP>>),

    Dummy
}

impl<AP> Algorithm for MuCommaLambda<AP> where AP: APolicy {
    type Exec = AP::Exec;
    type Res = <AP::P as Policy>::Indiv;
    type Err = Error<AP>;

    fn run(self, not_started_executor: Self::Exec) -> Result<Self::Res, Self::Err> {
        let mut executor =
            try!(not_started_executor.try_start(self.lc_builder).map_err(|e| Error::ExecutorStart(e)));
        let init_population = try!(self.pop_init.init(&mut executor).map_err(|e| Error::PopulationInit(e)));

        Err(Error::Dummy)
    }
}
<commit_msg>`PopInit` config -> `Pop` (population is common)<commit_after>use std::marker::PhantomData;
use par_exec::{Executor, LocalContextBuilder, ExecutorNewError};

use super::Algorithm;
use super::super::pop::individual::{Individual, IndividualManager, IndividualManagerMut};
use super::super::pop::init::PopulationInit;
use super::super::pop::init::limited;
use super::super::set::{Set, SetManager, SetManagerMut};

// common policy
pub trait Policy {
    // individual config
    type Indiv: Individual;
    type IndivME: Send + 'static;
    type IndivM: IndividualManager<I = Self::Indiv, E = Self::IndivME>;

    // population config
    type PopSE: Send + 'static;
    type PopS: Set<T = Self::Indiv, E = Self::PopSE> + Send + 'static;
    type PopSME: Send + 'static;
    type PopSM: SetManager<S = Self::PopS, E = Self::PopSME>;
}

pub struct LocalContext<P> where P: Policy {
    indiv_manager: P::IndivM,
    pop_set_manager: P::PopSM,
}

impl<P> SetManagerMut for LocalContext<P> where P: Policy {
    type SM = P::PopSM;

    fn set_manager_mut(&mut self) -> &mut Self::SM {
        &mut self.pop_set_manager
    }
}

impl<P> IndividualManagerMut for LocalContext<P> where P: Policy {
    type IM = P::IndivM;

    fn individual_manager_mut(&mut self) -> &mut Self::IM {
        &mut self.indiv_manager
    }
}

// algorithm policy
pub trait APolicy {
    type P: Policy;
    type LCBuilder: LocalContextBuilder<LC = LocalContext<Self::P>>;
    type Exec: Executor<LC = LocalContext<Self::P>>;
}

pub struct PopInitPolicy<AP>(PhantomData<AP>) where AP: APolicy;

impl<AP> limited::Policy for PopInitPolicy<AP> where AP: APolicy {
    type LocalContext = LocalContext<AP::P>;
    type Exec = AP::Exec;
    type Indiv = <AP::P as Policy>::Indiv;
    type IndivME = <AP::P as Policy>::IndivME;
    type IndivM = <AP::P as Policy>::IndivM;
    type PopE = <AP::P as Policy>::PopSE;
    type Pop = <AP::P as Policy>::PopS;
    type PopSME = <AP::P as Policy>::PopSME;
    type PopSM = <AP::P as Policy>::PopSM;
}

pub struct MuCommaLambda<AP> where AP: APolicy {
    lc_builder: AP::LCBuilder,
    pop_init: limited::LimitedPopulationInit<PopInitPolicy<AP>>,
}

impl<AP> MuCommaLambda<AP> where AP: APolicy {
    pub fn new(lc_builder: AP::LCBuilder, lambda: usize) -> MuCommaLambda<AP> {
        MuCommaLambda {
            lc_builder: lc_builder,
            pop_init: limited::LimitedPopulationInit::new(lambda),
        }
    }
}

pub enum Error<AP> where AP: APolicy {
    ExecutorStart(ExecutorNewError<<AP::Exec as Executor>::E, <AP::LCBuilder as LocalContextBuilder>::E>),
    PopulationInit(limited::Error<PopInitPolicy<AP>>),

    Dummy
}

impl<AP> Algorithm for MuCommaLambda<AP> where AP: APolicy {
    type Exec = AP::Exec;
    type Res = <AP::P as Policy>::Indiv;
    type Err = Error<AP>;

    fn run(self, not_started_executor: Self::Exec) -> Result<Self::Res, Self::Err> {
        let mut executor =
            try!(not_started_executor.try_start(self.lc_builder).map_err(|e| Error::ExecutorStart(e)));
        let init_population = try!(self.pop_init.init(&mut executor).map_err(|e| Error::PopulationInit(e)));

        Err(Error::Dummy)
    }
}
<|endoftext|>


<commit_before>// # References
//
// "The Content-Disposition Header Field" https://www.ietf.org/rfc/rfc2183.txt
// "The Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)" https://www.ietf.org/rfc/rfc6266.txt
// "Returning Values from Forms: multipart/form-data" https://www.ietf.org/rfc/rfc2388.txt
// Browser conformance tests at: http://greenbytes.de/tech/tc2231/
// IANA assignment: http://www.iana.org/assignments/cont-disp/cont-disp.xhtml

use language_tags::LanguageTag;
use unicase;

use header;
use header::{Header, IntoHeaderValue, Writer};
use header::shared::Charset;

use std::fmt::{self, Write};

/// The implied disposition of the content of the HTTP body.
#[derive(Clone, Debug, PartialEq)]
pub enum DispositionType {
    /// Inline implies default processing
    Inline,
    /// Attachment implies that the recipient should prompt the user to save the response locally,
    /// rather than process it normally (as per its media type).
    Attachment,
    /// Extension type.  Should be handled by recipients the same way as Attachment
    Ext(String)
}

/// A parameter to the disposition type.
#[derive(Clone, Debug, PartialEq)]
pub enum DispositionParam {
    /// A Filename consisting of a Charset, an optional LanguageTag, and finally a sequence of
    /// bytes representing the filename
    Filename(Charset, Option<LanguageTag>, Vec<u8>),
    /// Extension type consisting of token and value.  Recipients should ignore unrecognized
    /// parameters.
    Ext(String, String)
}

/// A `Content-Disposition` header, (re)defined in [RFC6266](https://tools.ietf.org/html/rfc6266).
///
/// The Content-Disposition response header field is used to convey
/// additional information about how to process the response payload, and
/// also can be used to attach additional metadata, such as the filename
/// to use when saving the response payload locally.
///
/// # ABNF

/// ```text
/// content-disposition = "Content-Disposition" ":"
///                       disposition-type *( ";" disposition-parm )
///
/// disposition-type    = "inline" | "attachment" | disp-ext-type
///                       ; case-insensitive
///
/// disp-ext-type       = token
///
/// disposition-parm    = filename-parm | disp-ext-parm
///
/// filename-parm       = "filename" "=" value
///                     | "filename*" "=" ext-value
///
/// disp-ext-parm       = token "=" value
///                     | ext-token "=" ext-value
///
/// ext-token           = <the characters in token, followed by "*">
/// ```
///
/// # Example
///
/// ```
/// use hyper::header::{Headers, ContentDisposition, DispositionType, DispositionParam, Charset};
///
/// let mut headers = Headers::new();
/// headers.set(ContentDisposition {
///     disposition: DispositionType::Attachment,
///     parameters: vec![DispositionParam::Filename(
///       Charset::Iso_8859_1, // The character set for the bytes of the filename
///       None, // The optional language tag (see `language-tag` crate)
///       b"\xa9 Copyright 1989.txt".to_vec() // the actual bytes of the filename
///     )]
/// });
/// ```
#[derive(Clone, Debug, PartialEq)]
pub struct ContentDisposition {
    /// The disposition
    pub disposition: DispositionType,
    /// Disposition parameters
    pub parameters: Vec<DispositionParam>,
}
impl ContentDisposition {
    /// Parse a raw Content-Disposition header value
    pub fn from_raw(hv: Option<&header::HeaderValue>) -> Result<Self, ::error::ParseError> {
        header::from_one_raw_str(hv).and_then(|s: String| {
            let mut sections = s.split(';');
            let disposition = match sections.next() {
                Some(s) => s.trim(),
                None => return Err(::error::ParseError::Header),
            };

            let mut cd = ContentDisposition {
                disposition: if unicase::eq_ascii(&*disposition, "inline") {
                    DispositionType::Inline
                } else if unicase::eq_ascii(&*disposition, "attachment") {
                    DispositionType::Attachment
                } else {
                    DispositionType::Ext(disposition.to_owned())
                },
                parameters: Vec::new(),
            };

            for section in sections {
                let mut parts = section.splitn(2, '=');

                let key = if let Some(key) = parts.next() {
                    key.trim()
                } else {
                    return Err(::error::ParseError::Header);
                };

                let val = if let Some(val) = parts.next() {
                    val.trim()
                } else {
                    return Err(::error::ParseError::Header);
                };

                cd.parameters.push(
                    if unicase::eq_ascii(&*key, "filename") {
                        DispositionParam::Filename(
                            Charset::Ext("UTF-8".to_owned()), None,
                            val.trim_matches('"').as_bytes().to_owned())
                    } else if unicase::eq_ascii(&*key, "filename*") {
                        let extended_value = try!(header::parse_extended_value(val));
                        DispositionParam::Filename(extended_value.charset, extended_value.language_tag, extended_value.value)
                    } else {
                        DispositionParam::Ext(key.to_owned(), val.trim_matches('"').to_owned())
                    }
                );
            }

            Ok(cd)
        })
    }
}

impl IntoHeaderValue for ContentDisposition {
    type Error = header::InvalidHeaderValueBytes;

    fn try_into(self) -> Result<header::HeaderValue, Self::Error> {
        let mut writer = Writer::new();
        let _ = write!(&mut writer, "{}", self);
        header::HeaderValue::from_shared(writer.take())
    }
}

impl Header for ContentDisposition {
    fn name() -> header::HeaderName {
        header::CONTENT_DISPOSITION
    }

    fn parse<T: ::HttpMessage>(msg: &T) -> Result<Self, ::error::ParseError> {
        Self::from_raw(msg.headers().get(Self::name()))
    }
}

impl fmt::Display for ContentDisposition {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.disposition {
            DispositionType::Inline => try!(write!(f, "inline")),
            DispositionType::Attachment => try!(write!(f, "attachment")),
            DispositionType::Ext(ref s) => try!(write!(f, "{}", s)),
        }
        for param in &self.parameters {
            match *param {
                DispositionParam::Filename(ref charset, ref opt_lang, ref bytes) => {
                    let mut use_simple_format: bool = false;
                    if opt_lang.is_none() {
                        if let Charset::Ext(ref ext) = *charset {
                            if unicase::eq_ascii(&**ext, "utf-8") {
                                use_simple_format = true;
                            }
                        }
                    }
                    if use_simple_format {
                        try!(write!(f, "; filename=\"{}\"",
                                    match String::from_utf8(bytes.clone()) {
                                        Ok(s) => s,
                                        Err(_) => return Err(fmt::Error),
                                    }));
                    } else {
                        try!(write!(f, "; filename*={}'", charset));
                        if let Some(ref lang) = *opt_lang {
                            try!(write!(f, "{}", lang));
                        };
                        try!(write!(f, "'"));
                        try!(header::http_percent_encode(f, bytes))
                    }
                },
                DispositionParam::Ext(ref k, ref v) => try!(write!(f, "; {}=\"{}\"", k, v)),
            }
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::{ContentDisposition,DispositionType,DispositionParam};
    use header::HeaderValue;
    use header::shared::Charset;
    #[test]
    fn test_from_raw() {
        assert!(ContentDisposition::from_raw(Some(&HeaderValue::from_static(""))).is_err());

        let a = HeaderValue::from_static("form-data; dummy=3; name=upload;\r\n filename=\"sample.png\"");
        let a: ContentDisposition = ContentDisposition::from_raw(Some(&a)).unwrap();
        let b = ContentDisposition {
            disposition: DispositionType::Ext("form-data".to_owned()),
            parameters: vec![
                DispositionParam::Ext("dummy".to_owned(), "3".to_owned()),
                DispositionParam::Ext("name".to_owned(), "upload".to_owned()),
                DispositionParam::Filename(
                    Charset::Ext("UTF-8".to_owned()),
                    None,
                    "sample.png".bytes().collect()) ]
        };
        assert_eq!(a, b);

        let a = HeaderValue::from_static("attachment; filename=\"image.jpg\"");
        let a: ContentDisposition = ContentDisposition::from_raw(Some(&a)).unwrap();
        let b = ContentDisposition {
            disposition: DispositionType::Attachment,
            parameters: vec![
                DispositionParam::Filename(
                    Charset::Ext("UTF-8".to_owned()),
                    None,
                    "image.jpg".bytes().collect()) ]
        };
        assert_eq!(a, b);

        let a = HeaderValue::from_static("attachment; filename*=UTF-8''%c2%a3%20and%20%e2%82%ac%20rates");
        let a: ContentDisposition = ContentDisposition::from_raw(Some(&a)).unwrap();
        let b = ContentDisposition {
            disposition: DispositionType::Attachment,
            parameters: vec![
                DispositionParam::Filename(
                    Charset::Ext("UTF-8".to_owned()),
                    None,
                    vec![0xc2, 0xa3, 0x20, b'a', b'n', b'd', 0x20,
                         0xe2, 0x82, 0xac, 0x20, b'r', b'a', b't', b'e', b's']) ]
        };
        assert_eq!(a, b);
    }

    #[test]
    fn test_display() {
        let as_string = "attachment; filename*=UTF-8'en'%C2%A3%20and%20%E2%82%AC%20rates";
        let a = HeaderValue::from_static(as_string);
        let a: ContentDisposition = ContentDisposition::from_raw(Some(&a)).unwrap();
        let display_rendered = format!("{}",a);
        assert_eq!(as_string, display_rendered);

        let a = HeaderValue::from_static("attachment; filename*=UTF-8''black%20and%20white.csv");
        let a: ContentDisposition = ContentDisposition::from_raw(Some(&a)).unwrap();
        let display_rendered = format!("{}",a);
        assert_eq!("attachment; filename=\"black and white.csv\"".to_owned(), display_rendered);

        let a = HeaderValue::from_static("attachment; filename=colourful.csv");
        let a: ContentDisposition = ContentDisposition::from_raw(Some(&a)).unwrap();
        let display_rendered = format!("{}",a);
        assert_eq!("attachment; filename=\"colourful.csv\"".to_owned(), display_rendered);
    }
}
<commit_msg>fix test<commit_after>// # References
//
// "The Content-Disposition Header Field" https://www.ietf.org/rfc/rfc2183.txt
// "The Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)" https://www.ietf.org/rfc/rfc6266.txt
// "Returning Values from Forms: multipart/form-data" https://www.ietf.org/rfc/rfc2388.txt
// Browser conformance tests at: http://greenbytes.de/tech/tc2231/
// IANA assignment: http://www.iana.org/assignments/cont-disp/cont-disp.xhtml

use language_tags::LanguageTag;
use unicase;

use header;
use header::{Header, IntoHeaderValue, Writer};
use header::shared::Charset;

use std::fmt::{self, Write};

/// The implied disposition of the content of the HTTP body.
#[derive(Clone, Debug, PartialEq)]
pub enum DispositionType {
    /// Inline implies default processing
    Inline,
    /// Attachment implies that the recipient should prompt the user to save the response locally,
    /// rather than process it normally (as per its media type).
    Attachment,
    /// Extension type.  Should be handled by recipients the same way as Attachment
    Ext(String)
}

/// A parameter to the disposition type.
#[derive(Clone, Debug, PartialEq)]
pub enum DispositionParam {
    /// A Filename consisting of a Charset, an optional LanguageTag, and finally a sequence of
    /// bytes representing the filename
    Filename(Charset, Option<LanguageTag>, Vec<u8>),
    /// Extension type consisting of token and value.  Recipients should ignore unrecognized
    /// parameters.
    Ext(String, String)
}

/// A `Content-Disposition` header, (re)defined in [RFC6266](https://tools.ietf.org/html/rfc6266).
///
/// The Content-Disposition response header field is used to convey
/// additional information about how to process the response payload, and
/// also can be used to attach additional metadata, such as the filename
/// to use when saving the response payload locally.
///
/// # ABNF

/// ```text
/// content-disposition = "Content-Disposition" ":"
///                       disposition-type *( ";" disposition-parm )
///
/// disposition-type    = "inline" | "attachment" | disp-ext-type
///                       ; case-insensitive
///
/// disp-ext-type       = token
///
/// disposition-parm    = filename-parm | disp-ext-parm
///
/// filename-parm       = "filename" "=" value
///                     | "filename*" "=" ext-value
///
/// disp-ext-parm       = token "=" value
///                     | ext-token "=" ext-value
///
/// ext-token           = <the characters in token, followed by "*">
/// ```
///
/// # Example
///
/// ```
/// use hyper::header::{Headers, ContentDisposition, DispositionType, DispositionParam, Charset};
///
/// let mut headers = Headers::new();
/// headers.set(ContentDisposition {
///     disposition: DispositionType::Attachment,
///     parameters: vec![DispositionParam::Filename(
///       Charset::Iso_8859_1, // The character set for the bytes of the filename
///       None, // The optional language tag (see `language-tag` crate)
///       b"\xa9 Copyright 1989.txt".to_vec() // the actual bytes of the filename
///     )]
/// });
/// ```
#[derive(Clone, Debug, PartialEq)]
pub struct ContentDisposition {
    /// The disposition
    pub disposition: DispositionType,
    /// Disposition parameters
    pub parameters: Vec<DispositionParam>,
}
impl ContentDisposition {
    /// Parse a raw Content-Disposition header value
    pub fn from_raw(hv: Option<&header::HeaderValue>) -> Result<Self, ::error::ParseError> {
        header::from_one_raw_str(hv).and_then(|s: String| {
            let mut sections = s.split(';');
            let disposition = match sections.next() {
                Some(s) => s.trim(),
                None => return Err(::error::ParseError::Header),
            };

            let mut cd = ContentDisposition {
                disposition: if unicase::eq_ascii(&*disposition, "inline") {
                    DispositionType::Inline
                } else if unicase::eq_ascii(&*disposition, "attachment") {
                    DispositionType::Attachment
                } else {
                    DispositionType::Ext(disposition.to_owned())
                },
                parameters: Vec::new(),
            };

            for section in sections {
                let mut parts = section.splitn(2, '=');

                let key = if let Some(key) = parts.next() {
                    key.trim()
                } else {
                    return Err(::error::ParseError::Header);
                };

                let val = if let Some(val) = parts.next() {
                    val.trim()
                } else {
                    return Err(::error::ParseError::Header);
                };

                cd.parameters.push(
                    if unicase::eq_ascii(&*key, "filename") {
                        DispositionParam::Filename(
                            Charset::Ext("UTF-8".to_owned()), None,
                            val.trim_matches('"').as_bytes().to_owned())
                    } else if unicase::eq_ascii(&*key, "filename*") {
                        let extended_value = try!(header::parse_extended_value(val));
                        DispositionParam::Filename(extended_value.charset, extended_value.language_tag, extended_value.value)
                    } else {
                        DispositionParam::Ext(key.to_owned(), val.trim_matches('"').to_owned())
                    }
                );
            }

            Ok(cd)
        })
    }
}

impl IntoHeaderValue for ContentDisposition {
    type Error = header::InvalidHeaderValueBytes;

    fn try_into(self) -> Result<header::HeaderValue, Self::Error> {
        let mut writer = Writer::new();
        let _ = write!(&mut writer, "{}", self);
        header::HeaderValue::from_shared(writer.take())
    }
}

impl Header for ContentDisposition {
    fn name() -> header::HeaderName {
        header::CONTENT_DISPOSITION
    }

    fn parse<T: ::HttpMessage>(msg: &T) -> Result<Self, ::error::ParseError> {
        Self::from_raw(msg.headers().get(Self::name()))
    }
}

impl fmt::Display for ContentDisposition {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.disposition {
            DispositionType::Inline => try!(write!(f, "inline")),
            DispositionType::Attachment => try!(write!(f, "attachment")),
            DispositionType::Ext(ref s) => try!(write!(f, "{}", s)),
        }
        for param in &self.parameters {
            match *param {
                DispositionParam::Filename(ref charset, ref opt_lang, ref bytes) => {
                    let mut use_simple_format: bool = false;
                    if opt_lang.is_none() {
                        if let Charset::Ext(ref ext) = *charset {
                            if unicase::eq_ascii(&**ext, "utf-8") {
                                use_simple_format = true;
                            }
                        }
                    }
                    if use_simple_format {
                        try!(write!(f, "; filename=\"{}\"",
                                    match String::from_utf8(bytes.clone()) {
                                        Ok(s) => s,
                                        Err(_) => return Err(fmt::Error),
                                    }));
                    } else {
                        try!(write!(f, "; filename*={}'", charset));
                        if let Some(ref lang) = *opt_lang {
                            try!(write!(f, "{}", lang));
                        };
                        try!(write!(f, "'"));
                        try!(header::http_percent_encode(f, bytes))
                    }
                },
                DispositionParam::Ext(ref k, ref v) => try!(write!(f, "; {}=\"{}\"", k, v)),
            }
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::{ContentDisposition,DispositionType,DispositionParam};
    use header::HeaderValue;
    use header::shared::Charset;
    #[test]
    fn test_from_raw() {
        assert!(ContentDisposition::from_raw(Some(&HeaderValue::from_static(""))).is_err());

        let a = HeaderValue::from_static("form-data; dummy=3; name=upload; filename=\"sample.png\"");
        let a: ContentDisposition = ContentDisposition::from_raw(Some(&a)).unwrap();
        let b = ContentDisposition {
            disposition: DispositionType::Ext("form-data".to_owned()),
            parameters: vec![
                DispositionParam::Ext("dummy".to_owned(), "3".to_owned()),
                DispositionParam::Ext("name".to_owned(), "upload".to_owned()),
                DispositionParam::Filename(
                    Charset::Ext("UTF-8".to_owned()),
                    None,
                    "sample.png".bytes().collect()) ]
        };
        assert_eq!(a, b);

        let a = HeaderValue::from_static("attachment; filename=\"image.jpg\"");
        let a: ContentDisposition = ContentDisposition::from_raw(Some(&a)).unwrap();
        let b = ContentDisposition {
            disposition: DispositionType::Attachment,
            parameters: vec![
                DispositionParam::Filename(
                    Charset::Ext("UTF-8".to_owned()),
                    None,
                    "image.jpg".bytes().collect()) ]
        };
        assert_eq!(a, b);

        let a = HeaderValue::from_static("attachment; filename*=UTF-8''%c2%a3%20and%20%e2%82%ac%20rates");
        let a: ContentDisposition = ContentDisposition::from_raw(Some(&a)).unwrap();
        let b = ContentDisposition {
            disposition: DispositionType::Attachment,
            parameters: vec![
                DispositionParam::Filename(
                    Charset::Ext("UTF-8".to_owned()),
                    None,
                    vec![0xc2, 0xa3, 0x20, b'a', b'n', b'd', 0x20,
                         0xe2, 0x82, 0xac, 0x20, b'r', b'a', b't', b'e', b's']) ]
        };
        assert_eq!(a, b);
    }

    #[test]
    fn test_display() {
        let as_string = "attachment; filename*=UTF-8'en'%C2%A3%20and%20%E2%82%AC%20rates";
        let a = HeaderValue::from_static(as_string);
        let a: ContentDisposition = ContentDisposition::from_raw(Some(&a)).unwrap();
        let display_rendered = format!("{}",a);
        assert_eq!(as_string, display_rendered);

        let a = HeaderValue::from_static("attachment; filename*=UTF-8''black%20and%20white.csv");
        let a: ContentDisposition = ContentDisposition::from_raw(Some(&a)).unwrap();
        let display_rendered = format!("{}",a);
        assert_eq!("attachment; filename=\"black and white.csv\"".to_owned(), display_rendered);

        let a = HeaderValue::from_static("attachment; filename=colourful.csv");
        let a: ContentDisposition = ContentDisposition::from_raw(Some(&a)).unwrap();
        let display_rendered = format!("{}",a);
        assert_eq!("attachment; filename=\"colourful.csv\"".to_owned(), display_rendered);
    }
}
<|endoftext|>