<commit_before>use editor::Editor;
use parse::{Inst, Parameter};
use key::Key;
use mode::{Mode, CommandMode, PrimitiveMode};
use insert::{InsertOptions, InsertMode};
use redraw::RedrawTask;
use buffer::Buffer;

// TODO: Move the command definitions outta here
impl Editor {
    /// Execute an instruction
    pub fn exec(&mut self, Inst(para, cmd): Inst) {
        use key::Key::*;
        use mode::Mode::*;
        use mode::PrimitiveMode::*;
        use mode::CommandMode::*;

        let n = para.d();
        let bef = self.pos();
        let mut mov = false;

        if cmd.key == Key::Char(' ') && self.key_state.shift {

            let mode = self.cursor().mode;

            match mode {
                Primitive(Prompt) => self.prompt = String::new(),
                Primitive(Insert(_)) => {
                    let left = self.left(1);
                    self.goto(left);
                }
                _ => {}
            }
            self.cursor_mut().mode = Mode::Command(CommandMode::Normal);

        } else if self.key_state.alt && cmd.key == Key::Char(' ') {

            self.next_cursor();

        } else if self.key_state.alt {

            if let Some(m) = self.to_motion(Inst(para, cmd)) {
                self.goto(m);
            }

        } else {
            match self.cursor().mode {
                Command(Normal) => match cmd.key {
                    //                    // { for debuging
                    //                    Char('n') => {
                    //                        let p = self.next(n);
                    //                        if let Some(p) = p {
                    //                            self.goto(p);
                    //                        }
                    //                    },
                    //                    Char('p') => {
                    //                        let p = self.previous(n);
                    //                        if let Some(p) = p {
                    //                            self.goto(p);
                    //                        }
                    //                    },
                    //                    // }
                    Char('i') => {
                        self.cursor_mut().mode =
                            Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                mode: InsertMode::Insert,
                            }));

                    }
                    Char('a') => {
                        let pos = self.right(1, false);
                        self.goto( pos );
                        self.cursor_mut().mode =
                            Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                mode: InsertMode::Insert,
                            }));

                    }
                    Char('o') => {
                        let y = self.y();
                        let ind = if self.options.autoindent {
                            self.buffer.get_indent(y).to_owned()
                        } else {
                            String::new()
                        };
                        let last = ind.len();
                        self.buffer.insert_line(y, ind.into());
                        self.goto((last, y + 1));
                        self.cursor_mut().mode =
                            Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                mode: InsertMode::Insert,
                            }));
                    }
                    Char('h') => {
                        let left = self.left(n);
                        self.goto(left);
                        mov = true;
                    }
                    Char('j') => {
                        let down = self.down(n);
                        self.goto(down);
                        mov = true;
                    }
                    Char('k') => {
                        let up = self.up(n);
                        self.goto(up);
                        mov = true;
                    }
                    Char('l') => {
                        let right = self.right(n, true);
                        self.goto(right);
                        mov = true;
                    }
                    Char('J') => {
                        let down = self.down(15 * n);
                        self.goto(down);
                        mov = true;
                    }
                    Char('K') => {
                        let up = self.up(15 * n);
                        self.goto(up);
                        mov = true;
                    }
                    Char('x') => {
                        self.delete();
                        let bounded = self.bound(self.pos(), true);
                        self.goto(bounded);
                    }
                    Char('X') => {
                        self.backspace();
                        let bounded = self.bound(self.pos(), true);
                        self.goto(bounded);
                    }
                    Char('L') => {
                        let ln_end = (self.buffer[self.y()].len(), self.y());
                        self.goto(ln_end);
                        mov = true;
                    }
                    Char('H') => {
                        self.cursor_mut().x = 0;
                        mov = true;
                    }
                    Char('r') => {
                        let (x, y) = self.pos();
                        let c = self.get_char();
                        // If there is nothing in the current buffer
                        // ignore the command
                        if self.buffer[y].len() > 0 {
                            self.buffer[y].remove(x);
                        }
                        self.buffer[y].insert(x, c);

                    }
                    Char('R') => {
                        self.cursor_mut().mode =
                            Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                mode: InsertMode::Replace,
                            }));
                    }
                    Char('d') => {
                        let ins = self.get_inst();
                        if let Some(m) = self.to_motion_unbounded(ins) {
                            self.remove_rb(m);
                        }
                    }
                    Char('G') => {
                        let last = self.buffer.len() - 1;
                        self.goto((0, last));
                        mov = true;
                    }
                    Char('g') => {
                        if let Parameter::Int(n) = para {
                            self.goto((0, n - 1));
                            mov = true;
                        } else {
                            let inst = self.get_inst();
                            if let Some(m) = self.to_motion(inst) {
                                self.goto(m); // fix
                                mov = true;
                            }
                        }

                    }
                    Char('b') => {
                        // Branch cursor
                        if self.cursors.len() < 255 {
                            let cursor = self.cursor().clone();
                            self.cursors.insert(self.current_cursor as usize, cursor);
                            self.next_cursor();
                        }
                        else {
                            self.status_bar.msg = format!("At max 255 cursors");
                        }
                    }
                    Char('B') => {
                        // Delete cursor
                        if self.cursors.len() > 1 {
                            self.cursors.remove(self.current_cursor as usize);
                            self.prev_cursor();
                        }
                        else {
                            self.status_bar.msg = format!("No other cursors!");
                        }
                    }
                    Char('t') => {
                        let ch = self.get_char();

                        let pos = self.next_ocur(ch, n);
                        if let Some(p) = pos {
                            let y = self.y();
                            self.goto((p, y));
                            mov = true;
                        }
                    }
                    Char('f') => {
                        let ch = self.get_char();

                        let pos = self.previous_ocur(ch, n);
                        if let Some(p) = pos {
                            let y = self.y();
                            self.goto((p, y));
                            mov = true;
                        }
                    }
                    Char(';') => {
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Prompt);
                    }
                    Char(' ') => {
                        self.next_cursor();
                    }
                    Char('z') => {
                        let Inst(param, cmd) = self.get_inst();
                        match param {
                            Parameter::Null => {
                                if let Some(m) = self.to_motion(Inst(param, cmd)) {
                                    self.scroll_y = m.1;
                                    self.goto(m);
                                }
                            }
                            Parameter::Int(n) => {
                                self.scroll_y = n;
                            }
                        }
                        self.redraw_task = RedrawTask::Full;
                    }
                    Char('Z') => {
                        self.scroll_y = self.y() - 3;
                        self.redraw_task = RedrawTask::Full;
                    }
                    Char('~') => {
                        self.invert_chars(n);
                    }
                    Char(c) => {
                        self.status_bar.msg = format!("Unknown command: {}", c);
                        self.redraw_task = RedrawTask::StatusBar;
                    }
                    _ => {
                        self.status_bar.msg = format!("Unknown command");
                        self.redraw_task = RedrawTask::StatusBar;
                    }
                },
                Primitive(Insert(opt)) => {
                    self.insert(cmd.key, opt);
                }
                Primitive(Prompt) => {
                    match cmd.key {
                        Char('\n') => {
                            self.cursor_mut().mode = Command(Normal);
                            let cmd = self.prompt.clone();

                            self.invoke(cmd);
                            self.prompt = String::new();
                        }
                        Backspace => {
                            self.prompt.pop();
                        }
                        Char(c) => self.prompt.push(c),
                        _ => {}
                    }
                    self.redraw_task = RedrawTask::StatusBar;
                }
            }
        }
        if mov {
            self.redraw_task = RedrawTask::Cursor(bef, self.pos());
        }
    }
}
<commit_msg>Fix r panic<commit_after>use editor::Editor;
use parse::{Inst, Parameter};
use key::Key;
use mode::{Mode, CommandMode, PrimitiveMode};
use insert::{InsertOptions, InsertMode};
use redraw::RedrawTask;
use buffer::Buffer;

// TODO: Move the command definitions outta here
impl Editor {
    /// Execute an instruction
    pub fn exec(&mut self, Inst(para, cmd): Inst) {
        use key::Key::*;
        use mode::Mode::*;
        use mode::PrimitiveMode::*;
        use mode::CommandMode::*;

        let n = para.d();
        let bef = self.pos();
        let mut mov = false;

        if cmd.key == Key::Char(' ') && self.key_state.shift {

            let mode = self.cursor().mode;

            match mode {
                Primitive(Prompt) => self.prompt = String::new(),
                Primitive(Insert(_)) => {
                    let left = self.left(1);
                    self.goto(left);
                }
                _ => {}
            }
            self.cursor_mut().mode = Mode::Command(CommandMode::Normal);

        } else if self.key_state.alt && cmd.key == Key::Char(' ') {

            self.next_cursor();

        } else if self.key_state.alt {

            if let Some(m) = self.to_motion(Inst(para, cmd)) {
                self.goto(m);
            }

        } else {
            match self.cursor().mode {
                Command(Normal) => match cmd.key {
                    //                    // { for debuging
                    //                    Char('n') => {
                    //                        let p = self.next(n);
                    //                        if let Some(p) = p {
                    //                            self.goto(p);
                    //                        }
                    //                    },
                    //                    Char('p') => {
                    //                        let p = self.previous(n);
                    //                        if let Some(p) = p {
                    //                            self.goto(p);
                    //                        }
                    //                    },
                    //                    // }
                    Char('i') => {
                        self.cursor_mut().mode =
                            Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                mode: InsertMode::Insert,
                            }));

                    }
                    Char('a') => {
                        let pos = self.right(1, false);
                        self.goto( pos );
                        self.cursor_mut().mode =
                            Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                mode: InsertMode::Insert,
                            }));

                    }
                    Char('o') => {
                        let y = self.y();
                        let ind = if self.options.autoindent {
                            self.buffer.get_indent(y).to_owned()
                        } else {
                            String::new()
                        };
                        let last = ind.len();
                        self.buffer.insert_line(y, ind.into());
                        self.goto((last, y + 1));
                        self.cursor_mut().mode =
                            Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                mode: InsertMode::Insert,
                            }));
                    }
                    Char('h') => {
                        let left = self.left(n);
                        self.goto(left);
                        mov = true;
                    }
                    Char('j') => {
                        let down = self.down(n);
                        self.goto(down);
                        mov = true;
                    }
                    Char('k') => {
                        let up = self.up(n);
                        self.goto(up);
                        mov = true;
                    }
                    Char('l') => {
                        let right = self.right(n, true);
                        self.goto(right);
                        mov = true;
                    }
                    Char('J') => {
                        let down = self.down(15 * n);
                        self.goto(down);
                        mov = true;
                    }
                    Char('K') => {
                        let up = self.up(15 * n);
                        self.goto(up);
                        mov = true;
                    }
                    Char('x') => {
                        self.delete();
                        let bounded = self.bound(self.pos(), true);
                        self.goto(bounded);
                    }
                    Char('X') => {
                        self.backspace();
                        let bounded = self.bound(self.pos(), true);
                        self.goto(bounded);
                    }
                    Char('L') => {
                        let ln_end = (self.buffer[self.y()].len(), self.y());
                        self.goto(ln_end);
                        mov = true;
                    }
                    Char('H') => {
                        self.cursor_mut().x = 0;
                        mov = true;
                    }
                    Char('r') => {
                        let (x, y) = self.pos();
                        let c = self.get_char();
                        // If there is nothing in the current buffer
                        // ignore the command
                        if self.buffer[y].len() > 0 {
                            self.buffer[y].remove(x);
                        }
                        self.buffer[y].insert(x, c);
                    }
                    Char('R') => {
                        self.cursor_mut().mode =
                            Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                mode: InsertMode::Replace,
                            }));
                    }
                    Char('d') => {
                        let ins = self.get_inst();
                        if let Some(m) = self.to_motion_unbounded(ins) {
                            self.remove_rb(m);
                        }
                    }
                    Char('G') => {
                        let last = self.buffer.len() - 1;
                        self.goto((0, last));
                        mov = true;
                    }
                    Char('g') => {
                        if let Parameter::Int(n) = para {
                            self.goto((0, n - 1));
                            mov = true;
                        } else {
                            let inst = self.get_inst();
                            if let Some(m) = self.to_motion(inst) {
                                self.goto(m); // fix
                                mov = true;
                            }
                        }

                    }
                    Char('b') => {
                        // Branch cursor
                        if self.cursors.len() < 255 {
                            let cursor = self.cursor().clone();
                            self.cursors.insert(self.current_cursor as usize, cursor);
                            self.next_cursor();
                        }
                        else {
                            self.status_bar.msg = format!("At max 255 cursors");
                        }
                    }
                    Char('B') => {
                        // Delete cursor
                        if self.cursors.len() > 1 {
                            self.cursors.remove(self.current_cursor as usize);
                            self.prev_cursor();
                        }
                        else {
                            self.status_bar.msg = format!("No other cursors!");
                        }
                    }
                    Char('t') => {
                        let ch = self.get_char();

                        let pos = self.next_ocur(ch, n);
                        if let Some(p) = pos {
                            let y = self.y();
                            self.goto((p, y));
                            mov = true;
                        }
                    }
                    Char('f') => {
                        let ch = self.get_char();

                        let pos = self.previous_ocur(ch, n);
                        if let Some(p) = pos {
                            let y = self.y();
                            self.goto((p, y));
                            mov = true;
                        }
                    }
                    Char(';') => {
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Prompt);
                    }
                    Char(' ') => {
                        self.next_cursor();
                    }
                    Char('z') => {
                        let Inst(param, cmd) = self.get_inst();
                        match param {
                            Parameter::Null => {
                                if let Some(m) = self.to_motion(Inst(param, cmd)) {
                                    self.scroll_y = m.1;
                                    self.goto(m);
                                }
                            }
                            Parameter::Int(n) => {
                                self.scroll_y = n;
                            }
                        }
                        self.redraw_task = RedrawTask::Full;
                    }
                    Char('Z') => {
                        self.scroll_y = self.y() - 3;
                        self.redraw_task = RedrawTask::Full;
                    }
                    Char('~') => {
                        self.invert_chars(n);
                    }
                    Char(c) => {
                        self.status_bar.msg = format!("Unknown command: {}", c);
                        self.redraw_task = RedrawTask::StatusBar;
                    }
                    _ => {
                        self.status_bar.msg = format!("Unknown command");
                        self.redraw_task = RedrawTask::StatusBar;
                    }
                },
                Primitive(Insert(opt)) => {
                    self.insert(cmd.key, opt);
                }
                Primitive(Prompt) => {
                    match cmd.key {
                        Char('\n') => {
                            self.cursor_mut().mode = Command(Normal);
                            let cmd = self.prompt.clone();

                            self.invoke(cmd);
                            self.prompt = String::new();
                        }
                        Backspace => {
                            self.prompt.pop();
                        }
                        Char(c) => self.prompt.push(c),
                        _ => {}
                    }
                    self.redraw_task = RedrawTask::StatusBar;
                }
            }
        }
        if mov {
            self.redraw_task = RedrawTask::Cursor(bef, self.pos());
        }
    }
}
<|endoftext|>


<commit_before>mod json;

use json_feed::JSONFeed;

use crate::page::Page;

/// Required resources for a `Feed`.
pub(crate) struct Feed<'a> {
    /// Every feed has its own title.
    title: String,
    /// The set of items to render in the feed. A read-only slice because I will
    /// never actually need to *write* to these. I just need the parsed metadata
    /// and rendered HTML contents of the page, to render into the template.
    items: &'a [Page],
}

impl<'a> Feed<'a> {
    pub(crate) fn new(title: String, items: &'a [Page]) -> Feed<'a> {
        Feed { title, items }
    }
}

impl<'a> From<Feed<'a>> for JSONFeed<'a> {
    fn from(feed: Feed<'a>) -> Self {
        todo!()
    }
}
<commit_msg>Feeds: include site_config in feed client<commit_after>mod json;

use json_feed::JSONFeed;

use crate::{config::Config, page::Page};

/// Required resources for a `Feed`.
pub(crate) struct Feed<'a> {
    /// Every feed has its own title.
    title: String,

    /// Feeds also need read access to the site config to be able to render the
    /// full set of data specified for Atom, JSON, or RSS.
    site_config: &'a Config,

    /// The set of items to render in the feed. A read-only slice because I will
    /// never actually need to *write* to these. I just need the parsed metadata
    /// and rendered HTML contents of the page, to render into the template.
    items: &'a [Page],
}

impl<'a> Feed<'a> {
    pub(crate) fn new(title: String, site_config: &'a Config, items: &'a [Page]) -> Feed<'a> {
        Feed {
            title,
            site_config,
            items,
        }
    }
}

impl<'a> From<Feed<'a>> for JSONFeed<'a> {
    fn from(feed: Feed<'a>) -> Self {
        todo!()
    }
}
<|endoftext|>


<commit_before>use std::io::{Read, Seek};
use std::mem;

use Result;
use band::{Band, Value};
use primitive::*;
use table::*;

/// A font.
pub struct Font {
    pub offset_table: OffsetTable,
    pub char_mapping: CharMapping,
    pub font_header: FontHeader,
    pub horizontal_header: HorizontalHeader,
    pub horizontal_metrics: HorizontalMetrics,
    pub maximum_profile: MaximumProfile,
    pub postscript: PostScript,
    pub windows_metrics: WindowsMetrics,
}

#[cfg(target_endian = "big")]
macro_rules! tag(
    ($value:expr) => (unsafe {
        mem::transmute::<_, [u8; 4]>($value)
    })
);

#[cfg(target_endian = "little")]
macro_rules! tag(
    ($value:expr) => (unsafe {
        let mut value = mem::transmute::<_, [u8; 4]>($value);
        value.reverse();
        value
    })
);

impl Font {
    pub fn read<T: Read + Seek>(reader: &mut T) -> Result<Font> {
        macro_rules! some(
            ($option:expr, $object:expr, plural) => (match $option {
                Some(value) => value,
                _ => raise!(concat!($object, " are missing")),
            });
            ($option:expr, $object:expr) => (match $option {
                Some(value) => value,
                _ => raise!(concat!($object, " is missing")),
            });
        );

        macro_rules! sort(
            ($records:expr) => ({
                let mut records = $records.iter().collect::<Vec<_>>();
                records.sort_by(|one, two| {
                    priority(&tag!(one.tag)).cmp(&priority(&tag!(two.tag)))
                });
                records
            });
        );

        let offset_table = try!(read_offset_table(reader));

        let mut char_mapping = None;
        let mut font_header = None;
        let mut horizontal_header = None;
        let mut horizontal_metrics = None;
        let mut maximum_profile = None;
        let mut postscript = None;
        let mut windows_metrics = None;

        for record in sort!(offset_table.records) {
            match &tag!(record.tag) {
                b"cmap" => char_mapping = Some(try!(read_char_mapping(reader, record))),
                b"head" => font_header = Some(try!(read_font_header(reader, record))),
                b"hhea" => horizontal_header = Some(try!(read_horizontal_header(reader, record))),
                b"hmtx" => {
                    let header = some!(horizontal_header.as_ref(), "the horizontal header");
                    let profile = some!(maximum_profile.as_ref(), "the maximum profile");
                    horizontal_metrics = Some(try!(read_horizontal_metrics(reader, record, header,
                                                                           profile)));
                },
                b"maxp" => maximum_profile = Some(try!(read_maximum_profile(reader, record))),
                b"post" => postscript = Some(try!(read_postscript(reader, record))),
                b"OS/2" => windows_metrics = Some(try!(read_windows_metrics(reader, record))),
                _ => (),
            }
        }

        Ok(Font {
            offset_table: offset_table,
            char_mapping: some!(char_mapping, "the character-to-glyph mapping"),
            font_header: some!(font_header, "the font header"),
            horizontal_header: some!(horizontal_header, "the horizontal header"),
            horizontal_metrics: some!(horizontal_metrics, "the horizontal metrics", plural),
            maximum_profile: some!(maximum_profile, "the maximum profile"),
            postscript: some!(postscript, "the PostScript information"),
            windows_metrics: some!(windows_metrics, "the OS/2 and Windows metrics", plural),
        })
    }
}

fn read_offset_table<T: Band>(band: &mut T) -> Result<OffsetTable> {
    const CFF_TAG: &'static [u8; 4] = b"OTTO";

    let header = try!(OffsetTableHeader::read(band));
    if &tag!(header.version) != CFF_TAG {
        raise!("the format of a font is not supported");
    }
    let mut records = vec![];
    for _ in 0..header.numTables {
        records.push(try!(OffsetTableRecord::read(band)));
    }

    Ok(OffsetTable { header: header, records: records })
}

fn read_char_mapping<T: Band>(band: &mut T, table: &OffsetTableRecord) -> Result<CharMapping> {
    const VERSION_0_0: USHORT = 0;

    if !try!(table.check(band, |_, chunk| chunk)) {
        raise!("the character-to-glyph mapping is corrupted");
    }
    try!(band.jump(table.offset as u64));

    let header = try!(CharMappingHeader::read(band));
    if header.version != VERSION_0_0 {
        raise!("the format of the character-to-glyph mapping header is not supported");
    }
    let mut records = vec![];
    for _ in 0..header.numTables {
        records.push(try!(CharMappingRecord::read(band)));
    }
    let mut encodings = vec![];
    for encoding in records.iter() {
        try!(band.jump(table.offset as u64 + encoding.offset as u64));
        encodings.push(match try!(band.peek::<USHORT>()) {
            4 => CharMappingEncoding::Format4(try!(Value::read(band))),
            6 => CharMappingEncoding::Format6(try!(Value::read(band))),
            _ => raise!("the format of a character-to-glyph mapping is not supported"),
        });
    }

    Ok(CharMapping { header: header, records: records, encodings: encodings })
}

fn read_font_header<T: Band>(band: &mut T, record: &OffsetTableRecord) -> Result<FontHeader> {
    const MAGIC_NUMBER: ULONG = 0x5F0F3CF5;
    const VERSION_1_0: Fixed = Fixed(0x00010000);

    if !try!(record.check(band, |i, chunk| if i == 2 { 0 } else { chunk })) {
        raise!("the font header is corrupted");
    }
    try!(band.jump(record.offset as u64));

    let table = try!(FontHeader::read(band));
    if table.version != VERSION_1_0 {
        raise!("the format of the font header is not supported");
    }
    if table.magicNumber != MAGIC_NUMBER {
        raise!("the font header is malformed");
    }

    Ok(table)
}

fn read_horizontal_header<T: Band>(band: &mut T, record: &OffsetTableRecord)
                                   -> Result<HorizontalHeader> {

    const VERSION_1_0: Fixed = Fixed(0x00010000);

    if !try!(record.check(band, |_, chunk| chunk)) {
        raise!("the horizontal header is corrupted");
    }
    try!(band.jump(record.offset as u64));

    let table = try!(HorizontalHeader::read(band));
    if table.version != VERSION_1_0 {
        raise!("the format of the horizontal header is not supported");
    }

    Ok(table)
}

fn read_horizontal_metrics<T: Band>(band: &mut T, record: &OffsetTableRecord,
                                    header: &HorizontalHeader, profile: &MaximumProfile)
                                    -> Result<HorizontalMetrics> {

    if !try!(record.check(band, |_, chunk| chunk)) {
        raise!("the horizontal metrics are corrupted");
    }
    try!(band.jump(record.offset as u64));

    Ok(try!(HorizontalMetrics::read(band, header, profile)))
}

fn read_maximum_profile<T: Band>(band: &mut T, record: &OffsetTableRecord)
                                 -> Result<MaximumProfile> {

    const VERSION_0_5: Fixed = Fixed(0x00005000);
    const VERSION_1_0: Fixed = Fixed(0x00010000);

    if !try!(record.check(band, |_, chunk| chunk)) {
        raise!("the maximum profile is corrupted");
    }
    try!(band.jump(record.offset as u64));

    Ok(match try!(band.peek::<Fixed>()) {
        VERSION_0_5 => MaximumProfile::Version05(try!(Value::read(band))),
        VERSION_1_0 => MaximumProfile::Version10(try!(Value::read(band))),
        _ => raise!("the format of the maximum profile is not supported"),
    })
}

fn read_postscript<T: Band>(band: &mut T, record: &OffsetTableRecord) -> Result<PostScript> {
    const VERSION_1_0: Fixed = Fixed(0x00010000);
    const VERSION_3_0: Fixed = Fixed(0x00030000);

    if !try!(record.check(band, |_, chunk| chunk)) {
        raise!("the PostScript information is corrupted");
    }
    try!(band.jump(record.offset as u64));

    Ok(match try!(band.peek::<Fixed>()) {
        VERSION_1_0 => PostScript::Version10(try!(Value::read(band))),
        VERSION_3_0 => PostScript::Version30(try!(Value::read(band))),
        _ => raise!("the format of the PostScript information is not supported"),
    })
}

fn read_windows_metrics<T: Band>(band: &mut T, record: &OffsetTableRecord)
                                 -> Result<WindowsMetrics> {

    if !try!(record.check(band, |_, chunk| chunk)) {
        raise!("the OS/2 and Windows metrics are corrupted");
    }
    try!(band.jump(record.offset as u64));

    Ok(match try!(band.peek::<USHORT>()) {
        3 => WindowsMetrics::Version3(try!(Value::read(band))),
        5 => WindowsMetrics::Version5(try!(Value::read(band))),
        _ => raise!("the format of the OS/2 and Windows metrics is not supported"),
    })
}

fn priority(tag: &[u8; 4]) -> usize {
    use std::collections::HashMap;
    use std::sync::{Once, ONCE_INIT};

    unsafe {
        static mut PRIORITY: *const HashMap<[u8; 4], usize> = 0 as *const _;
        static ONCE: Once = ONCE_INIT;
        ONCE.call_once(|| {
            let mut map: HashMap<[u8; 4], usize> = HashMap::new();
            map.insert(*b"hmtx", 42);
            PRIORITY = mem::transmute(Box::new(map));
        });
        *(&*PRIORITY).get(tag).unwrap_or(&0)
    }
}
<commit_msg>Introduce verify_and_position!<commit_after>use std::io::{Read, Seek};
use std::mem;

use Result;
use band::{Band, Value};
use primitive::*;
use table::*;

/// A font.
pub struct Font {
    pub offset_table: OffsetTable,
    pub char_mapping: CharMapping,
    pub font_header: FontHeader,
    pub horizontal_header: HorizontalHeader,
    pub horizontal_metrics: HorizontalMetrics,
    pub maximum_profile: MaximumProfile,
    pub postscript: PostScript,
    pub windows_metrics: WindowsMetrics,
}

#[cfg(target_endian = "big")]
macro_rules! tag(
    ($value:expr) => (unsafe {
        mem::transmute::<_, [u8; 4]>($value)
    });
);

#[cfg(target_endian = "little")]
macro_rules! tag(
    ($value:expr) => (unsafe {
        let mut value = mem::transmute::<_, [u8; 4]>($value);
        value.reverse();
        value
    });
);

macro_rules! verify_and_position(
    ($record:ident, $band:ident, $table:expr, $process:expr) => ({
        if !try!($record.check($band, $process)) {
            raise!(concat!("the ", $table, " is corrupted"));
        }
        try!($band.jump($record.offset as u64));
    });
    ($record:ident, $band:ident, $table:expr) => (
        verify_and_position!($record, $band, $table, |_, word| word);
    );
);

impl Font {
    pub fn read<T: Read + Seek>(reader: &mut T) -> Result<Font> {
        macro_rules! some(
            ($option:expr, $table:expr) => (match $option {
                Some(value) => value,
                _ => raise!(concat!("the ", $table, " is missing")),
            });
        );

        macro_rules! sort(
            ($records:expr) => ({
                let mut records = $records.iter().collect::<Vec<_>>();
                records.sort_by(|one, two| {
                    priority(&tag!(one.tag)).cmp(&priority(&tag!(two.tag)))
                });
                records
            });
        );

        let offset_table = try!(read_offset_table(reader));

        let mut char_mapping = None;
        let mut font_header = None;
        let mut horizontal_header = None;
        let mut horizontal_metrics = None;
        let mut maximum_profile = None;
        let mut postscript = None;
        let mut windows_metrics = None;

        for record in sort!(offset_table.records) {
            match &tag!(record.tag) {
                b"cmap" => char_mapping = Some(try!(read_char_mapping(reader, record))),
                b"head" => font_header = Some(try!(read_font_header(reader, record))),
                b"hhea" => horizontal_header = Some(try!(read_horizontal_header(reader, record))),
                b"hmtx" => {
                    let header = some!(horizontal_header.as_ref(), "horizontal header");
                    let profile = some!(maximum_profile.as_ref(), "maximum profile");
                    horizontal_metrics = Some(try!(read_horizontal_metrics(reader, record, header,
                                                                           profile)));
                },
                b"maxp" => maximum_profile = Some(try!(read_maximum_profile(reader, record))),
                b"post" => postscript = Some(try!(read_postscript(reader, record))),
                b"OS/2" => windows_metrics = Some(try!(read_windows_metrics(reader, record))),
                _ => (),
            }
        }

        Ok(Font {
            offset_table: offset_table,
            char_mapping: some!(char_mapping, "character-to-glyph mapping"),
            font_header: some!(font_header, "font header"),
            horizontal_header: some!(horizontal_header, "horizontal header"),
            horizontal_metrics: some!(horizontal_metrics, "horizontal metrics"),
            maximum_profile: some!(maximum_profile, "maximum profile"),
            postscript: some!(postscript, "PostScript information"),
            windows_metrics: some!(windows_metrics, "OS/2 and Windows metrics"),
        })
    }
}

fn read_offset_table<T: Band>(band: &mut T) -> Result<OffsetTable> {
    const CFF_TAG: &'static [u8; 4] = b"OTTO";

    let header = try!(OffsetTableHeader::read(band));
    if &tag!(header.version) != CFF_TAG {
        raise!("the format of a font is not supported");
    }
    let mut records = vec![];
    for _ in 0..header.numTables {
        records.push(try!(OffsetTableRecord::read(band)));
    }

    Ok(OffsetTable { header: header, records: records })
}

fn read_char_mapping<T: Band>(band: &mut T, record: &OffsetTableRecord) -> Result<CharMapping> {
    const VERSION_0_0: USHORT = 0;

    verify_and_position!(record, band, "character-to-glyph mapping");
    let header = try!(CharMappingHeader::read(band));
    if header.version != VERSION_0_0 {
        raise!("the format of the character-to-glyph mapping header is not supported");
    }
    let mut records = vec![];
    for _ in 0..header.numTables {
        records.push(try!(CharMappingRecord::read(band)));
    }
    let mut encodings = vec![];
    for encoding in records.iter() {
        try!(band.jump(record.offset as u64 + encoding.offset as u64));
        encodings.push(match try!(band.peek::<USHORT>()) {
            4 => CharMappingEncoding::Format4(try!(Value::read(band))),
            6 => CharMappingEncoding::Format6(try!(Value::read(band))),
            _ => raise!("the format of a character-to-glyph mapping is not supported"),
        });
    }

    Ok(CharMapping { header: header, records: records, encodings: encodings })
}

fn read_font_header<T: Band>(band: &mut T, record: &OffsetTableRecord) -> Result<FontHeader> {
    const MAGIC_NUMBER: ULONG = 0x5F0F3CF5;
    const VERSION_1_0: Fixed = Fixed(0x00010000);

    verify_and_position!(record, band, "font header", |i, word| if i == 2 { 0 } else { word });
    let table = try!(FontHeader::read(band));
    if table.version != VERSION_1_0 {
        raise!("the format of the font header is not supported");
    }
    if table.magicNumber != MAGIC_NUMBER {
        raise!("the font header is malformed");
    }

    Ok(table)
}

fn read_horizontal_header<T: Band>(band: &mut T, record: &OffsetTableRecord)
                                   -> Result<HorizontalHeader> {

    const VERSION_1_0: Fixed = Fixed(0x00010000);

    verify_and_position!(record, band, "horizontal header");
    let table = try!(HorizontalHeader::read(band));
    if table.version != VERSION_1_0 {
        raise!("the format of the horizontal header is not supported");
    }

    Ok(table)
}

fn read_horizontal_metrics<T: Band>(band: &mut T, record: &OffsetTableRecord,
                                    header: &HorizontalHeader, profile: &MaximumProfile)
                                    -> Result<HorizontalMetrics> {

    verify_and_position!(record, band, "horizontal metrics");
    Ok(try!(HorizontalMetrics::read(band, header, profile)))
}

fn read_maximum_profile<T: Band>(band: &mut T, record: &OffsetTableRecord)
                                 -> Result<MaximumProfile> {

    const VERSION_0_5: Fixed = Fixed(0x00005000);
    const VERSION_1_0: Fixed = Fixed(0x00010000);

    verify_and_position!(record, band, "maximum profile");
    Ok(match try!(band.peek::<Fixed>()) {
        VERSION_0_5 => MaximumProfile::Version05(try!(Value::read(band))),
        VERSION_1_0 => MaximumProfile::Version10(try!(Value::read(band))),
        _ => raise!("the format of the maximum profile is not supported"),
    })
}

fn read_postscript<T: Band>(band: &mut T, record: &OffsetTableRecord) -> Result<PostScript> {
    const VERSION_1_0: Fixed = Fixed(0x00010000);
    const VERSION_3_0: Fixed = Fixed(0x00030000);

    verify_and_position!(record, band, "PostScript information");
    Ok(match try!(band.peek::<Fixed>()) {
        VERSION_1_0 => PostScript::Version10(try!(Value::read(band))),
        VERSION_3_0 => PostScript::Version30(try!(Value::read(band))),
        _ => raise!("the format of the PostScript information is not supported"),
    })
}

fn read_windows_metrics<T: Band>(band: &mut T, record: &OffsetTableRecord)
                                 -> Result<WindowsMetrics> {

    verify_and_position!(record, band, "OS/2 and Windows metrics");
    Ok(match try!(band.peek::<USHORT>()) {
        3 => WindowsMetrics::Version3(try!(Value::read(band))),
        5 => WindowsMetrics::Version5(try!(Value::read(band))),
        _ => raise!("the format of the OS/2 and Windows metrics is not supported"),
    })
}

fn priority(tag: &[u8; 4]) -> usize {
    use std::collections::HashMap;
    use std::sync::{Once, ONCE_INIT};

    unsafe {
        static mut PRIORITY: *const HashMap<[u8; 4], usize> = 0 as *const _;
        static ONCE: Once = ONCE_INIT;
        ONCE.call_once(|| {
            let mut map: HashMap<[u8; 4], usize> = HashMap::new();
            map.insert(*b"hmtx", 42);
            PRIORITY = mem::transmute(Box::new(map));
        });
        *(&*PRIORITY).get(tag).unwrap_or(&0)
    }
}
<|endoftext|>


<commit_before>use mul_reader::MulReader;
use color::Color16;
use std::io::{Result, Error, ErrorKind, Cursor, SeekFrom, Seek, Write, Read};
use std::fs::File;
use byteorder::{LittleEndian, ReadBytesExt};
use std::path::Path;

#[cfg(feature = "use-sdl2")]
use sdl2::surface::Surface;
#[cfg(feature = "use-sdl2")]
use sdl2::pixels::PixelFormatEnum;
#[cfg(feature = "use-sdl2")]
use utils::{SURFACE_ERROR};

#[derive(Clone, Copy)]
pub struct GumpPair {
    color: Color16,
    count: u16
}

#[derive(Clone)]
pub struct Gump {
    width: u16,
    height: u16,
    data: Vec<Vec<GumpPair>>
}

impl Gump {

    #[cfg(feature = "use-sdl2")]
    pub fn to_surface(&self) -> Surface {
        let mut surface = Surface::new(self.width as u32, self.height as u32, PixelFormatEnum::RGBA8888).expect(SURFACE_ERROR);
        surface.with_lock_mut(|bitmap| {
            let mut read_idx = 0;

            for y in 0..self.height {
            };
        });
        surface
    }
}

pub struct GumpReader<T: Read + Seek> {
    mul_reader: MulReader<T>
}

impl GumpReader<File> {

    pub fn new(index_path: &Path, mul_path: &Path) -> Result<GumpReader<File>> {
        let mul_reader = try!(MulReader::new(index_path, mul_path));
        Ok(GumpReader {
            mul_reader: mul_reader
        })
    }
}

impl<T: Read + Seek> GumpReader<T> {

    pub fn read_gump(&mut self, index: u32) -> Result<Gump> {
        let raw = try!(self.mul_reader.read(index));
        let mut output = vec![];
        let len = raw.data.len();
        assert!(len % 4 == 0);
        let mut reader = Cursor::new(raw.data);
        let mut row_offsets = vec![];
        // Load all of our offsets
        for _i in 0..raw.opt1 {
            row_offsets.push(try!(reader.read_u32::<LittleEndian>()));
        }
        // Unsure if the offset is from start of file, or start of data

        // FIXME: The RLE stuff in here and in art should probably be abstracted
        for (row_idx, offset) in row_offsets.iter().enumerate() {
            let row_length = if row_idx == row_offsets.len() - 1 {
                (len / 4) as u32 - offset
            } else {
                let next_row = row_offsets[row_idx + 1];
                next_row - offset
            };
            try!(reader.seek(SeekFrom::Start((*offset as u64) * 4)));
            let mut row = vec![];
            for _i in 0..row_length {
                let color = try!(reader.read_u16::<LittleEndian>());
                let count = try!(reader.read_u16::<LittleEndian>());
                row.push(GumpPair {
                    color: color,
                    count: count
                });
            };
            output.push(row);
        }
        Ok(Gump {
            height: raw.opt1,
            width: raw.opt2,
            data: output
        })
    }
}
<commit_msg>Gump printing<commit_after>use mul_reader::MulReader;
use color::{Color16, Color};
use std::io::{Result, Error, ErrorKind, Cursor, SeekFrom, Seek, Write, Read};
use std::fs::File;
use byteorder::{LittleEndian, ReadBytesExt};
use std::path::Path;

#[cfg(feature = "use-sdl2")]
use sdl2::surface::Surface;
#[cfg(feature = "use-sdl2")]
use sdl2::pixels::PixelFormatEnum;
#[cfg(feature = "use-sdl2")]
use utils::{SURFACE_ERROR};

#[derive(Clone, Copy)]
pub struct GumpPair {
    color: Color16,
    count: u16
}

#[derive(Clone)]
pub struct Gump {
    width: u16,
    height: u16,
    data: Vec<Vec<GumpPair>>
}

impl Gump {

    #[cfg(feature = "use-sdl2")]
    pub fn to_surface(&self) -> Surface {
        let mut surface = Surface::new(self.width as u32, self.height as u32, PixelFormatEnum::RGBA8888).expect(SURFACE_ERROR);
        let mut surface_target: usize = 0;

        surface.with_lock_mut(|bitmap| {
            for row in self.data.iter() {
                let mut current_width = 0;
                for run_pair in row {
                    let (r, g, b, a) = run_pair.color.to_rgba();

                    for _i in 0..run_pair.count {
                        bitmap[surface_target] = a;
                        bitmap[surface_target + 1] = b;
                        bitmap[surface_target + 2] = g;
                        bitmap[surface_target + 3] = r;
                        surface_target += 4;
                        current_width += 1;
                    }
                    assert!(current_width <= self.width)
                }
                if current_width < self.width {
                    surface_target += (self.width - current_width) as usize * 4;
                }
            };
        });
        surface
    }
}

pub struct GumpReader<T: Read + Seek> {
    mul_reader: MulReader<T>
}

impl GumpReader<File> {

    pub fn new(index_path: &Path, mul_path: &Path) -> Result<GumpReader<File>> {
        let mul_reader = try!(MulReader::new(index_path, mul_path));
        Ok(GumpReader {
            mul_reader: mul_reader
        })
    }
}

impl<T: Read + Seek> GumpReader<T> {

    pub fn read_gump(&mut self, index: u32) -> Result<Gump> {
        let raw = try!(self.mul_reader.read(index));
        let mut output = vec![];
        let len = raw.data.len();
        assert!(len % 4 == 0);
        let mut reader = Cursor::new(raw.data);
        let mut row_offsets = vec![];
        // Load all of our offsets
        for _i in 0..raw.opt1 {
            row_offsets.push(try!(reader.read_u32::<LittleEndian>()));
        }
        // Unsure if the offset is from start of file, or start of data

        // FIXME: The RLE stuff in here and in art should probably be abstracted
        for (row_idx, offset) in row_offsets.iter().enumerate() {
            let row_length = if row_idx == row_offsets.len() - 1 {
                (len / 4) as u32 - offset
            } else {
                let next_row = row_offsets[row_idx + 1];
                next_row - offset
            };
            try!(reader.seek(SeekFrom::Start((*offset as u64) * 4)));
            let mut row = vec![];
            for _i in 0..row_length {
                let color = try!(reader.read_u16::<LittleEndian>());
                let count = try!(reader.read_u16::<LittleEndian>());
                row.push(GumpPair {
                    color: color,
                    count: count
                });
            };
            output.push(row);
        }
        Ok(Gump {
            height: raw.opt1,
            width: raw.opt2,
            data: output
        })
    }
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use flate2::read::GzDecoder;

use error::Result;

pub fn uncompress<T: Read>(src: T) -> Result<Vec<u8>> {
    let mut d = try!(GzDecoder::new(src));

    let mut buffer: Vec<u8> = Vec::new();
    match d.read_to_end(&mut buffer) {
        Err(err) =>  Err(From::from(err)),
        Ok(_) => Ok(buffer)
    }
}
<commit_msg>gzip uncompress<commit_after>use std::io::prelude::*;
use flate2::read::GzDecoder;

use error::Result;

pub fn uncompress<T: Read>(src: T) -> Result<Vec<u8>> {
    let mut d = try!(GzDecoder::new(src));

    let mut buffer: Vec<u8> = Vec::new();
    match d.read_to_end(&mut buffer) {
        Err(err) =>  Err(From::from(err)),
        Ok(_) => Ok(buffer)
    }
}

#[test]
fn test_uncompress() {
    use std::io::Cursor;
    // The vector should uncompress to "test"
    let msg: Vec<u8> = vec!(31, 139, 8, 0, 192, 248, 79, 85, 2, 255, 43, 73, 45, 46, 1, 0, 12, 126, 127, 216, 4, 0, 0, 0);
    let uncomp_msg = String::from_utf8(uncompress(Cursor::new(msg)).unwrap()).unwrap();
    assert_eq!(&uncomp_msg[..], "test");
}

#[test]
#[should_panic]
fn test_uncompress_panic() {
    use std::io::Cursor;
    let msg: Vec<u8> = vec!(12, 42, 84, 104, 105, 115, 32, 105, 115, 32, 116, 101, 115, 116);
    let uncomp_msg = String::from_utf8(uncompress(Cursor::new(msg)).unwrap()).unwrap();
    assert_eq!(&uncomp_msg[..], "This is test");
}
<|endoftext|>


<commit_before>use std::mem::size_of_val;
use std::ptr::null_mut;

use libc::funcs::c95::stdlib::{free, malloc};
use libc::{c_void, size_t};

use util::{MIN_MATCH, WINDOW_MASK};

pub struct Hash {
    /// Hash value to index of its most recent occurrence.
    pub head: *mut i32,
    /// Index to index of prev. occurrence of same hash.
    pub prev: *mut u16,
    /// Index to hash value at this index.
    pub hashval: *mut i32,
    /// Current hash value.
    pub val: i32,

    pub hash_same_hash: HashSameHash,
    pub hash_same: HashSame,
}

#[cfg(not(feature = "hash-same-hash"))]
pub struct HashSameHash;

#[cfg(feature = "hash-same-hash")]
/// Fields with similar purpose as the above hash, but for the second hash with
/// a value that is calculated differently.
pub struct HashSameHash {
    /// Hash value to index of its most recent occurrence.
    pub head2: *mut i32,
    /// Index to index of prev. occurrence of same hash.
    pub prev2: *mut u16,
    /// Index to hash value at this index.
    pub hashval2: *mut i32,
    /// Current hash value.
    pub val2: i32,
}

impl HashSameHash {
    #[cfg(not(feature = "hash-same-hash"))]
    fn new(_window_size: usize) -> HashSameHash {
        HashSameHash
    }

    #[cfg(feature = "hash-same-hash")]
    unsafe fn new(window_size: usize) -> HashSameHash {
        let mut head2: *mut i32 = null_mut();
        head2 = malloc(size_of_val(&*head2) as size_t * 65536) as *mut i32;
        let mut prev2: *mut u16 = null_mut();
        prev2 = malloc((size_of_val(&*prev2) * window_size) as size_t) as *mut u16;
        let mut hashval2: *mut i32 = null_mut();
        hashval2 = malloc((size_of_val(&*hashval2) * window_size) as size_t) as *mut i32;
        for i in 0..65536 {
            *head2.offset(i) = -1;
        }
        for i in 0..window_size {
            *prev2.offset(i as isize) = i as u16;
            *hashval2.offset(i as isize) = -1;
        }

        HashSameHash {
            head2: head2,
            prev2: prev2,
            hashval2: hashval2,
            val2: 0,
        }
    }

    #[cfg(not(feature = "hash-same-hash"))]
    fn clean(_h: *const HashSameHash) { }

    #[cfg(feature = "hash-same-hash")]
    unsafe fn clean(h: *const HashSameHash) {
        free((*h).head2 as *mut c_void);
        free((*h).prev2 as *mut c_void);
        free((*h).hashval2 as *mut c_void);
    }
}

#[cfg(not(feature = "hash-same"))]
pub struct HashSame;

#[cfg(feature = "hash-same")]
pub struct HashSame {
    /// Amount of repetitions of same byte after this.
    pub same: *mut u16,
}

impl HashSame {
    #[cfg(not(feature = "hash-same"))]
    fn new(_window_size: usize) -> HashSame {
        HashSame
    }

    #[cfg(feature = "hash-same")]
    unsafe fn new(window_size: usize) -> HashSame {
        let mut same: *mut u16 = null_mut();
        same = malloc((size_of_val(&*same) * window_size) as size_t) as *mut u16;
        for i in 0..window_size {
            *same.offset(i as isize) = 0;
        }
        HashSame {
            same: same
        }
    }

    #[cfg(not(feature = "hash-same"))]
    fn clean(_h: *const HashSame) { }

    #[cfg(feature = "hash-same")]
    unsafe fn clean(h: *const HashSame) {
        free((*h).same as *mut c_void);
    }
}

const HASH_SHIFT: u32 = 5;
const HASH_MASK: i32 = 32767;

impl Hash {
    pub unsafe fn new(window_size: usize) -> Hash {
        let mut head: *mut i32 = null_mut();
        head = malloc(size_of_val(&*head) as size_t * 65536) as *mut i32;
        let mut prev: *mut u16 = null_mut();
        prev = malloc((size_of_val(&*prev) * window_size) as size_t) as *mut u16;
        let mut hashval: *mut i32 = null_mut();
        hashval = malloc((size_of_val(&*hashval) * window_size) as size_t) as *mut i32;

        for i in 0..65536 {
            // -1 indicates no head so far.
            *head.offset(i) = -1;
        }
        for i in 0..window_size {
            // If prev[j] == j, then prev[j] is uninitialized.
            *prev.offset(i as isize) = i as u16;
            *hashval.offset(i as isize) = -1;
        }

        Hash {
            head: head,
            prev: prev,
            hashval: hashval,
            val: 0,
            hash_same: HashSame::new(window_size),
            hash_same_hash: HashSameHash::new(window_size),
        }
    }

    pub unsafe fn clean(h: *mut Hash) {
        free((*h).head as *mut c_void);
        free((*h).prev as *mut c_void);
        free((*h).hashval as *mut c_void);

        HashSameHash::clean(&(*h).hash_same_hash as *const _);
        HashSame::clean(&(*h).hash_same as *const _);
    }
}

/// Update the sliding hash value with the given byte. All calls to this function
/// must be made on consecutive input characters. Since the hash value exists out
/// of multiple input bytes, a few warmups with this function are needed initially.
unsafe fn update_hash_value(h: *mut Hash, c: u8) {
    (*h).val = (((*h).val << HASH_SHIFT) ^ c as i32) & HASH_MASK;
}

#[cfg(not(feature = "hash-same"))]
fn update_hash_same(_array: *const u8, _pos: usize, _end: usize, _hpos: u16, _h: *mut Hash) { }

#[cfg(feature = "hash-same")]
unsafe fn update_hash_same(array: *const u8, pos: usize, end: usize, hpos: u16, h: *mut Hash) {
    let mut amount: usize = 0;
    if *(*h).hash_same.same.offset((pos as isize - 1) & WINDOW_MASK as isize) > 1 {
        amount = (*(*h).hash_same.same.offset(((pos - 1) & WINDOW_MASK) as isize) - 1) as usize;
    }
    while pos + amount + 1 < end && *array.offset(pos as isize) == *array.offset((pos + amount + 1) as isize) && amount < !0u16 as usize {
        amount += 1;
    }
    *(*h).hash_same.same.offset(hpos as isize) = amount as u16;
}

#[cfg(not(feature = "hash-same-hash"))]
fn update_hash_same_hash(_hpos: u16, _h: *mut Hash) { }

#[cfg(feature = "hash-same-hash")]
unsafe fn update_hash_same_hash(hpos: u16, h: *mut Hash) {
    (*h).hash_same_hash.val2 = ((*(*h).hash_same.same.offset(hpos as isize) as i32 - MIN_MATCH as i32) & 255) ^ (*h).val;
    *(*h).hash_same_hash.hashval2.offset(hpos as isize) = (*h).hash_same_hash.val2;
    if *(*h).hash_same_hash.head2.offset((*h).hash_same_hash.val2 as isize) != -1 && *(*h).hash_same_hash.hashval2.offset(*(*h).hash_same_hash.head2.offset((*h).hash_same_hash.val2 as isize) as isize) == (*h).hash_same_hash.val2 {
        *(*h).hash_same_hash.prev2.offset(hpos as isize) = *(*h).hash_same_hash.head2.offset((*h).hash_same_hash.val2 as isize) as u16;
    } else {
        *(*h).hash_same_hash.prev2.offset(hpos as isize) = hpos;
    }
    *(*h).hash_same_hash.head2.offset((*h).hash_same_hash.val2 as isize) = hpos as i32;
}

pub unsafe fn update_hash(array: *const u8, pos: usize, end: usize, h: *mut Hash) {
    let hpos: u16 = pos as u16 & WINDOW_MASK as u16;
    update_hash_value(h, if pos + MIN_MATCH <= end { *array.offset(pos as isize + MIN_MATCH as isize - 1) } else { 0 });
    *(*h).hashval.offset(hpos as isize) = (*h).val;
    if *(*h).head.offset((*h).val as isize) != -1 && *(*h).hashval.offset(*(*h).head.offset((*h).val as isize) as isize) == (*h).val {
        *(*h).prev.offset(hpos as isize) = *(*h).head.offset((*h).val as isize) as u16;
    } else {
        *(*h).prev.offset(hpos as isize) = hpos;
    }
    *(*h).head.offset((*h).val as isize) = hpos as i32;

    update_hash_same(array, pos, end, hpos, h);
    update_hash_same_hash(hpos, h);
}

pub unsafe fn warmup_hash(array: *const u8, pos: usize, _end: usize, h: *mut Hash) {
    update_hash_value(h, *array.offset(pos as isize + 0));
    update_hash_value(h, *array.offset(pos as isize + 1));
}
<commit_msg>Fix invalid read when compressing a 1 byte file<commit_after>use std::mem::size_of_val;
use std::ptr::null_mut;

use libc::funcs::c95::stdlib::{free, malloc};
use libc::{c_void, size_t};

use util::{MIN_MATCH, WINDOW_MASK};

pub struct Hash {
    /// Hash value to index of its most recent occurrence.
    pub head: *mut i32,
    /// Index to index of prev. occurrence of same hash.
    pub prev: *mut u16,
    /// Index to hash value at this index.
    pub hashval: *mut i32,
    /// Current hash value.
    pub val: i32,

    pub hash_same_hash: HashSameHash,
    pub hash_same: HashSame,
}

#[cfg(not(feature = "hash-same-hash"))]
pub struct HashSameHash;

#[cfg(feature = "hash-same-hash")]
/// Fields with similar purpose as the above hash, but for the second hash with
/// a value that is calculated differently.
pub struct HashSameHash {
    /// Hash value to index of its most recent occurrence.
    pub head2: *mut i32,
    /// Index to index of prev. occurrence of same hash.
    pub prev2: *mut u16,
    /// Index to hash value at this index.
    pub hashval2: *mut i32,
    /// Current hash value.
    pub val2: i32,
}

impl HashSameHash {
    #[cfg(not(feature = "hash-same-hash"))]
    fn new(_window_size: usize) -> HashSameHash {
        HashSameHash
    }

    #[cfg(feature = "hash-same-hash")]
    unsafe fn new(window_size: usize) -> HashSameHash {
        let mut head2: *mut i32 = null_mut();
        head2 = malloc(size_of_val(&*head2) as size_t * 65536) as *mut i32;
        let mut prev2: *mut u16 = null_mut();
        prev2 = malloc((size_of_val(&*prev2) * window_size) as size_t) as *mut u16;
        let mut hashval2: *mut i32 = null_mut();
        hashval2 = malloc((size_of_val(&*hashval2) * window_size) as size_t) as *mut i32;
        for i in 0..65536 {
            *head2.offset(i) = -1;
        }
        for i in 0..window_size {
            *prev2.offset(i as isize) = i as u16;
            *hashval2.offset(i as isize) = -1;
        }

        HashSameHash {
            head2: head2,
            prev2: prev2,
            hashval2: hashval2,
            val2: 0,
        }
    }

    #[cfg(not(feature = "hash-same-hash"))]
    fn clean(_h: *const HashSameHash) { }

    #[cfg(feature = "hash-same-hash")]
    unsafe fn clean(h: *const HashSameHash) {
        free((*h).head2 as *mut c_void);
        free((*h).prev2 as *mut c_void);
        free((*h).hashval2 as *mut c_void);
    }
}

#[cfg(not(feature = "hash-same"))]
pub struct HashSame;

#[cfg(feature = "hash-same")]
pub struct HashSame {
    /// Amount of repetitions of same byte after this.
    pub same: *mut u16,
}

impl HashSame {
    #[cfg(not(feature = "hash-same"))]
    fn new(_window_size: usize) -> HashSame {
        HashSame
    }

    #[cfg(feature = "hash-same")]
    unsafe fn new(window_size: usize) -> HashSame {
        let mut same: *mut u16 = null_mut();
        same = malloc((size_of_val(&*same) * window_size) as size_t) as *mut u16;
        for i in 0..window_size {
            *same.offset(i as isize) = 0;
        }
        HashSame {
            same: same
        }
    }

    #[cfg(not(feature = "hash-same"))]
    fn clean(_h: *const HashSame) { }

    #[cfg(feature = "hash-same")]
    unsafe fn clean(h: *const HashSame) {
        free((*h).same as *mut c_void);
    }
}

const HASH_SHIFT: u32 = 5;
const HASH_MASK: i32 = 32767;

impl Hash {
    pub unsafe fn new(window_size: usize) -> Hash {
        let mut head: *mut i32 = null_mut();
        head = malloc(size_of_val(&*head) as size_t * 65536) as *mut i32;
        let mut prev: *mut u16 = null_mut();
        prev = malloc((size_of_val(&*prev) * window_size) as size_t) as *mut u16;
        let mut hashval: *mut i32 = null_mut();
        hashval = malloc((size_of_val(&*hashval) * window_size) as size_t) as *mut i32;

        for i in 0..65536 {
            // -1 indicates no head so far.
            *head.offset(i) = -1;
        }
        for i in 0..window_size {
            // If prev[j] == j, then prev[j] is uninitialized.
            *prev.offset(i as isize) = i as u16;
            *hashval.offset(i as isize) = -1;
        }

        Hash {
            head: head,
            prev: prev,
            hashval: hashval,
            val: 0,
            hash_same: HashSame::new(window_size),
            hash_same_hash: HashSameHash::new(window_size),
        }
    }

    pub unsafe fn clean(h: *mut Hash) {
        free((*h).head as *mut c_void);
        free((*h).prev as *mut c_void);
        free((*h).hashval as *mut c_void);

        HashSameHash::clean(&(*h).hash_same_hash as *const _);
        HashSame::clean(&(*h).hash_same as *const _);
    }
}

/// Update the sliding hash value with the given byte. All calls to this function
/// must be made on consecutive input characters. Since the hash value exists out
/// of multiple input bytes, a few warmups with this function are needed initially.
unsafe fn update_hash_value(h: *mut Hash, c: u8) {
    (*h).val = (((*h).val << HASH_SHIFT) ^ c as i32) & HASH_MASK;
}

#[cfg(not(feature = "hash-same"))]
fn update_hash_same(_array: *const u8, _pos: usize, _end: usize, _hpos: u16, _h: *mut Hash) { }

#[cfg(feature = "hash-same")]
unsafe fn update_hash_same(array: *const u8, pos: usize, end: usize, hpos: u16, h: *mut Hash) {
    let mut amount: usize = 0;
    if *(*h).hash_same.same.offset((pos as isize - 1) & WINDOW_MASK as isize) > 1 {
        amount = (*(*h).hash_same.same.offset(((pos - 1) & WINDOW_MASK) as isize) - 1) as usize;
    }
    while pos + amount + 1 < end && *array.offset(pos as isize) == *array.offset((pos + amount + 1) as isize) && amount < !0u16 as usize {
        amount += 1;
    }
    *(*h).hash_same.same.offset(hpos as isize) = amount as u16;
}

#[cfg(not(feature = "hash-same-hash"))]
fn update_hash_same_hash(_hpos: u16, _h: *mut Hash) { }

#[cfg(feature = "hash-same-hash")]
unsafe fn update_hash_same_hash(hpos: u16, h: *mut Hash) {
    (*h).hash_same_hash.val2 = ((*(*h).hash_same.same.offset(hpos as isize) as i32 - MIN_MATCH as i32) & 255) ^ (*h).val;
    *(*h).hash_same_hash.hashval2.offset(hpos as isize) = (*h).hash_same_hash.val2;
    if *(*h).hash_same_hash.head2.offset((*h).hash_same_hash.val2 as isize) != -1 && *(*h).hash_same_hash.hashval2.offset(*(*h).hash_same_hash.head2.offset((*h).hash_same_hash.val2 as isize) as isize) == (*h).hash_same_hash.val2 {
        *(*h).hash_same_hash.prev2.offset(hpos as isize) = *(*h).hash_same_hash.head2.offset((*h).hash_same_hash.val2 as isize) as u16;
    } else {
        *(*h).hash_same_hash.prev2.offset(hpos as isize) = hpos;
    }
    *(*h).hash_same_hash.head2.offset((*h).hash_same_hash.val2 as isize) = hpos as i32;
}

pub unsafe fn update_hash(array: *const u8, pos: usize, end: usize, h: *mut Hash) {
    let hpos: u16 = pos as u16 & WINDOW_MASK as u16;
    update_hash_value(h, if pos + MIN_MATCH <= end { *array.offset(pos as isize + MIN_MATCH as isize - 1) } else { 0 });
    *(*h).hashval.offset(hpos as isize) = (*h).val;
    if *(*h).head.offset((*h).val as isize) != -1 && *(*h).hashval.offset(*(*h).head.offset((*h).val as isize) as isize) == (*h).val {
        *(*h).prev.offset(hpos as isize) = *(*h).head.offset((*h).val as isize) as u16;
    } else {
        *(*h).prev.offset(hpos as isize) = hpos;
    }
    *(*h).head.offset((*h).val as isize) = hpos as i32;

    update_hash_same(array, pos, end, hpos, h);
    update_hash_same_hash(hpos, h);
}

pub unsafe fn warmup_hash(array: *const u8, pos: usize, end: usize, h: *mut Hash) {
    update_hash_value(h, *array.offset(pos as isize + 0));
    if pos + 1 < end {
        update_hash_value(h, *array.offset(pos as isize + 1));
    }
}
<|endoftext|>


<commit_before>use moka::future::Cache;
use std::time::Duration;
use tide::{
    http::{
        content::{AcceptEncoding, ContentEncoding, Encoding},
        headers::{HeaderName, HeaderValues},
        Method, Mime,
    },
    Body, Middleware, Next, Request, Response, StatusCode,
};
use wildmatch::WildMatch;

use crate::common::{is_inline_css, log_access};

#[derive(Clone)]
pub struct CacheMiddleware {
    cache: Cache<String, (StatusCode, Mime, Vec<u8>, Vec<(HeaderName, HeaderValues)>)>,
    skip_cache_wildmatch: Option<Vec<WildMatch>>,
    inline_css_wildmatch: Option<Vec<WildMatch>>,
    inline_css_skip_domain_wildmatch: Option<Vec<WildMatch>>,
}

pub fn create_cache(
    cache_ttl_sec: Option<u64>,
    cache_tti_sec: Option<u64>,
) -> Option<Cache<String, (StatusCode, Mime, Vec<u8>, Vec<(HeaderName, HeaderValues)>)>> {
    let ttl_sec = cache_ttl_sec?;
    let tti_sec = cache_tti_sec?;
    log::info!(
        "Creating cache with time-to-live: {}s and time-to-idle: {}s",
        &ttl_sec,
        &tti_sec,
    );

    Some(
        Cache::builder()
            .time_to_live(Duration::from_secs(ttl_sec))
            .time_to_idle(Duration::from_secs(tti_sec))
            .build(),
    )
}

impl CacheMiddleware {
    pub fn new(
        prefix: String,
        cache: Cache<String, (StatusCode, Mime, Vec<u8>, Vec<(HeaderName, HeaderValues)>)>,
        skip_cache_path: Option<Vec<String>>,
        inline_css_wildmatch: Option<Vec<WildMatch>>,
        inline_css_skip_domain_wildmatch: Option<Vec<WildMatch>>,
    ) -> Self {
        log::info!("Setting up response cache for path {}", &prefix,);
        let skip_cache_wildmatch = match skip_cache_path {
            Some(skip_cache_path) => Some(
                skip_cache_path
                    .iter()
                    .map(|path| WildMatch::new(path))
                    .collect(),
            ),
            None => None,
        };

        Self {
            cache,
            skip_cache_wildmatch,
            inline_css_wildmatch,
            inline_css_skip_domain_wildmatch,
        }
    }
}

#[tide::utils::async_trait]
impl<State: Clone + Send + Sync + 'static> Middleware<State> for CacheMiddleware {
    async fn handle(&self, req: Request<State>, next: Next<'_, State>) -> tide::Result {
        let url_path: String = req.url().path().to_string();
        let method = &req.method();
        let skip_cache: bool = {
            if method != &Method::Get {
                true
            } else {
                match &self.skip_cache_wildmatch {
                    Some(skip_cache_wildmatch) => skip_cache_wildmatch
                        .iter()
                        .find(|wildmatch_path| wildmatch_path.matches(&url_path))
                        .is_some(),
                    None => false,
                }
            }
        };
        let mut inline_css = false;
        let cache_key: Option<String> = if skip_cache {
            None
        } else {
            let accepts = AcceptEncoding::from_headers(&req)?;
            let encoding: String = if let Some(mut accepts) = accepts {
                let encoding =
                    accepts.negotiate(&[Encoding::Brotli, Encoding::Gzip, Encoding::Deflate])?;
                encoding.to_string()
            } else {
                "".to_string()
            };
            inline_css = is_inline_css(
                &url_path,
                req.header("Referer"),
                &self.inline_css_wildmatch,
                &self.inline_css_skip_domain_wildmatch,
            );

            Some(get_cache_key(&url_path, &encoding, inline_css))
        };

        if let Some(cache_key) = &cache_key {
            // Try to find this request from the cache
            let cached_response = &self.cache.get(&cache_key.clone());
            if let Some((status, mime, body_as_bytes, headers)) = cached_response {
                log::debug!("Cache hit: {}", cache_key);
                let mut body = Body::from_bytes(body_as_bytes.to_vec());
                body.set_mime(mime.clone());
                let mut res_builder = Response::builder(status.clone()).body(body);
                for (header_name, header_values) in headers {
                    res_builder = res_builder.header(header_name, header_values);
                }
                log_access(method, &url_path, &status.to_string(), Some("cached"));
                return Ok(res_builder.build());
            }
        }

        let mut res: Response = next.run(req).await;
        if let Some(cache_key) = cache_key {
            let status = res.status();
            if !status.is_success() {
                return Ok(res);
            }
            let response_encoding =
                if let Some(response_encoding) = ContentEncoding::from_headers(&res).unwrap() {
                    response_encoding.to_string()
                } else {
                    "".to_string()
                };
            let response_cache_key = get_cache_key(&url_path, &response_encoding, inline_css);
            if response_cache_key != cache_key {
                // For some reason tide_compress didn't encode the way we thought it would
                log::error!(
                    "Encoding mismatch with cache, expected: '{}' but was '{}'",
                    &cache_key,
                    response_cache_key
                );
                return Ok(res);
            }

            log::debug!("Cache_miss: {}", cache_key);
            let cache_headers: Vec<(HeaderName, HeaderValues)> = res
                .iter()
                .map(|(header_name, header_values)| (header_name.clone(), header_values.clone()))
                .collect();
            let body = res.take_body();
            let mime = body.mime().clone();
            let body_as_bytes = body.into_bytes().await.unwrap();

            self.cache
                .insert(
                    cache_key,
                    (status, mime.clone(), body_as_bytes.clone(), cache_headers),
                )
                .await;
            let mut body = Body::from_bytes(body_as_bytes);
            body.set_mime(mime.clone());
            res.set_body(body);
            Ok(res)
        } else {
            // There is no caching for this request, just return the response we got
            log::debug!("Skip cache: {}", url_path);
            Ok(res)
        }
    }
}

fn get_cache_key(url_path: &str, encoding: &str, inline_css: bool) -> String {
    format!("{} {} {}", url_path, encoding, inline_css)
}
<commit_msg>Hack to cache correctly image/avif. Needs a better long-term plan.<commit_after>use moka::future::Cache;
use std::time::Duration;
use tide::{
    http::{
        content::{AcceptEncoding, ContentEncoding, Encoding},
        headers::{HeaderName, HeaderValues},
        Method, Mime,
    },
    Body, Middleware, Next, Request, Response, StatusCode,
};
use wildmatch::WildMatch;

use crate::common::{is_inline_css, log_access};

#[derive(Clone)]
pub struct CacheMiddleware {
    cache: Cache<String, (StatusCode, Mime, Vec<u8>, Vec<(HeaderName, HeaderValues)>)>,
    skip_cache_wildmatch: Option<Vec<WildMatch>>,
    inline_css_wildmatch: Option<Vec<WildMatch>>,
    inline_css_skip_domain_wildmatch: Option<Vec<WildMatch>>,
}

pub fn create_cache(
    cache_ttl_sec: Option<u64>,
    cache_tti_sec: Option<u64>,
) -> Option<Cache<String, (StatusCode, Mime, Vec<u8>, Vec<(HeaderName, HeaderValues)>)>> {
    let ttl_sec = cache_ttl_sec?;
    let tti_sec = cache_tti_sec?;
    log::info!(
        "Creating cache with time-to-live: {}s and time-to-idle: {}s",
        &ttl_sec,
        &tti_sec,
    );

    Some(
        Cache::builder()
            .time_to_live(Duration::from_secs(ttl_sec))
            .time_to_idle(Duration::from_secs(tti_sec))
            .build(),
    )
}

impl CacheMiddleware {
    pub fn new(
        prefix: String,
        cache: Cache<String, (StatusCode, Mime, Vec<u8>, Vec<(HeaderName, HeaderValues)>)>,
        skip_cache_path: Option<Vec<String>>,
        inline_css_wildmatch: Option<Vec<WildMatch>>,
        inline_css_skip_domain_wildmatch: Option<Vec<WildMatch>>,
    ) -> Self {
        log::info!("Setting up response cache for path {}", &prefix,);
        let skip_cache_wildmatch = match skip_cache_path {
            Some(skip_cache_path) => Some(
                skip_cache_path
                    .iter()
                    .map(|path| WildMatch::new(path))
                    .collect(),
            ),
            None => None,
        };

        Self {
            cache,
            skip_cache_wildmatch,
            inline_css_wildmatch,
            inline_css_skip_domain_wildmatch,
        }
    }
}

#[tide::utils::async_trait]
impl<State: Clone + Send + Sync + 'static> Middleware<State> for CacheMiddleware {
    async fn handle(&self, req: Request<State>, next: Next<'_, State>) -> tide::Result {
        let url_path: String = req.url().path().to_string();
        let method = &req.method();
        let skip_cache: bool = {
            if method != &Method::Get {
                true
            } else {
                match &self.skip_cache_wildmatch {
                    Some(skip_cache_wildmatch) => skip_cache_wildmatch
                        .iter()
                        .find(|wildmatch_path| wildmatch_path.matches(&url_path))
                        .is_some(),
                    None => false,
                }
            }
        };
        let mut inline_css = false;
        let cache_key: Option<String> = if skip_cache {
            None
        } else {
            let accepts = AcceptEncoding::from_headers(&req)?;

            let encoding: String = if let Some(mut accepts) = accepts {
                // TODO: tide-compress uses
                // https://github.com/jshttp/mime-db/blob/master/db.json
                // to find out if a mime type is compressible or not.
                // Just fixing this for image/avif is a short-term hack.
                if url_path.ends_with(".avif") {
                    "".to_string()
                } else {
                    let encoding = accepts.negotiate(&[
                        Encoding::Brotli,
                        Encoding::Gzip,
                        Encoding::Deflate,
                    ])?;
                    encoding.to_string()
                }
            } else {
                "".to_string()
            };
            inline_css = is_inline_css(
                &url_path,
                req.header("Referer"),
                &self.inline_css_wildmatch,
                &self.inline_css_skip_domain_wildmatch,
            );

            Some(get_cache_key(&url_path, &encoding, inline_css))
        };

        if let Some(cache_key) = &cache_key {
            // Try to find this request from the cache
            let cached_response = &self.cache.get(&cache_key.clone());
            if let Some((status, mime, body_as_bytes, headers)) = cached_response {
                log::debug!("Cache hit: {}", cache_key);
                let mut body = Body::from_bytes(body_as_bytes.to_vec());
                body.set_mime(mime.clone());
                let mut res_builder = Response::builder(status.clone()).body(body);
                for (header_name, header_values) in headers {
                    res_builder = res_builder.header(header_name, header_values);
                }
                log_access(method, &url_path, &status.to_string(), Some("cached"));
                return Ok(res_builder.build());
            }
        }

        let mut res: Response = next.run(req).await;
        if let Some(cache_key) = cache_key {
            let status = res.status();
            if !status.is_success() {
                return Ok(res);
            }
            let response_encoding =
                if let Some(response_encoding) = ContentEncoding::from_headers(&res).unwrap() {
                    response_encoding.to_string()
                } else {
                    "".to_string()
                };
            let response_cache_key = get_cache_key(&url_path, &response_encoding, inline_css);
            if response_cache_key != cache_key {
                // For some reason tide_compress didn't encode the way we thought it would
                log::error!(
                    "Encoding mismatch with cache, expected: '{}' but was '{}'",
                    &cache_key,
                    response_cache_key
                );
                return Ok(res);
            }

            log::debug!("Cache_miss: {}", cache_key);
            let cache_headers: Vec<(HeaderName, HeaderValues)> = res
                .iter()
                .map(|(header_name, header_values)| (header_name.clone(), header_values.clone()))
                .collect();
            let body = res.take_body();
            let mime = body.mime().clone();
            let body_as_bytes = body.into_bytes().await.unwrap();

            self.cache
                .insert(
                    cache_key,
                    (status, mime.clone(), body_as_bytes.clone(), cache_headers),
                )
                .await;
            let mut body = Body::from_bytes(body_as_bytes);
            body.set_mime(mime.clone());
            res.set_body(body);
            Ok(res)
        } else {
            // There is no caching for this request, just return the response we got
            log::debug!("Skip cache: {}", url_path);
            Ok(res)
        }
    }
}

fn get_cache_key(url_path: &str, encoding: &str, inline_css: bool) -> String {
    format!("{} {} {}", url_path, encoding, inline_css)
}
<|endoftext|>


<commit_before>use std::path::Path;
use std::env;
use std::process::Command;
use super::es::traits::*;
extern crate open;

pub fn open(p: &Path) {
    open::that(p).or_die("cannot open");
}

pub fn edit(p: &Path) {
    // Respect POSIX
    let editor = if let Ok(ed) = env::var("VISUAL") {
        ed
    } else
    if let Ok(ed) = env::var("EDITOR") {
        ed
    } else
    // MacOS open will NOT open random text files, so vim it is...
    if cfg!(macos) {
        "vim".into()
    } else
    if cfg!(windows) {
		// likewise, regular 'start' won't cope with files-without-known-extensions
		// Notepad is useless, so use Wordpad
		"write".into()
    } else {
        "open".into()
    };
    if editor == "open" {
        open(p);
    } else {
        Command::new(&editor).arg(&p).status().or_die(&format!("Cannot find editor {:?}: ",p));
    }
}

<commit_msg>use target_os. Now works on MacOS again<commit_after>use std::path::Path;
use std::env;
use std::process::Command;
use super::es::traits::*;
extern crate open;

pub fn open(p: &Path) {
    open::that(p).or_die("cannot open");
}

pub fn edit(p: &Path) {
    // Respect POSIX
    let editor = if let Ok(ed) = env::var("VISUAL") {
        ed
    } else
    if let Ok(ed) = env::var("EDITOR") {
        ed
    } else
    // MacOS open will NOT open random text files, so vim it is...
    if cfg!(target_os = "macos") {
        "vim".into()
    } else
    if cfg!(target_os = "windows") {
        // likewise, regular 'start' won't cope with files-without-known-extensions
        // Notepad is useless, so use Wordpad
        "write".into()
    } else {
        "open".into()
    };
    if editor == "open" {
        open(p);
    } else {
        Command::new(&editor).arg(&p).status().or_die(&format!("Cannot find editor {:?}: ",p));
    }
}

<|endoftext|>


<commit_before>use errno::errno;
use libc;
pub use tools::rlog;

pub unsafe fn give_terminal_to(pid: i32) {
    let mut mask: libc::sigset_t = 0;
    let mut old_mask: libc::sigset_t = 0;

    libc::sigemptyset(&mut mask);
    libc::sigaddset(&mut mask, libc::SIGTSTP);
    libc::sigaddset(&mut mask, libc::SIGTTIN);
    libc::sigaddset(&mut mask, libc::SIGTTOU);
    libc::sigaddset(&mut mask, libc::SIGCHLD);

    let rcode = libc::pthread_sigmask(libc::SIG_BLOCK, &mask, &mut old_mask);
    if rcode != 0 {
        rlog(format!("failed to call pthread_sigmask\n"));
    }
    let rcode = libc::tcsetpgrp(1, pid);
    if rcode == -1 {
        let e = errno();
        let code = e.0;
        rlog(format!("Error {}: {}\n", code, e));
    } else {
        rlog(format!("return term back to {} rcode: {}\n", pid, rcode));
    }
    let rcode = libc::pthread_sigmask(libc::SIG_SETMASK, &old_mask, &mut mask);
    if rcode != 0 {
        rlog(format!("failed to call pthread_sigmask\n"));
    }
}
<commit_msg>small issue<commit_after>use errno::errno;
use libc;
pub use tools::rlog;
use std::mem;

pub unsafe fn give_terminal_to(pid: i32) {
    let mut mask: libc::sigset_t = mem::zeroed();
    let mut old_mask: libc::sigset_t = mem::zeroed();

    libc::sigemptyset(&mut mask);
    libc::sigaddset(&mut mask, libc::SIGTSTP);
    libc::sigaddset(&mut mask, libc::SIGTTIN);
    libc::sigaddset(&mut mask, libc::SIGTTOU);
    libc::sigaddset(&mut mask, libc::SIGCHLD);

    let rcode = libc::pthread_sigmask(libc::SIG_BLOCK, &mask, &mut old_mask);
    if rcode != 0 {
        rlog(format!("failed to call pthread_sigmask\n"));
    }
    let rcode = libc::tcsetpgrp(1, pid);
    if rcode == -1 {
        let e = errno();
        let code = e.0;
        rlog(format!("Error {}: {}\n", code, e));
    } else {
        rlog(format!("return term back to {} rcode: {}\n", pid, rcode));
    }
    let rcode = libc::pthread_sigmask(libc::SIG_SETMASK, &old_mask, &mut mask);
    if rcode != 0 {
        rlog(format!("failed to call pthread_sigmask\n"));
    }
}
<|endoftext|>