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

//! Simple [DEFLATE][def]-based compression. This is a wrapper around the
//! [`miniz`][mz] library, which is a one-file pure-C implementation of zlib.
//!
//! [def]: https://en.wikipedia.org/wiki/DEFLATE
//! [mz]: https://code.google.com/p/miniz/

// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
#![cfg_attr(stage0, feature(custom_attribute))]
#![crate_name = "flate"]
#![unstable(feature = "rustc_private", issue = "27812")]
#![staged_api]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/")]

#![feature(libc)]
#![feature(staged_api)]
#![feature(unique)]
#![cfg_attr(test, feature(rustc_private, rand, vec_push_all))]

#[cfg(test)] #[macro_use] extern crate log;

extern crate libc;

use libc::{c_void, size_t, c_int};
use std::fmt;
use std::ops::Deref;
use std::ptr::Unique;
use std::slice;

#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Error {
    _unused: (),
}

impl Error {
    fn new() -> Error {
        Error {
            _unused: (),
        }
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "decompression error".fmt(f)
    }
}

pub struct Bytes {
    ptr: Unique<u8>,
    len: usize,
}

impl Deref for Bytes {
    type Target = [u8];
    fn deref(&self) -> &[u8] {
        unsafe { slice::from_raw_parts(*self.ptr, self.len) }
    }
}

impl Drop for Bytes {
    fn drop(&mut self) {
        unsafe { libc::free(*self.ptr as *mut _); }
    }
}

#[link(name = "miniz", kind = "static")]
extern {
    /// Raw miniz compression function.
    fn tdefl_compress_mem_to_heap(psrc_buf: *const c_void,
                                  src_buf_len: size_t,
                                  pout_len: *mut size_t,
                                  flags: c_int)
                                  -> *mut c_void;

    /// Raw miniz decompression function.
    fn tinfl_decompress_mem_to_heap(psrc_buf: *const c_void,
                                    src_buf_len: size_t,
                                    pout_len: *mut size_t,
                                    flags: c_int)
                                    -> *mut c_void;
}

const LZ_NORM: c_int = 0x80;  // LZ with 128 probes, "normal"
const TINFL_FLAG_PARSE_ZLIB_HEADER: c_int = 0x1; // parse zlib header and adler32 checksum
const TDEFL_WRITE_ZLIB_HEADER: c_int = 0x01000; // write zlib header and adler32 checksum

fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Bytes {
    unsafe {
        let mut outsz: size_t = 0;
        let res = tdefl_compress_mem_to_heap(bytes.as_ptr() as *const _,
                                             bytes.len() as size_t,
                                             &mut outsz,
                                             flags);
        assert!(!res.is_null());
        Bytes {
            ptr: Unique::new(res as *mut u8),
            len: outsz as usize,
        }
    }
}

/// Compress a buffer, without writing any sort of header on the output.
pub fn deflate_bytes(bytes: &[u8]) -> Bytes {
    deflate_bytes_internal(bytes, LZ_NORM)
}

/// Compress a buffer, using a header that zlib can understand.
pub fn deflate_bytes_zlib(bytes: &[u8]) -> Bytes {
    deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER)
}

fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Result<Bytes,Error> {
    unsafe {
        let mut outsz: size_t = 0;
        let res = tinfl_decompress_mem_to_heap(bytes.as_ptr() as *const _,
                                               bytes.len() as size_t,
                                               &mut outsz,
                                               flags);
        if !res.is_null() {
            Ok(Bytes {
                ptr: Unique::new(res as *mut u8),
                len: outsz as usize,
            })
        } else {
            Err(Error::new())
        }
    }
}

/// Decompress a buffer, without parsing any sort of header on the input.
pub fn inflate_bytes(bytes: &[u8]) -> Result<Bytes,Error> {
    inflate_bytes_internal(bytes, 0)
}

/// Decompress a buffer that starts with a zlib header.
pub fn inflate_bytes_zlib(bytes: &[u8]) -> Result<Bytes,Error> {
    inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER)
}

#[cfg(test)]
mod tests {
    #![allow(deprecated)]
    use super::{inflate_bytes, deflate_bytes};
    use std::__rand::{thread_rng, Rng};

    #[test]
    fn test_flate_round_trip() {
        let mut r = thread_rng();
        let mut words = vec![];
        for _ in 0..20 {
            let range = r.gen_range(1, 10);
            let v = r.gen_iter::<u8>().take(range).collect::<Vec<u8>>();
            words.push(v);
        }
        for _ in 0..20 {
            let mut input = vec![];
            for _ in 0..2000 {
                input.push_all(r.choose(&words).unwrap());
            }
            debug!("de/inflate of {} bytes of random word-sequences",
                   input.len());
            let cmp = deflate_bytes(&input);
            let out = inflate_bytes(&cmp).unwrap();
            debug!("{} bytes deflated to {} ({:.1}% size)",
                   input.len(), cmp.len(),
                   100.0 * ((cmp.len() as f64) / (input.len() as f64)));
            assert_eq!(&*input, &*out);
        }
    }

    #[test]
    fn test_zlib_flate() {
        let bytes = vec![1, 2, 3, 4, 5];
        let deflated = deflate_bytes(&bytes);
        let inflated = inflate_bytes(&deflated).unwrap();
        assert_eq!(&*inflated, &*bytes);
    }
}
<commit_msg>Update Libflate Formatting<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Simple [DEFLATE][def]-based compression. This is a wrapper around the
//! [`miniz`][mz] library, which is a one-file pure-C implementation of zlib.
//!
//! [def]: https://en.wikipedia.org/wiki/DEFLATE
//! [mz]: https://code.google.com/p/miniz/

// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
#![cfg_attr(stage0, feature(custom_attribute))]
#![crate_name = "flate"]
#![unstable(feature = "rustc_private", issue = "27812")]
#![staged_api]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/")]

#![feature(libc)]
#![feature(staged_api)]
#![feature(unique)]
#![cfg_attr(test, feature(rustc_private, rand, vec_push_all))]

#[cfg(test)]
#[macro_use]
extern crate log;

extern crate libc;

use libc::{c_void, size_t, c_int};
use std::fmt;
use std::ops::Deref;
use std::ptr::Unique;
use std::slice;

#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Error {
    _unused: (),
}

impl Error {
    fn new() -> Error {
        Error { _unused: () }
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "decompression error".fmt(f)
    }
}

pub struct Bytes {
    ptr: Unique<u8>,
    len: usize,
}

impl Deref for Bytes {
    type Target = [u8];
    fn deref(&self) -> &[u8] {
        unsafe { slice::from_raw_parts(*self.ptr, self.len) }
    }
}

impl Drop for Bytes {
    fn drop(&mut self) {
        unsafe {
            libc::free(*self.ptr as *mut _);
        }
    }
}

#[link(name = "miniz", kind = "static")]
extern {
    /// Raw miniz compression function.
    fn tdefl_compress_mem_to_heap(psrc_buf: *const c_void,
                                  src_buf_len: size_t,
                                  pout_len: *mut size_t,
                                  flags: c_int)
                                  -> *mut c_void;

    /// Raw miniz decompression function.
    fn tinfl_decompress_mem_to_heap(psrc_buf: *const c_void,
                                    src_buf_len: size_t,
                                    pout_len: *mut size_t,
                                    flags: c_int)
                                    -> *mut c_void;
}

const LZ_NORM: c_int = 0x80;  // LZ with 128 probes, "normal"
const TINFL_FLAG_PARSE_ZLIB_HEADER: c_int = 0x1; // parse zlib header and adler32 checksum
const TDEFL_WRITE_ZLIB_HEADER: c_int = 0x01000; // write zlib header and adler32 checksum

fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> Bytes {
    unsafe {
        let mut outsz: size_t = 0;
        let res = tdefl_compress_mem_to_heap(bytes.as_ptr() as *const _,
                                             bytes.len() as size_t,
                                             &mut outsz,
                                             flags);
        assert!(!res.is_null());
        Bytes {
            ptr: Unique::new(res as *mut u8),
            len: outsz as usize,
        }
    }
}

/// Compress a buffer, without writing any sort of header on the output.
pub fn deflate_bytes(bytes: &[u8]) -> Bytes {
    deflate_bytes_internal(bytes, LZ_NORM)
}

/// Compress a buffer, using a header that zlib can understand.
pub fn deflate_bytes_zlib(bytes: &[u8]) -> Bytes {
    deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER)
}

fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Result<Bytes, Error> {
    unsafe {
        let mut outsz: size_t = 0;
        let res = tinfl_decompress_mem_to_heap(bytes.as_ptr() as *const _,
                                               bytes.len() as size_t,
                                               &mut outsz,
                                               flags);
        if !res.is_null() {
            Ok(Bytes {
                ptr: Unique::new(res as *mut u8),
                len: outsz as usize,
            })
        } else {
            Err(Error::new())
        }
    }
}

/// Decompress a buffer, without parsing any sort of header on the input.
pub fn inflate_bytes(bytes: &[u8]) -> Result<Bytes, Error> {
    inflate_bytes_internal(bytes, 0)
}

/// Decompress a buffer that starts with a zlib header.
pub fn inflate_bytes_zlib(bytes: &[u8]) -> Result<Bytes, Error> {
    inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER)
}

#[cfg(test)]
mod tests {
    #![allow(deprecated)]
    use super::{inflate_bytes, deflate_bytes};
    use std::__rand::{thread_rng, Rng};

    #[test]
    fn test_flate_round_trip() {
        let mut r = thread_rng();
        let mut words = vec![];
        for _ in 0..20 {
            let range = r.gen_range(1, 10);
            let v = r.gen_iter::<u8>().take(range).collect::<Vec<u8>>();
            words.push(v);
        }
        for _ in 0..20 {
            let mut input = vec![];
            for _ in 0..2000 {
                input.push_all(r.choose(&words).unwrap());
            }
            debug!("de/inflate of {} bytes of random word-sequences",
                   input.len());
            let cmp = deflate_bytes(&input);
            let out = inflate_bytes(&cmp).unwrap();
            debug!("{} bytes deflated to {} ({:.1}% size)",
                   input.len(),
                   cmp.len(),
                   100.0 * ((cmp.len() as f64) / (input.len() as f64)));
            assert_eq!(&*input, &*out);
        }
    }

    #[test]
    fn test_zlib_flate() {
        let bytes = vec![1, 2, 3, 4, 5];
        let deflated = deflate_bytes(&bytes);
        let inflated = inflate_bytes(&deflated).unwrap();
        assert_eq!(&*inflated, &*bytes);
    }
}
<|endoftext|>


<commit_before><commit_msg>Skeleton for problem 2325<commit_after>// https://leetcode.com/problems/decode-the-message/
pub fn decode_message(key: String, message: String) -> String {
    todo!()
}

fn main() {
    println!(
        "{}",
        decode_message(
            String::from("the quick brown fox jumps over the lazy dog"),
            String::from("vkbs bs t suepuv")
        )
    ); // "this is a secret"
    println!(
        "{}",
        decode_message(
            String::from("eljuxhpwnyrdgtqkviszcfmabo"),
            String::from("zwx hnfx lqantp mnoeius ycgk vcnjrdb")
        )
    ); // "the five boxing wizards jump quickly"
}
<|endoftext|>


<commit_before><commit_msg>an empy message<commit_after><|endoftext|>


<commit_before>use std::borrow::Cow;
use std::fmt::{self, Write};

use httparse;

use header::{self, Headers, ContentLength, TransferEncoding};
use http::{MessageHead, RawStatus, Http1Transaction, ParseResult, ServerTransaction, ClientTransaction, RequestLine};
use http::h1::{Encoder, Decoder};
use http::buf::{MemBuf, MemSlice};
use method::Method;
use status::StatusCode;
use version::HttpVersion::{Http10, Http11};

const MAX_HEADERS: usize = 100;
const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific

pub fn parse<T: Http1Transaction<Incoming=I>, I>(buf: &MemBuf) -> ParseResult<I> {
    if buf.len() == 0 {
        return Ok(None);
    }
    trace!("parse({:?})", buf);
    <T as Http1Transaction>::parse(buf)
}

impl Http1Transaction for ServerTransaction {
    type Incoming = RequestLine;
    type Outgoing = StatusCode;

    fn parse(buf: &MemBuf) -> ParseResult<RequestLine> {
        let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS];
        trace!("Request.parse([Header; {}], [u8; {}])", headers.len(), buf.len());
        let mut req = httparse::Request::new(&mut headers);
        Ok(match try!(req.parse(buf.bytes())) {
            httparse::Status::Complete(len) => {
                trace!("Request.parse Complete({})", len);
                let mut headers = Headers::with_capacity(req.headers.len());
                let slice = buf.slice(len);
                headers.extend(HeadersAsMemSliceIter {
                    headers: req.headers.iter(),
                    slice: slice,
                });
                Some((MessageHead {
                    version: if req.version.unwrap() == 1 { Http11 } else { Http10 },
                    subject: RequestLine(
                        try!(req.method.unwrap().parse()),
                        try!(req.path.unwrap().parse())
                    ),
                    headers: headers,
                }, len))
            }
            httparse::Status::Partial => None,
        })
    }

    fn decoder(head: &MessageHead<Self::Incoming>) -> ::Result<Decoder> {
        use ::header;
        if let Some(&header::ContentLength(len)) = head.headers.get() {
            Ok(Decoder::length(len))
        } else if head.headers.has::<header::TransferEncoding>() {
            //TODO: check for Transfer-Encoding: chunked
            Ok(Decoder::chunked())
        } else {
            Ok(Decoder::length(0))
        }
    }

    fn encode(head: &mut MessageHead<Self::Outgoing>, dst: &mut Vec<u8>) -> Encoder {
        use ::header;
        trace!("writing head: {:?}", head);

        if !head.headers.has::<header::Date>() {
            head.headers.set(header::Date(header::HttpDate(::time::now_utc())));
        }

        let mut is_chunked = true;
        let mut body = Encoder::chunked();
        if let Some(cl) = head.headers.get::<header::ContentLength>() {
            body = Encoder::length(**cl);
            is_chunked = false
        }

        if is_chunked {
            let encodings = match head.headers.get_mut::<header::TransferEncoding>() {
                Some(&mut header::TransferEncoding(ref mut encodings)) => {
                    if encodings.last() != Some(&header::Encoding::Chunked) {
                        encodings.push(header::Encoding::Chunked);
                    }
                    false
                },
                None => true
            };

            if encodings {
                head.headers.set(header::TransferEncoding(vec![header::Encoding::Chunked]));
            }
        }

        let init_cap = 30 + head.headers.len() * AVERAGE_HEADER_SIZE;
        dst.reserve(init_cap);
        debug!("writing headers = {:?}", head.headers);
        if head.version == ::HttpVersion::Http11 && head.subject == ::StatusCode::Ok {
            extend(dst, b"HTTP/1.1 200 OK\r\n");
            let _ = write!(FastWrite(dst), "{}\r\n", head.headers);
        } else {
            let _ = write!(FastWrite(dst), "{} {}\r\n{}\r\n", head.version, head.subject, head.headers);
        }
        body
    }

    fn should_set_length(_head: &MessageHead<Self::Outgoing>) -> bool {
        //TODO: pass method, check if method == HEAD
        true
    }
}

impl Http1Transaction for ClientTransaction {
    type Incoming = RawStatus;
    type Outgoing = RequestLine;

    fn parse(buf: &MemBuf) -> ParseResult<RawStatus> {
        let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS];
        trace!("Response.parse([Header; {}], [u8; {}])", headers.len(), buf.len());
        let mut res = httparse::Response::new(&mut headers);
        Ok(match try!(res.parse(buf.bytes())) {
            httparse::Status::Complete(len) => {
                trace!("Response.try_parse Complete({})", len);
                let code = res.code.unwrap();
                let reason = match StatusCode::from_u16(code).canonical_reason() {
                    Some(reason) if reason == res.reason.unwrap() => Cow::Borrowed(reason),
                    _ => Cow::Owned(res.reason.unwrap().to_owned())
                };
                let mut headers = Headers::with_capacity(res.headers.len());
                let slice = buf.slice(len);
                headers.extend(HeadersAsMemSliceIter {
                    headers: res.headers.iter(),
                    slice: slice,
                });
                Some((MessageHead {
                    version: if res.version.unwrap() == 1 { Http11 } else { Http10 },
                    subject: RawStatus(code, reason),
                    headers: headers,
                }, len))
            },
            httparse::Status::Partial => None
        })
    }

    fn decoder(inc: &MessageHead<Self::Incoming>) -> ::Result<Decoder> {
        use ::header;
        // According to https://tools.ietf.org/html/rfc7230#section-3.3.3
        // 1. HEAD reponses, and Status 1xx, 204, and 304 cannot have a body.
        // 2. Status 2xx to a CONNECT cannot have a body.
        //
        // First two steps taken care of before this method.
        //
        // 3. Transfer-Encoding: chunked has a chunked body.
        // 4. If multiple differing Content-Length headers or invalid, close connection.
        // 5. Content-Length header has a sized body.
        // 6. Not Client.
        // 7. Read till EOF.
        if let Some(&header::TransferEncoding(ref codings)) = inc.headers.get() {
            if codings.last() == Some(&header::Encoding::Chunked) {
                Ok(Decoder::chunked())
            } else {
                trace!("not chuncked. read till eof");
                Ok(Decoder::eof())
            }
        } else if let Some(&header::ContentLength(len)) = inc.headers.get() {
            Ok(Decoder::length(len))
        } else if inc.headers.has::<header::ContentLength>() {
            trace!("illegal Content-Length: {:?}", inc.headers.get_raw("Content-Length"));
            Err(::Error::Header)
        } else {
            trace!("neither Transfer-Encoding nor Content-Length");
            Ok(Decoder::eof())
        }
    }

    fn encode(head: &mut MessageHead<Self::Outgoing>, dst: &mut Vec<u8>) -> Encoder {
        trace!("writing head: {:?}", head);

        let mut body = Encoder::length(0);
        let expects_no_body = match head.subject.0 {
            Method::Head | Method::Get | Method::Connect => true,
            _ => false
        };
        let mut chunked = false;

        if let Some(con_len) = head.headers.get::<ContentLength>() {
            body = Encoder::length(**con_len);
        } else {
            chunked = !expects_no_body;
        }

        if chunked {
            body = Encoder::chunked();
            let encodings = match head.headers.get_mut::<TransferEncoding>() {
                Some(encodings) => {
                    if !encodings.contains(&header::Encoding::Chunked) {
                        encodings.push(header::Encoding::Chunked);
                    }
                    true
                },
                None => false
            };

            if !encodings {
                head.headers.set(TransferEncoding(vec![header::Encoding::Chunked]));
            }
        }

        let init_cap = 30 + head.headers.len() * AVERAGE_HEADER_SIZE;
        dst.reserve(init_cap);
        debug!("writing {:#?}", head.headers);
        let _ = write!(FastWrite(dst), "{} {}\r\n{}\r\n", head.subject, head.version, head.headers);

        body
    }

    fn should_set_length(head: &MessageHead<Self::Outgoing>) -> bool {
        match &head.subject.0 {
            &Method::Get | &Method::Head => false,
            _ => true
        }
    }
}

struct HeadersAsMemSliceIter<'a> {
    headers: ::std::slice::Iter<'a, httparse::Header<'a>>,
    slice: MemSlice,
}

impl<'a> Iterator for HeadersAsMemSliceIter<'a> {
    type Item = (&'a str, MemSlice);
    fn next(&mut self) -> Option<Self::Item> {
        self.headers.next().map(|header| {
            let value_start = header.value.as_ptr() as usize - self.slice.as_ref().as_ptr() as usize;
            let value_end = value_start + header.value.len();
            (header.name, self.slice.slice(value_start..value_end))
        })
    }
}

struct FastWrite<'a>(&'a mut Vec<u8>);

impl<'a> fmt::Write for FastWrite<'a> {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        extend(self.0, s.as_bytes());
        Ok(())
    }

    fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result {
        fmt::write(self, args)
    }
}

fn extend(dst: &mut Vec<u8>, data: &[u8]) {
    use std::ptr;
    dst.reserve(data.len());
    let prev = dst.len();
    unsafe {
        ptr::copy_nonoverlapping(data.as_ptr(),
                                 dst.as_mut_ptr().offset(prev as isize),
                                 data.len());
        dst.set_len(prev + data.len());
    }
}

#[cfg(test)]
mod tests {
    use http;
    use http::buf::MemBuf;
    use super::{parse};

    #[test]
    fn test_parse_request() {
        let raw = MemBuf::from(b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec());
        parse::<http::ServerTransaction, _>(&raw).unwrap();
    }

    #[test]
    fn test_parse_raw_status() {
        let raw = MemBuf::from(b"HTTP/1.1 200 OK\r\n\r\n".to_vec());
        let (res, _) = parse::<http::ClientTransaction, _>(&raw).unwrap().unwrap();
        assert_eq!(res.subject.1, "OK");

        let raw = MemBuf::from(b"HTTP/1.1 200 Howdy\r\n\r\n".to_vec());
        let (res, _) = parse::<http::ClientTransaction, _>(&raw).unwrap().unwrap();
        assert_eq!(res.subject.1, "Howdy");
    }

    #[cfg(feature = "nightly")]
    use test::Bencher;

    #[cfg(feature = "nightly")]
    #[bench]
    fn bench_parse_incoming(b: &mut Bencher) {
        let mut raw = MemBuf::from(b"GET /super_long_uri/and_whatever?what_should_we_talk_about/\
                                  I_wonder/Hard_to_write_in_an_uri_after_all/you_have_to_make\
                                  _up_the_punctuation_yourself/how_fun_is_that?test=foo&test1=\
                                  foo1&test2=foo2&test3=foo3&test4=foo4 HTTP/1.1\r\nHost: \
                                  hyper.rs\r\nAccept: a lot of things\r\nAccept-Charset: \
                                  utf8\r\nAccept-Encoding: *\r\nAccess-Control-Allow-\
                                  Credentials: None\r\nAccess-Control-Allow-Origin: None\r\n\
                                  Access-Control-Allow-Methods: None\r\nAccess-Control-Allow-\
                                  Headers: None\r\nContent-Encoding: utf8\r\nContent-Security-\
                                  Policy: None\r\nContent-Type: text/html\r\nOrigin: hyper\
                                  \r\nSec-Websocket-Extensions: It looks super important!\r\n\
                                  Sec-Websocket-Origin: hyper\r\nSec-Websocket-Version: 4.3\r\
                                  \nStrict-Transport-Security: None\r\nUser-Agent: hyper\r\n\
                                  X-Content-Duration: None\r\nX-Content-Security-Policy: None\
                                  \r\nX-DNSPrefetch-Control: None\r\nX-Frame-Options: \
                                  Something important obviously\r\nX-Requested-With: Nothing\
                                  \r\n\r\n".to_vec());
        b.iter(|| {
            parse::<http::ServerTransaction, _>(&raw).unwrap();
            raw.restart();
        });
    }

}
<commit_msg>test(http): test Uri parse errors propagate<commit_after>use std::borrow::Cow;
use std::fmt::{self, Write};

use httparse;

use header::{self, Headers, ContentLength, TransferEncoding};
use http::{MessageHead, RawStatus, Http1Transaction, ParseResult, ServerTransaction, ClientTransaction, RequestLine};
use http::h1::{Encoder, Decoder};
use http::buf::{MemBuf, MemSlice};
use method::Method;
use status::StatusCode;
use version::HttpVersion::{Http10, Http11};

const MAX_HEADERS: usize = 100;
const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific

pub fn parse<T: Http1Transaction<Incoming=I>, I>(buf: &MemBuf) -> ParseResult<I> {
    if buf.len() == 0 {
        return Ok(None);
    }
    trace!("parse({:?})", buf);
    <T as Http1Transaction>::parse(buf)
}

impl Http1Transaction for ServerTransaction {
    type Incoming = RequestLine;
    type Outgoing = StatusCode;

    fn parse(buf: &MemBuf) -> ParseResult<RequestLine> {
        let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS];
        trace!("Request.parse([Header; {}], [u8; {}])", headers.len(), buf.len());
        let mut req = httparse::Request::new(&mut headers);
        Ok(match try!(req.parse(buf.bytes())) {
            httparse::Status::Complete(len) => {
                trace!("Request.parse Complete({})", len);
                let mut headers = Headers::with_capacity(req.headers.len());
                let slice = buf.slice(len);
                headers.extend(HeadersAsMemSliceIter {
                    headers: req.headers.iter(),
                    slice: slice,
                });
                Some((MessageHead {
                    version: if req.version.unwrap() == 1 { Http11 } else { Http10 },
                    subject: RequestLine(
                        try!(req.method.unwrap().parse()),
                        try!(req.path.unwrap().parse())
                    ),
                    headers: headers,
                }, len))
            }
            httparse::Status::Partial => None,
        })
    }

    fn decoder(head: &MessageHead<Self::Incoming>) -> ::Result<Decoder> {
        use ::header;
        if let Some(&header::ContentLength(len)) = head.headers.get() {
            Ok(Decoder::length(len))
        } else if head.headers.has::<header::TransferEncoding>() {
            //TODO: check for Transfer-Encoding: chunked
            Ok(Decoder::chunked())
        } else {
            Ok(Decoder::length(0))
        }
    }

    fn encode(head: &mut MessageHead<Self::Outgoing>, dst: &mut Vec<u8>) -> Encoder {
        use ::header;
        trace!("writing head: {:?}", head);

        if !head.headers.has::<header::Date>() {
            head.headers.set(header::Date(header::HttpDate(::time::now_utc())));
        }

        let mut is_chunked = true;
        let mut body = Encoder::chunked();
        if let Some(cl) = head.headers.get::<header::ContentLength>() {
            body = Encoder::length(**cl);
            is_chunked = false
        }

        if is_chunked {
            let encodings = match head.headers.get_mut::<header::TransferEncoding>() {
                Some(&mut header::TransferEncoding(ref mut encodings)) => {
                    if encodings.last() != Some(&header::Encoding::Chunked) {
                        encodings.push(header::Encoding::Chunked);
                    }
                    false
                },
                None => true
            };

            if encodings {
                head.headers.set(header::TransferEncoding(vec![header::Encoding::Chunked]));
            }
        }

        let init_cap = 30 + head.headers.len() * AVERAGE_HEADER_SIZE;
        dst.reserve(init_cap);
        debug!("writing headers = {:?}", head.headers);
        if head.version == ::HttpVersion::Http11 && head.subject == ::StatusCode::Ok {
            extend(dst, b"HTTP/1.1 200 OK\r\n");
            let _ = write!(FastWrite(dst), "{}\r\n", head.headers);
        } else {
            let _ = write!(FastWrite(dst), "{} {}\r\n{}\r\n", head.version, head.subject, head.headers);
        }
        body
    }

    fn should_set_length(_head: &MessageHead<Self::Outgoing>) -> bool {
        //TODO: pass method, check if method == HEAD
        true
    }
}

impl Http1Transaction for ClientTransaction {
    type Incoming = RawStatus;
    type Outgoing = RequestLine;

    fn parse(buf: &MemBuf) -> ParseResult<RawStatus> {
        let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS];
        trace!("Response.parse([Header; {}], [u8; {}])", headers.len(), buf.len());
        let mut res = httparse::Response::new(&mut headers);
        Ok(match try!(res.parse(buf.bytes())) {
            httparse::Status::Complete(len) => {
                trace!("Response.try_parse Complete({})", len);
                let code = res.code.unwrap();
                let reason = match StatusCode::from_u16(code).canonical_reason() {
                    Some(reason) if reason == res.reason.unwrap() => Cow::Borrowed(reason),
                    _ => Cow::Owned(res.reason.unwrap().to_owned())
                };
                let mut headers = Headers::with_capacity(res.headers.len());
                let slice = buf.slice(len);
                headers.extend(HeadersAsMemSliceIter {
                    headers: res.headers.iter(),
                    slice: slice,
                });
                Some((MessageHead {
                    version: if res.version.unwrap() == 1 { Http11 } else { Http10 },
                    subject: RawStatus(code, reason),
                    headers: headers,
                }, len))
            },
            httparse::Status::Partial => None
        })
    }

    fn decoder(inc: &MessageHead<Self::Incoming>) -> ::Result<Decoder> {
        use ::header;
        // According to https://tools.ietf.org/html/rfc7230#section-3.3.3
        // 1. HEAD reponses, and Status 1xx, 204, and 304 cannot have a body.
        // 2. Status 2xx to a CONNECT cannot have a body.
        //
        // First two steps taken care of before this method.
        //
        // 3. Transfer-Encoding: chunked has a chunked body.
        // 4. If multiple differing Content-Length headers or invalid, close connection.
        // 5. Content-Length header has a sized body.
        // 6. Not Client.
        // 7. Read till EOF.
        if let Some(&header::TransferEncoding(ref codings)) = inc.headers.get() {
            if codings.last() == Some(&header::Encoding::Chunked) {
                Ok(Decoder::chunked())
            } else {
                trace!("not chuncked. read till eof");
                Ok(Decoder::eof())
            }
        } else if let Some(&header::ContentLength(len)) = inc.headers.get() {
            Ok(Decoder::length(len))
        } else if inc.headers.has::<header::ContentLength>() {
            trace!("illegal Content-Length: {:?}", inc.headers.get_raw("Content-Length"));
            Err(::Error::Header)
        } else {
            trace!("neither Transfer-Encoding nor Content-Length");
            Ok(Decoder::eof())
        }
    }

    fn encode(head: &mut MessageHead<Self::Outgoing>, dst: &mut Vec<u8>) -> Encoder {
        trace!("writing head: {:?}", head);

        let mut body = Encoder::length(0);
        let expects_no_body = match head.subject.0 {
            Method::Head | Method::Get | Method::Connect => true,
            _ => false
        };
        let mut chunked = false;

        if let Some(con_len) = head.headers.get::<ContentLength>() {
            body = Encoder::length(**con_len);
        } else {
            chunked = !expects_no_body;
        }

        if chunked {
            body = Encoder::chunked();
            let encodings = match head.headers.get_mut::<TransferEncoding>() {
                Some(encodings) => {
                    if !encodings.contains(&header::Encoding::Chunked) {
                        encodings.push(header::Encoding::Chunked);
                    }
                    true
                },
                None => false
            };

            if !encodings {
                head.headers.set(TransferEncoding(vec![header::Encoding::Chunked]));
            }
        }

        let init_cap = 30 + head.headers.len() * AVERAGE_HEADER_SIZE;
        dst.reserve(init_cap);
        debug!("writing {:#?}", head.headers);
        let _ = write!(FastWrite(dst), "{} {}\r\n{}\r\n", head.subject, head.version, head.headers);

        body
    }

    fn should_set_length(head: &MessageHead<Self::Outgoing>) -> bool {
        match &head.subject.0 {
            &Method::Get | &Method::Head => false,
            _ => true
        }
    }
}

struct HeadersAsMemSliceIter<'a> {
    headers: ::std::slice::Iter<'a, httparse::Header<'a>>,
    slice: MemSlice,
}

impl<'a> Iterator for HeadersAsMemSliceIter<'a> {
    type Item = (&'a str, MemSlice);
    fn next(&mut self) -> Option<Self::Item> {
        self.headers.next().map(|header| {
            let value_start = header.value.as_ptr() as usize - self.slice.as_ref().as_ptr() as usize;
            let value_end = value_start + header.value.len();
            (header.name, self.slice.slice(value_start..value_end))
        })
    }
}

struct FastWrite<'a>(&'a mut Vec<u8>);

impl<'a> fmt::Write for FastWrite<'a> {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        extend(self.0, s.as_bytes());
        Ok(())
    }

    fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result {
        fmt::write(self, args)
    }
}

fn extend(dst: &mut Vec<u8>, data: &[u8]) {
    use std::ptr;
    dst.reserve(data.len());
    let prev = dst.len();
    unsafe {
        ptr::copy_nonoverlapping(data.as_ptr(),
                                 dst.as_mut_ptr().offset(prev as isize),
                                 data.len());
        dst.set_len(prev + data.len());
    }
}

#[cfg(test)]
mod tests {
    use http;
    use http::buf::MemBuf;
    use super::{parse};

    #[test]
    fn test_parse_request() {
        let raw = MemBuf::from(b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec());
        parse::<http::ServerTransaction, _>(&raw).unwrap();
    }

    #[test]
    fn test_parse_request_errors() {
        let raw = MemBuf::from(b"GET htt:p// HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec());
        parse::<http::ServerTransaction, _>(&raw).unwrap_err();
    }
    #[test]
    fn test_parse_raw_status() {
        let raw = MemBuf::from(b"HTTP/1.1 200 OK\r\n\r\n".to_vec());
        let (res, _) = parse::<http::ClientTransaction, _>(&raw).unwrap().unwrap();
        assert_eq!(res.subject.1, "OK");

        let raw = MemBuf::from(b"HTTP/1.1 200 Howdy\r\n\r\n".to_vec());
        let (res, _) = parse::<http::ClientTransaction, _>(&raw).unwrap().unwrap();
        assert_eq!(res.subject.1, "Howdy");
    }

    #[cfg(feature = "nightly")]
    use test::Bencher;

    #[cfg(feature = "nightly")]
    #[bench]
    fn bench_parse_incoming(b: &mut Bencher) {
        let mut raw = MemBuf::from(b"GET /super_long_uri/and_whatever?what_should_we_talk_about/\
                                  I_wonder/Hard_to_write_in_an_uri_after_all/you_have_to_make\
                                  _up_the_punctuation_yourself/how_fun_is_that?test=foo&test1=\
                                  foo1&test2=foo2&test3=foo3&test4=foo4 HTTP/1.1\r\nHost: \
                                  hyper.rs\r\nAccept: a lot of things\r\nAccept-Charset: \
                                  utf8\r\nAccept-Encoding: *\r\nAccess-Control-Allow-\
                                  Credentials: None\r\nAccess-Control-Allow-Origin: None\r\n\
                                  Access-Control-Allow-Methods: None\r\nAccess-Control-Allow-\
                                  Headers: None\r\nContent-Encoding: utf8\r\nContent-Security-\
                                  Policy: None\r\nContent-Type: text/html\r\nOrigin: hyper\
                                  \r\nSec-Websocket-Extensions: It looks super important!\r\n\
                                  Sec-Websocket-Origin: hyper\r\nSec-Websocket-Version: 4.3\r\
                                  \nStrict-Transport-Security: None\r\nUser-Agent: hyper\r\n\
                                  X-Content-Duration: None\r\nX-Content-Security-Policy: None\
                                  \r\nX-DNSPrefetch-Control: None\r\nX-Frame-Options: \
                                  Something important obviously\r\nX-Requested-With: Nothing\
                                  \r\n\r\n".to_vec());
        b.iter(|| {
            parse::<http::ServerTransaction, _>(&raw).unwrap();
            raw.restart();
        });
    }

}
<|endoftext|>


<commit_before><commit_msg>Reduce duplication in creation of stats message<commit_after><|endoftext|>


<commit_before>#![feature(phase, globs)]
extern crate regex;
#[phase(plugin)] extern crate regex_macros;
extern crate ansi_term;
extern crate users;
extern crate unicode;

use std::io::FileType;
use std::io::fs;
use std::iter::AdditiveIterator;
use std::os;
use std::str::StrVector;

use column::Alignment::Left;
use column::Column;
use dir::Dir;
use file::File;
use options::{Options, View};

use ansi_term::Style::Plain;
use ansi_term::strip_formatting;

use users::OSUsers;

pub mod column;
pub mod dir;
pub mod format;
pub mod file;
pub mod filetype;
pub mod options;
pub mod term;

fn main() {
    let args: Vec<String> = os::args();

    match Options::getopts(args) {
        Err(error_code) => os::set_exit_status(error_code),
        Ok(options) => exa(&options),
    };
}

fn exa(opts: &Options) {
    let mut dirs: Vec<String> = vec![];
    let mut files: Vec<File> = vec![];

    // Separate the user-supplied paths into directories and files.
    // Files are shown first, and then each directory is expanded
    // and listed second.
    for file in opts.path_strs.iter() {
        let path = Path::new(file);
        match fs::stat(&path) {
            Ok(stat) => {
                if !opts.list_dirs && stat.kind == FileType::Directory {
                    dirs.push(file.clone());
                }
                else {
                    // May as well reuse the stat result from earlier
                    // instead of just using File::from_path().
                    files.push(File::with_stat(stat, &path, None));
                }
            }
            Err(e) => println!("{}: {}", file, e),
        }
    }

    // It's only worth printing out directory names if the user supplied
    // more than one of them.
    let print_dir_names = opts.path_strs.len() > 1;
    let mut first = files.is_empty();

    if !files.is_empty() {
        view(opts, files);
    }

    for dir_name in dirs.iter() {
        if first {
            first = false;
        }
        else {
            print!("\n");
        }

        match Dir::readdir(Path::new(dir_name.clone())) {
            Ok(dir) => {
                let unsorted_files = dir.files();
                let files: Vec<File> = opts.transform_files(unsorted_files);

                if print_dir_names {
                    println!("{}:", dir_name);
                }

                view(opts, files);
            }
            Err(e) => {
                println!("{}: {}", dir_name, e);
                return;
            }
        };
    }
}

fn view(options: &Options, files: Vec<File>) {
    match options.view {
        View::Details(ref cols) => details_view(options, cols, files),
        View::Lines => lines_view(files),
        View::Grid(across, width) => grid_view(across, width, files),
    }
}

fn lines_view(files: Vec<File>) {
    for file in files.iter() {
        println!("{}", file.file_name());
    }
}

fn grid_view(across: bool, console_width: uint, files: Vec<File>) {
    // Check if all the files can be displayed on one line, and do
    // that if possible. The width has to take into account the
    // two-space separator between file names for every file except
    // the last one (because it's a separator)
    let width = files.iter()
                     .map(|f| f.name.len() + 2)
                     .sum() - 2;

    if width <= console_width {
        let names: Vec<String> = files.iter()
                                      .map(|f| f.file_name().to_string())
                                      .collect();

        println!("{}", names.connect("  "));
        return;
    }

    // Otherwise, contort them into a grid.
    let max_column_length = files.iter().map(|f| f.file_name_width()).max().unwrap_or(0);
    let num_columns = (console_width + 1) / (max_column_length + 1);
    let count = files.len();

    let mut num_rows = count / num_columns;
    if count % num_columns != 0 {
        num_rows += 1;
    }

    for y in range(0, num_rows) {
        for x in range(0, num_columns) {
            let num = if across {
                y * num_columns + x
            }
            else {
                y + num_rows * x
            };

            if num >= count {
                continue;
            }

            let ref file = files[num];
            let styled_name = file.file_colour().paint(file.name.as_slice()).to_string();
            if x == num_columns - 1 {
                print!("{}", styled_name);
            }
            else {
                print!("{}", Left.pad_string(&styled_name, max_column_length - file.name.len() + 1));
            }
        }
        print!("\n");
    }
}

fn details_view(options: &Options, columns: &Vec<Column>, files: Vec<File>) {
    // The output gets formatted into columns, which looks nicer. To
    // do this, we have to write the results into a table, instead of
    // displaying each file immediately, then calculating the maximum
    // width of each column based on the length of the results and
    // padding the fields during output.

    let mut cache = OSUsers::empty_cache();

    let mut table: Vec<Vec<String>> = files.iter()
        .map(|f| columns.iter().map(|c| f.display(c, &mut cache)).collect())
        .collect();

    if options.header {
        table.insert(0, columns.iter().map(|c| Plain.underline().paint(c.header()).to_string()).collect());
    }

    // Each column needs to have its invisible colour-formatting
    // characters stripped before it has its width calculated, or the
    // width will be incorrect and the columns won't line up properly.
    // This is fairly expensive to do (it uses a regex), so the
    // results are cached.

    let lengths: Vec<Vec<uint>> = table.iter()
        .map(|row| row.iter().map(|col| strip_formatting(col.as_slice()).len()).collect())
        .collect();

    let column_widths: Vec<uint> = range(0, columns.len())
        .map(|n| lengths.iter().map(|row| row[n]).max().unwrap_or(0))
        .collect();

    for (field_widths, row) in lengths.iter().zip(table.iter()) {
        for (num, column) in columns.iter().enumerate() {
            if num != 0 {
                print!(" ");
            }

            if num == columns.len() - 1 {
                print!("{}", row[num]);
            }
            else {
                let padding = column_widths[num] - field_widths[num];
                print!("{}", column.alignment().pad_string(&row[num], padding));
            }
        }
        print!("\n");
    }
}
<commit_msg>Use a more compact grid view<commit_after>#![feature(phase, globs)]
extern crate regex;
#[phase(plugin)] extern crate regex_macros;
extern crate ansi_term;
extern crate users;
extern crate unicode;

use std::io::FileType;
use std::io::fs;
use std::iter::AdditiveIterator;
use std::os;
use std::cmp::max;

use column::Alignment::Left;
use column::Column;
use dir::Dir;
use file::File;
use options::{Options, View};

use ansi_term::Style::Plain;
use ansi_term::strip_formatting;

use users::OSUsers;

pub mod column;
pub mod dir;
pub mod format;
pub mod file;
pub mod filetype;
pub mod options;
pub mod term;

fn main() {
    let args: Vec<String> = os::args();

    match Options::getopts(args) {
        Err(error_code) => os::set_exit_status(error_code),
        Ok(options) => exa(&options),
    };
}

fn exa(opts: &Options) {
    let mut dirs: Vec<String> = vec![];
    let mut files: Vec<File> = vec![];

    // Separate the user-supplied paths into directories and files.
    // Files are shown first, and then each directory is expanded
    // and listed second.
    for file in opts.path_strs.iter() {
        let path = Path::new(file);
        match fs::stat(&path) {
            Ok(stat) => {
                if !opts.list_dirs && stat.kind == FileType::Directory {
                    dirs.push(file.clone());
                }
                else {
                    // May as well reuse the stat result from earlier
                    // instead of just using File::from_path().
                    files.push(File::with_stat(stat, &path, None));
                }
            }
            Err(e) => println!("{}: {}", file, e),
        }
    }

    // It's only worth printing out directory names if the user supplied
    // more than one of them.
    let print_dir_names = opts.path_strs.len() > 1;
    let mut first = files.is_empty();

    if !files.is_empty() {
        view(opts, files);
    }

    for dir_name in dirs.iter() {
        if first {
            first = false;
        }
        else {
            print!("\n");
        }

        match Dir::readdir(Path::new(dir_name.clone())) {
            Ok(dir) => {
                let unsorted_files = dir.files();
                let files: Vec<File> = opts.transform_files(unsorted_files);

                if print_dir_names {
                    println!("{}:", dir_name);
                }

                view(opts, files);
            }
            Err(e) => {
                println!("{}: {}", dir_name, e);
                return;
            }
        };
    }
}

fn view(options: &Options, files: Vec<File>) {
    match options.view {
        View::Details(ref cols) => details_view(options, cols, files),
        View::Lines => lines_view(files),
        View::Grid(across, width) => grid_view(across, width, files),
    }
}

fn lines_view(files: Vec<File>) {
    for file in files.iter() {
        println!("{}", file.file_name());
    }
}

fn fit_into_grid(across: bool, console_width: uint, files: &Vec<File>) -> Option<(uint, Vec<uint>)> {
    // TODO: this function could almost certainly be optimised...
    // surely not *all* of the numbers of lines are worth searching through!

    // Instead of numbers of columns, try to find the fewest number of *lines*
    // that the output will fit in.
    for num_lines in range(1, files.len()) {

        // The number of columns is the number of files divided by the number
        // of lines, *rounded up*.
        let mut num_columns = files.len() / num_lines;
        if files.len() % num_lines != 0 {
            num_columns += 1;
        }

        // Early abort: if there are so many columns that the width of the
        // *column separators* is bigger than the width of the screen, then
        // don't even try to tabulate it.
        // This is actually a necessary check, because the width is stored as
        // a uint, and making it go negative makes it huge instead, but it
        // also serves as a speed-up.
        if console_width < (num_columns - 1) * 2 {
            continue;
        }

        // Remove the separator width from the available space.
        let adjusted_width = console_width - (num_columns - 1) * 2;

        // Find the width of each column by adding the lengths of the file
        // names in that column up.
        let mut column_widths = Vec::from_fn(num_columns, |_| 0u);
        for (index, file) in files.iter().enumerate() {
            let index = if across {
                index % num_columns
            }
            else {
                index / num_lines
            };
            column_widths[index] = max(column_widths[index], file.name.len());
        }

        // If they all fit in the terminal, combined, then success!
        if column_widths.iter().map(|&x| x).sum() < adjusted_width {
            return Some((num_lines, column_widths));
        }
    }

    // If you get here you have really long file names.
    return None;
}

fn grid_view(across: bool, console_width: uint, files: Vec<File>) {
    if let Some((num_lines, widths)) = fit_into_grid(across, console_width, &files) {
        for y in range(0, num_lines) {
            for x in range(0, widths.len()) {
                let num = if across {
                    y * widths.len() + x
                }
                else {
                    y + num_lines * x
                };

                // Show whitespace in the place of trailing files
                if num >= files.len() {
                    continue;
                }

                let ref file = files[num];
                let styled_name = file.file_colour().paint(file.name.as_slice()).to_string();
                if x == widths.len() - 1 {
                    // The final column doesn't need to have trailing spaces
                    print!("{}", styled_name);
                }
                else {
                    assert!(widths[x] >= file.name.len());
                    print!("{}", Left.pad_string(&styled_name, widths[x] - file.name.len() + 2));
                }
            }
            print!("\n");
        }
    }
    else {
        // Drop down to lines view if the file names are too big for a grid
        lines_view(files);
    }
}

fn details_view(options: &Options, columns: &Vec<Column>, files: Vec<File>) {
    // The output gets formatted into columns, which looks nicer. To
    // do this, we have to write the results into a table, instead of
    // displaying each file immediately, then calculating the maximum
    // width of each column based on the length of the results and
    // padding the fields during output.

    let mut cache = OSUsers::empty_cache();

    let mut table: Vec<Vec<String>> = files.iter()
        .map(|f| columns.iter().map(|c| f.display(c, &mut cache)).collect())
        .collect();

    if options.header {
        table.insert(0, columns.iter().map(|c| Plain.underline().paint(c.header()).to_string()).collect());
    }

    // Each column needs to have its invisible colour-formatting
    // characters stripped before it has its width calculated, or the
    // width will be incorrect and the columns won't line up properly.
    // This is fairly expensive to do (it uses a regex), so the
    // results are cached.

    let lengths: Vec<Vec<uint>> = table.iter()
        .map(|row| row.iter().map(|col| strip_formatting(col.as_slice()).len()).collect())
        .collect();

    let column_widths: Vec<uint> = range(0, columns.len())
        .map(|n| lengths.iter().map(|row| row[n]).max().unwrap_or(0))
        .collect();

    for (field_widths, row) in lengths.iter().zip(table.iter()) {
        for (num, column) in columns.iter().enumerate() {
            if num != 0 {
                print!(" ");  // Separator
            }

            if num == columns.len() - 1 {
                // The final column doesn't need to have trailing spaces
                print!("{}", row[num]);
            }
            else {
                let padding = column_widths[num] - field_widths[num];
                print!("{}", column.alignment().pad_string(&row[num], padding));
            }
        }
        print!("\n");
    }
}
<|endoftext|>


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

use std::sync::{self, Arc}; //~ NOTE previous import
                            //~^ NOTE previous import
use std::sync::Arc; //~ ERROR a type named
use std::sync; //~ ERROR a module named

fn main() {
}
<|endoftext|>


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

macro_rules! m { ($t:tt) => { $t } }

fn main() {
    m!($t); //~ ERROR unknown macro variable
            //~| ERROR expected expression
}
<|endoftext|>


<commit_before><commit_msg>Implement get_idx_mut_slice method to retrieve indexes in a page<commit_after><|endoftext|>


<commit_before><commit_msg>Added tests to show that items in different nodes won't collide<commit_after><|endoftext|>


<commit_before><commit_msg>Corrected prelogin_payload name in lib.rs<commit_after><|endoftext|>


<commit_before><commit_msg>Move tests to sub-module<commit_after><|endoftext|>


<commit_before><commit_msg>Define custom rust lang features<commit_after><|endoftext|>


<commit_before><commit_msg>Forgot to add rsp.rs<commit_after>#[derive(Default)]
pub struct Rsp {
    _dummy: i32
}

impl Rsp {
    // TODO: Read general regs
    pub fn read_status_reg(&self) -> u32 {
        0 // TODO: Properly implement this
    }
}
<|endoftext|>


<commit_before><commit_msg>Track failed tests<commit_after><|endoftext|>


<commit_before><commit_msg>Rename Arc to ServoArc in layout_2020::dom_traversal<commit_after><|endoftext|>


<commit_before><commit_msg>Advent day7_2<commit_after><|endoftext|>


<commit_before>use cliargsparser::CliArgsParser;
use dirs;
use gettextrs::gettext;
use libc;
use logger::{self, Level};
use std::fs::{self, DirBuilder};
use std::io;
use std::os::unix::fs::DirBuilderExt;
use std::path::{Path, PathBuf};
use utils;
use xdg;

pub const NEWSBOAT_SUBDIR_XDG: &str = "newsboat";
pub const NEWSBOAT_CONFIG_SUBDIR: &str = ".newsboat";
pub const NEWSBEUTER_SUBDIR_XDG: &str = "newsbeuter";
pub const NEWSBEUTER_CONFIG_SUBDIR: &str = ".newsbeuter";
pub const LOCK_SUFFIX: &str = ".lock";

const URLS_FILENAME: &str = "urls";
const CACHE_FILENAME: &str = "cache.db";
const CONFIG_FILENAME: &str = "config";
const QUEUE_FILENAME: &str = "queue";
const SEARCH_HISTORY_FILENAME: &str = "history.search";
const CMDLINE_HISTORY_FILENAME: &str = "history.cmdline";

#[derive(Debug)]
pub struct ConfigPaths {
    env_home: PathBuf,
    error_message: String,

    data_dir: PathBuf,
    config_dir: PathBuf,

    url_file: PathBuf,
    cache_file: PathBuf,
    config_file: PathBuf,
    lock_file: PathBuf,
    queue_file: PathBuf,
    search_file: PathBuf,
    cmdline_file: PathBuf,

    silent: bool,
    using_nonstandard_configs: bool,
}

impl ConfigPaths {
    pub fn new() -> ConfigPaths {
        let mut config_paths = ConfigPaths {
            env_home: PathBuf::new(),
            error_message: String::new(),

            data_dir: PathBuf::new(),
            config_dir: PathBuf::new(),

            url_file: PathBuf::new(),
            cache_file: PathBuf::new(),
            config_file: PathBuf::new(),
            lock_file: PathBuf::new(),
            queue_file: PathBuf::new(),
            search_file: PathBuf::new(),
            cmdline_file: PathBuf::new(),

            silent: false,
            using_nonstandard_configs: false,
        };

        let env_home = dirs::home_dir();
        if env_home.is_none() {
            let uid = unsafe { libc::getuid() };

            config_paths.error_message = fmt!(
                &gettext(
                    "Fatal error: couldn't determine home directory!\n\
                     Please set the HOME environment variable or add \
                     a valid user for UID %u!"
                ),
                uid
            );

            return config_paths;
        }

        // hitting this branch means we found a home directory
        // we can now safely call unwrap on all other functions in the dirs crate

        config_paths.env_home = env_home.unwrap();
        config_paths.find_dirs();
        config_paths
    }

    fn migrate_data_from_newsbeuter_xdg(&mut self) -> bool {
        // This can't panic because we've tested we can find the home directory in ConfigPaths::new
        // This should be replaced with proper error handling after this is not used by c++ anymore
        let xdg_dirs = xdg::BaseDirectories::new().unwrap();
        let xdg_config_dir = xdg_dirs.get_config_home();
        let xdg_data_dir = xdg_dirs.get_data_home();

        let newsbeuter_config_dir = xdg_config_dir.join(NEWSBEUTER_SUBDIR_XDG);
        let newsbeuter_data_dir = xdg_data_dir.join(NEWSBEUTER_SUBDIR_XDG);

        let newsboat_config_dir = xdg_config_dir.join(NEWSBOAT_SUBDIR_XDG);
        let newsboat_data_dir = xdg_data_dir.join(NEWSBOAT_SUBDIR_XDG);

        if !newsbeuter_config_dir.is_dir() {
            return false;
        }

        fn exists(path: &Path) -> bool {
            let exists = path.exists();
            if exists {
                log!(
                    Level::Debug,
                    "{:?} already exists, aborting XDG migration.",
                    path
                );
            }
            return exists;
        }

        if exists(&newsboat_config_dir) {
            return false;
        }

        if exists(&newsboat_data_dir) {
            return false;
        }

        self.config_dir = newsboat_config_dir;
        self.data_dir = newsboat_data_dir;

        if !self.silent {
            eprintln!(
                "{}",
                &gettext("Migrating configs and data from Newsbeuter's XDG dirs...")
            );
        }

        if !try_mkdir(&self.config_dir) {
            return false;
        }

        if !try_mkdir(&self.data_dir) {
            return false;
        }

        // We ignore the return codes because it's okay if some files are missing.

        // in config
        let _ = migrate_file(&newsbeuter_config_dir, &self.config_dir, URLS_FILENAME);
        let _ = migrate_file(&newsbeuter_config_dir, &self.config_dir, CONFIG_FILENAME);

        // in data
        let _ = migrate_file(&newsbeuter_data_dir, &self.data_dir, CACHE_FILENAME);
        let _ = migrate_file(&newsbeuter_data_dir, &self.data_dir, QUEUE_FILENAME);
        let _ = migrate_file(
            &newsbeuter_data_dir,
            &self.data_dir,
            SEARCH_HISTORY_FILENAME,
        );
        let _ = migrate_file(
            &newsbeuter_data_dir,
            &self.data_dir,
            CMDLINE_HISTORY_FILENAME,
        );

        return true;
    }

    fn migrate_data_from_newsbeuter_simple(&self) -> bool {
        let newsbeuter_dir = self.env_home.join(NEWSBEUTER_CONFIG_SUBDIR);

        if !newsbeuter_dir.is_dir() {
            return false;
        }

        let newsboat_dir = self.env_home.join(NEWSBOAT_CONFIG_SUBDIR);

        if newsboat_dir.exists() {
            log!(
                Level::Debug,
                "{:?} already exists, aborting migration.",
                newsboat_dir
            );
            return false;
        }

        if !self.silent {
            eprintln!(
                "{}",
                &gettext("Migrating configs and data from Newsbeuter's dotdir...")
            );
        }

        match mkdir(&newsboat_dir, 0o700) {
            Ok(_) => (),
            Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => (),
            Err(err) => {
                if !self.silent {
                    eprintln!(
                        "{}",
                        &fmt!(
                            &gettext("Aborting migration because mkdir on `%s' failed: %s"),
                            &newsboat_dir.to_string_lossy().into_owned(),
                            err.to_string()
                        )
                    );
                }
                return false;
            }
        };

        // We ignore the return codes because it's okay if some files are missing.
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, URLS_FILENAME);
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, CACHE_FILENAME);
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, CONFIG_FILENAME);
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, QUEUE_FILENAME);
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, SEARCH_HISTORY_FILENAME);
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, CMDLINE_HISTORY_FILENAME);

        return true;
    }

    fn migrate_data_from_newsbeuter(&mut self) -> bool {
        let mut migrated = self.migrate_data_from_newsbeuter_xdg();

        if migrated {
            // Re-running to pick up XDG dirs
            self.find_dirs();
        } else {
            migrated = self.migrate_data_from_newsbeuter_simple();
        }

        migrated
    }

    pub fn create_dirs(&self) -> bool {
        return try_mkdir(&self.config_dir) && try_mkdir(&self.data_dir);
    }

    fn find_dirs(&mut self) {
        self.config_dir = self.env_home.join(NEWSBOAT_CONFIG_SUBDIR);

        self.data_dir = self.config_dir.clone();

        // Will change config_dir and data_dir to point to XDG if XDG
        // directories are available.
        self.find_dirs_xdg();

        // in config
        self.url_file = self.config_dir.join(URLS_FILENAME);
        self.config_file = self.config_dir.join(CONFIG_FILENAME);

        // in data
        self.cache_file = self.data_dir.join(CACHE_FILENAME);
        self.lock_file = self.data_dir.join(CACHE_FILENAME.to_owned() + LOCK_SUFFIX);
        self.queue_file = self.data_dir.join(QUEUE_FILENAME);
        self.search_file = self.data_dir.join(SEARCH_HISTORY_FILENAME);
        self.cmdline_file = self.data_dir.join(CMDLINE_HISTORY_FILENAME);
    }

    fn find_dirs_xdg(&mut self) {
        // This can't panic because we've tested we can find the home directory in ConfigPaths::new
        // This should be replaced with proper error handling after this is not used by c++ anymore
        let xdg_dirs = xdg::BaseDirectories::new().unwrap();
        let config_dir = xdg_dirs.get_config_home().join(NEWSBOAT_SUBDIR_XDG);
        let data_dir = xdg_dirs.get_data_home().join(NEWSBOAT_SUBDIR_XDG);

        if !config_dir.is_dir() {
            return;
        }

        /* Invariant: config dir exists.
         *
         * At this point, we're confident we'll be using XDG. We don't check if
         * data dir exists, because if it doesn't we'll create it. */

        self.config_dir = config_dir;
        self.data_dir = data_dir;
    }

    /// Indicates if the object can be used.
    ///
    /// If this method returned `false`, the cause for initialization failure can be found using
    /// `error_message()`.
    pub fn initialized(&self) -> bool {
        !self.env_home.as_os_str().is_empty()
    }

    /// Returns explanation why initialization failed.
    ///
    /// \note You shouldn't call this unless `initialized()` returns `false`.
    pub fn error_message(&self) -> &str {
        &self.error_message
    }

    /// Initializes paths to config, cache etc. from CLI arguments.
    pub fn process_args(&mut self, args: &CliArgsParser) {
        if let Some(ref url_file) = args.url_file {
            self.url_file = Path::new(url_file).to_owned();
        }

        if let Some(ref cache_file) = args.cache_file {
            self.cache_file = Path::new(cache_file).to_owned();
        }

        if let Some(ref lock_file) = args.lock_file {
            self.lock_file = Path::new(lock_file).to_owned();
        }

        if let Some(ref config_file) = args.config_file {
            self.config_file = Path::new(config_file).to_owned();
        }

        self.silent = args.silent;
        self.using_nonstandard_configs = args.using_nonstandard_configs();
    }

    /// Migrate configs and data from Newsbeuter if they exist. Return `true` if migrated
    /// something, `false` otherwise.
    pub fn try_migrate_from_newsbeuter(&mut self) -> bool {
        if !self.using_nonstandard_configs && !&self.url_file.exists() {
            return self.migrate_data_from_newsbeuter();
        }

        // No migration occurred.
        false
    }

    /// Path to the URLs file.
    pub fn url_file(&self) -> &Path {
        &self.url_file
    }

    /// Path to the cache file.
    pub fn cache_file(&self) -> &Path {
        &self.cache_file
    }

    /// Sets path to the cache file.
    // FIXME: this is actually a kludge that lets Controller change the path
    // midway. That logic should be moved into ConfigPaths, and this method
    // removed.
    pub fn set_cache_file(&mut self, mut path: PathBuf) {
        self.cache_file = path.clone();
        self.lock_file = {
            let current_extension = path
                .extension()
                .and_then(|p| Some(p.to_string_lossy().into_owned()))
                .unwrap_or_else(|| String::new());
            path.set_extension(current_extension + LOCK_SUFFIX);
            path
        };
    }

    /// Path to the config file.
    pub fn config_file(&self) -> &Path {
        &self.config_file
    }

    /// Path to the lock file.
    ///
    /// \note This changes when path to config file changes.
    pub fn lock_file(&self) -> &Path {
        &self.lock_file
    }

    /// \brief Path to the queue file.
    ///
    /// Queue file stores enqueued podcasts. It's written by Newsboat, and read by Podboat.
    pub fn queue_file(&self) -> &Path {
        &self.queue_file
    }

    /// Path to the file with previous search queries.
    pub fn search_file(&self) -> &Path {
        &self.search_file
    }

    /// Path to the file with command-line history.
    pub fn cmdline_file(&self) -> &Path {
        &self.cmdline_file
    }
}

fn try_mkdir<R: AsRef<Path>>(path: R) -> bool {
    utils::mkdir_parents(&path.as_ref(), 0o700).is_ok()
}

fn mkdir<R: AsRef<Path>>(path: R, mode: u32) -> io::Result<()> {
    DirBuilder::new().mode(mode).create(path.as_ref())
}

fn migrate_file<R: AsRef<Path>>(newsbeuter_dir: R, newsboat_dir: R, file: &str) -> io::Result<()> {
    let input_filepath = newsbeuter_dir.as_ref().join(file);
    let output_filepath = newsboat_dir.as_ref().join(file);
    eprintln!("{:?} -> {:?}", input_filepath, output_filepath);
    fs::copy(input_filepath, output_filepath).map(|_| ())
}
<commit_msg>Reformat code with cargo fmt<commit_after>use cliargsparser::CliArgsParser;
use dirs;
use gettextrs::gettext;
use libc;
use logger::{self, Level};
use std::fs::{self, DirBuilder};
use std::io;
use std::os::unix::fs::DirBuilderExt;
use std::path::{Path, PathBuf};
use utils;
use xdg;

pub const NEWSBOAT_SUBDIR_XDG: &str = "newsboat";
pub const NEWSBOAT_CONFIG_SUBDIR: &str = ".newsboat";
pub const NEWSBEUTER_SUBDIR_XDG: &str = "newsbeuter";
pub const NEWSBEUTER_CONFIG_SUBDIR: &str = ".newsbeuter";
pub const LOCK_SUFFIX: &str = ".lock";

const URLS_FILENAME: &str = "urls";
const CACHE_FILENAME: &str = "cache.db";
const CONFIG_FILENAME: &str = "config";
const QUEUE_FILENAME: &str = "queue";
const SEARCH_HISTORY_FILENAME: &str = "history.search";
const CMDLINE_HISTORY_FILENAME: &str = "history.cmdline";

#[derive(Debug)]
pub struct ConfigPaths {
    env_home: PathBuf,
    error_message: String,

    data_dir: PathBuf,
    config_dir: PathBuf,

    url_file: PathBuf,
    cache_file: PathBuf,
    config_file: PathBuf,
    lock_file: PathBuf,
    queue_file: PathBuf,
    search_file: PathBuf,
    cmdline_file: PathBuf,

    silent: bool,
    using_nonstandard_configs: bool,
}

impl ConfigPaths {
    pub fn new() -> ConfigPaths {
        let mut config_paths = ConfigPaths {
            env_home: PathBuf::new(),
            error_message: String::new(),

            data_dir: PathBuf::new(),
            config_dir: PathBuf::new(),

            url_file: PathBuf::new(),
            cache_file: PathBuf::new(),
            config_file: PathBuf::new(),
            lock_file: PathBuf::new(),
            queue_file: PathBuf::new(),
            search_file: PathBuf::new(),
            cmdline_file: PathBuf::new(),

            silent: false,
            using_nonstandard_configs: false,
        };

        let env_home = dirs::home_dir();
        if env_home.is_none() {
            let uid = unsafe { libc::getuid() };

            config_paths.error_message = fmt!(
                &gettext(
                    "Fatal error: couldn't determine home directory!\n\
                     Please set the HOME environment variable or add \
                     a valid user for UID %u!"
                ),
                uid
            );

            return config_paths;
        }

        // hitting this branch means we found a home directory
        // we can now safely call unwrap on all other functions in the dirs crate

        config_paths.env_home = env_home.unwrap();
        config_paths.find_dirs();
        config_paths
    }

    fn migrate_data_from_newsbeuter_xdg(&mut self) -> bool {
        // This can't panic because we've tested we can find the home directory in ConfigPaths::new
        // This should be replaced with proper error handling after this is not used by c++ anymore
        let xdg_dirs = xdg::BaseDirectories::new().unwrap();
        let xdg_config_dir = xdg_dirs.get_config_home();
        let xdg_data_dir = xdg_dirs.get_data_home();

        let newsbeuter_config_dir = xdg_config_dir.join(NEWSBEUTER_SUBDIR_XDG);
        let newsbeuter_data_dir = xdg_data_dir.join(NEWSBEUTER_SUBDIR_XDG);

        let newsboat_config_dir = xdg_config_dir.join(NEWSBOAT_SUBDIR_XDG);
        let newsboat_data_dir = xdg_data_dir.join(NEWSBOAT_SUBDIR_XDG);

        if !newsbeuter_config_dir.is_dir() {
            return false;
        }

        fn exists(path: &Path) -> bool {
            let exists = path.exists();
            if exists {
                log!(
                    Level::Debug,
                    "{:?} already exists, aborting XDG migration.",
                    path
                );
            }
            return exists;
        }

        if exists(&newsboat_config_dir) {
            return false;
        }

        if exists(&newsboat_data_dir) {
            return false;
        }

        self.config_dir = newsboat_config_dir;
        self.data_dir = newsboat_data_dir;

        if !self.silent {
            eprintln!(
                "{}",
                &gettext("Migrating configs and data from Newsbeuter's XDG dirs...")
            );
        }

        if !try_mkdir(&self.config_dir) {
            return false;
        }

        if !try_mkdir(&self.data_dir) {
            return false;
        }

        // We ignore the return codes because it's okay if some files are missing.

        // in config
        let _ = migrate_file(&newsbeuter_config_dir, &self.config_dir, URLS_FILENAME);
        let _ = migrate_file(&newsbeuter_config_dir, &self.config_dir, CONFIG_FILENAME);

        // in data
        let _ = migrate_file(&newsbeuter_data_dir, &self.data_dir, CACHE_FILENAME);
        let _ = migrate_file(&newsbeuter_data_dir, &self.data_dir, QUEUE_FILENAME);
        let _ = migrate_file(
            &newsbeuter_data_dir,
            &self.data_dir,
            SEARCH_HISTORY_FILENAME,
        );
        let _ = migrate_file(
            &newsbeuter_data_dir,
            &self.data_dir,
            CMDLINE_HISTORY_FILENAME,
        );

        return true;
    }

    fn migrate_data_from_newsbeuter_simple(&self) -> bool {
        let newsbeuter_dir = self.env_home.join(NEWSBEUTER_CONFIG_SUBDIR);

        if !newsbeuter_dir.is_dir() {
            return false;
        }

        let newsboat_dir = self.env_home.join(NEWSBOAT_CONFIG_SUBDIR);

        if newsboat_dir.exists() {
            log!(
                Level::Debug,
                "{:?} already exists, aborting migration.",
                newsboat_dir
            );
            return false;
        }

        if !self.silent {
            eprintln!(
                "{}",
                &gettext("Migrating configs and data from Newsbeuter's dotdir...")
            );
        }

        match mkdir(&newsboat_dir, 0o700) {
            Ok(_) => (),
            Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => (),
            Err(err) => {
                if !self.silent {
                    eprintln!(
                        "{}",
                        &fmt!(
                            &gettext("Aborting migration because mkdir on `%s' failed: %s"),
                            &newsboat_dir.to_string_lossy().into_owned(),
                            err.to_string()
                        )
                    );
                }
                return false;
            }
        };

        // We ignore the return codes because it's okay if some files are missing.
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, URLS_FILENAME);
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, CACHE_FILENAME);
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, CONFIG_FILENAME);
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, QUEUE_FILENAME);
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, SEARCH_HISTORY_FILENAME);
        let _ = migrate_file(&newsbeuter_dir, &newsboat_dir, CMDLINE_HISTORY_FILENAME);

        return true;
    }

    fn migrate_data_from_newsbeuter(&mut self) -> bool {
        let mut migrated = self.migrate_data_from_newsbeuter_xdg();

        if migrated {
            // Re-running to pick up XDG dirs
            self.find_dirs();
        } else {
            migrated = self.migrate_data_from_newsbeuter_simple();
        }

        migrated
    }

    pub fn create_dirs(&self) -> bool {
        return try_mkdir(&self.config_dir) && try_mkdir(&self.data_dir);
    }

    fn find_dirs(&mut self) {
        self.config_dir = self.env_home.join(NEWSBOAT_CONFIG_SUBDIR);

        self.data_dir = self.config_dir.clone();

        // Will change config_dir and data_dir to point to XDG if XDG
        // directories are available.
        self.find_dirs_xdg();

        // in config
        self.url_file = self.config_dir.join(URLS_FILENAME);
        self.config_file = self.config_dir.join(CONFIG_FILENAME);

        // in data
        self.cache_file = self.data_dir.join(CACHE_FILENAME);
        self.lock_file = self.data_dir.join(CACHE_FILENAME.to_owned() + LOCK_SUFFIX);
        self.queue_file = self.data_dir.join(QUEUE_FILENAME);
        self.search_file = self.data_dir.join(SEARCH_HISTORY_FILENAME);
        self.cmdline_file = self.data_dir.join(CMDLINE_HISTORY_FILENAME);
    }

    fn find_dirs_xdg(&mut self) {
        // This can't panic because we've tested we can find the home directory in ConfigPaths::new
        // This should be replaced with proper error handling after this is not used by c++ anymore
        let xdg_dirs = xdg::BaseDirectories::new().unwrap();
        let config_dir = xdg_dirs.get_config_home().join(NEWSBOAT_SUBDIR_XDG);
        let data_dir = xdg_dirs.get_data_home().join(NEWSBOAT_SUBDIR_XDG);

        if !config_dir.is_dir() {
            return;
        }

        /* Invariant: config dir exists.
         *
         * At this point, we're confident we'll be using XDG. We don't check if
         * data dir exists, because if it doesn't we'll create it. */

        self.config_dir = config_dir;
        self.data_dir = data_dir;
    }

    /// Indicates if the object can be used.
    ///
    /// If this method returned `false`, the cause for initialization failure can be found using
    /// `error_message()`.
    pub fn initialized(&self) -> bool {
        !self.env_home.as_os_str().is_empty()
    }

    /// Returns explanation why initialization failed.
    ///
    /// \note You shouldn't call this unless `initialized()` returns `false`.
    pub fn error_message(&self) -> &str {
        &self.error_message
    }

    /// Initializes paths to config, cache etc. from CLI arguments.
    pub fn process_args(&mut self, args: &CliArgsParser) {
        if let Some(ref url_file) = args.url_file {
            self.url_file = Path::new(url_file).to_owned();
        }

        if let Some(ref cache_file) = args.cache_file {
            self.cache_file = Path::new(cache_file).to_owned();
        }

        if let Some(ref lock_file) = args.lock_file {
            self.lock_file = Path::new(lock_file).to_owned();
        }

        if let Some(ref config_file) = args.config_file {
            self.config_file = Path::new(config_file).to_owned();
        }

        self.silent = args.silent;
        self.using_nonstandard_configs = args.using_nonstandard_configs();
    }

    /// Migrate configs and data from Newsbeuter if they exist. Return `true` if migrated
    /// something, `false` otherwise.
    pub fn try_migrate_from_newsbeuter(&mut self) -> bool {
        if !self.using_nonstandard_configs && !&self.url_file.exists() {
            return self.migrate_data_from_newsbeuter();
        }

        // No migration occurred.
        false
    }

    /// Path to the URLs file.
    pub fn url_file(&self) -> &Path {
        &self.url_file
    }

    /// Path to the cache file.
    pub fn cache_file(&self) -> &Path {
        &self.cache_file
    }

    /// Sets path to the cache file.
    // FIXME: this is actually a kludge that lets Controller change the path
    // midway. That logic should be moved into ConfigPaths, and this method
    // removed.
    pub fn set_cache_file(&mut self, mut path: PathBuf) {
        self.cache_file = path.clone();
        self.lock_file = {
            let current_extension = path
                .extension()
                .and_then(|p| Some(p.to_string_lossy().into_owned()))
                .unwrap_or_else(|| String::new());
            path.set_extension(current_extension + LOCK_SUFFIX);
            path
        };
    }

    /// Path to the config file.
    pub fn config_file(&self) -> &Path {
        &self.config_file
    }

    /// Path to the lock file.
    ///
    /// \note This changes when path to config file changes.
    pub fn lock_file(&self) -> &Path {
        &self.lock_file
    }

    /// \brief Path to the queue file.
    ///
    /// Queue file stores enqueued podcasts. It's written by Newsboat, and read by Podboat.
    pub fn queue_file(&self) -> &Path {
        &self.queue_file
    }

    /// Path to the file with previous search queries.
    pub fn search_file(&self) -> &Path {
        &self.search_file
    }

    /// Path to the file with command-line history.
    pub fn cmdline_file(&self) -> &Path {
        &self.cmdline_file
    }
}

fn try_mkdir<R: AsRef<Path>>(path: R) -> bool {
    utils::mkdir_parents(&path.as_ref(), 0o700).is_ok()
}

fn mkdir<R: AsRef<Path>>(path: R, mode: u32) -> io::Result<()> {
    DirBuilder::new().mode(mode).create(path.as_ref())
}

fn migrate_file<R: AsRef<Path>>(newsbeuter_dir: R, newsboat_dir: R, file: &str) -> io::Result<()> {
    let input_filepath = newsbeuter_dir.as_ref().join(file);
    let output_filepath = newsboat_dir.as_ref().join(file);
    eprintln!("{:?} -> {:?}", input_filepath, output_filepath);
    fs::copy(input_filepath, output_filepath).map(|_| ())
}
<|endoftext|>


<commit_before><commit_msg>Fix for #532 Liner seems to be doing some very limited form of multi-line comment support, itself. This change will strip out the excess characters that are returned by liner.<commit_after><|endoftext|>


<commit_before>import syntax::ast::*;
import syntax::walk;
import std::ivec;
import std::option::*;
import aux::*;
import tstate::ann::pre_and_post;
import tstate::ann::precond;
import tstate::ann::postcond;
import tstate::ann::prestate;
import tstate::ann::poststate;
import tstate::ann::relax_prestate;
import tstate::ann::relax_precond;
import tstate::ann::relax_poststate;
import tstate::ann::pps_len;
import tstate::ann::true_precond;
import tstate::ann::empty_prestate;
import tstate::ann::difference;
import tstate::ann::union;
import tstate::ann::intersect;
import tstate::ann::clone;
import tstate::ann::set_in_postcond;
import tstate::ann::set_in_poststate;
import tstate::ann::set_in_poststate_;
import tstate::ann::clear_in_poststate;
import tstate::ann::clear_in_prestate;
import tstate::ann::clear_in_poststate_;
import tritv::*;

fn bit_num(fcx: &fn_ctxt, c: &tsconstr) -> uint {
    let d = tsconstr_to_def_id(c);
    assert (fcx.enclosing.constrs.contains_key(d));
    let rslt = fcx.enclosing.constrs.get(d);
    alt c {
      ninit(_, _) {
        alt rslt {
          cinit(n, _, _) { ret n; }
          _ {
            fcx.ccx.tcx.sess.bug("bit_num: asked for init constraint," +
                                     " found a pred constraint");
          }
        }
      }
      npred(_, _, args) {
        alt rslt {
          cpred(_, descs) { ret match_args(fcx, descs, args); }
          _ {
            fcx.ccx.tcx.sess.bug("bit_num: asked for pred constraint," +
                                     " found an init constraint");
          }
        }
      }
    }
}

fn promises(fcx: &fn_ctxt, p: &poststate, c: &tsconstr) -> bool {
    ret promises_(bit_num(fcx, c), p);
}

fn promises_(n: uint, p: &poststate) -> bool { ret tritv_get(p, n) == ttrue; }

// v "happens after" u
fn seq_trit(u: trit, v: trit) -> trit {
    alt v { ttrue. { ttrue } tfalse. { tfalse } dont_care. { u } }
}

// idea: q "happens after" p -- so if something is
// 1 in q and 0 in p, it's 1 in the result; however,
// if it's 0 in q and 1 in p, it's 0 in the result
fn seq_tritv(p: &postcond, q: &postcond) {
    let i = 0u;
    assert (p.nbits == q.nbits);
    while i < p.nbits {
        tritv_set(i, p, seq_trit(tritv_get(p, i), tritv_get(q, i)));
        i += 1u;
    }
}

fn seq_postconds(fcx: &fn_ctxt, ps: &postcond[]) -> postcond {
    let sz = ivec::len(ps);
    if sz >= 1u {
        let prev = tritv_clone(ps.(0));
        for p: postcond  in ivec::slice(ps, 1u, sz) { seq_tritv(prev, p); }
        ret prev;
    } else { ret ann::empty_poststate(num_constraints(fcx.enclosing)); }
}

// Given a list of pres and posts for exprs e0 ... en,
// return the precondition for evaluating each expr in order.
// So, if e0's post is {x} and e1's pre is {x, y, z}, the entire
// precondition shouldn't include x.
fn seq_preconds(fcx: &fn_ctxt, pps: &pre_and_post[]) -> precond {
    let sz: uint = ivec::len(pps);
    let num_vars: uint = num_constraints(fcx.enclosing);

    fn seq_preconds_go(fcx: &fn_ctxt, pps: &pre_and_post[],
                       first: &pre_and_post) -> precond {
        let sz: uint = ivec::len(pps);
        if sz >= 1u {
            let second = pps.(0);
            assert (pps_len(second) == num_constraints(fcx.enclosing));
            let second_pre = clone(second.precondition);
            difference(second_pre, first.postcondition);
            let next_first = clone(first.precondition);
            union(next_first, second_pre);
            let next_first_post = clone(first.postcondition);
            seq_tritv(next_first_post, second.postcondition);
            ret seq_preconds_go(fcx, ivec::slice(pps, 1u, sz),
                                @{precondition: next_first,
                                  postcondition: next_first_post});
        } else { ret first.precondition; }
    }

    if sz >= 1u {
        let first = pps.(0);
        assert (pps_len(first) == num_vars);
        ret seq_preconds_go(fcx, ivec::slice(pps, 1u, sz), first);
    } else { ret true_precond(num_vars); }
}

fn intersect_states(p: &prestate, q: &prestate) -> prestate {
    let rslt = tritv_clone(p);
    tritv_intersect(rslt, q);
    ret rslt;
}

fn gen(fcx: &fn_ctxt, id: node_id, c: &tsconstr) -> bool {
    ret set_in_postcond(bit_num(fcx, c),
                        node_id_to_ts_ann(fcx.ccx, id).conditions);
}

fn declare_var(fcx: &fn_ctxt, c: &tsconstr, pre: prestate) -> prestate {
    let rslt = clone(pre);
    relax_prestate(bit_num(fcx, c), rslt);
    // idea is this is scoped
    relax_poststate(bit_num(fcx, c), rslt);
    ret rslt;
}

fn relax_precond_block_non_recursive(fcx: &fn_ctxt, i: node_id, b: &blk) {
    relax_precond(i as uint, block_precond(fcx.ccx, b));
}

fn relax_precond_expr(fcx: &fn_ctxt, i: node_id, e: &@expr) {
    relax_precond(i as uint, expr_precond(fcx.ccx, e));
}

fn relax_precond_stmt(fcx: &fn_ctxt, i: node_id, s: &@stmt) {
    relax_precond(i as uint, stmt_precond(fcx.ccx, *s));
}

fn relax_precond_block(fcx: &fn_ctxt, i: node_id, b: &blk) {
    relax_precond_block_non_recursive(fcx, i, b);
    // FIXME: should use visit instead
    // could at least generalize this pattern
    // (also seen in ck::check_states_against_conditions)
    let keepgoing: @mutable bool = @mutable true;

    fn quit(keepgoing: @mutable bool, i: &@item) { *keepgoing = false; }
    fn kg(keepgoing: @mutable bool) -> bool { ret *keepgoing; }

    let v =
        {visit_block_pre: bind relax_precond_block_non_recursive(fcx, i, _),
         visit_expr_pre: bind relax_precond_expr(fcx, i, _),
         visit_stmt_pre: bind relax_precond_stmt(fcx, i, _),
         visit_item_pre: bind quit(keepgoing, _),
         keep_going: bind kg(keepgoing) with walk::default_visitor()};
    walk::walk_block(v, b);
}

fn gen_poststate(fcx: &fn_ctxt, id: node_id, c: &tsconstr) -> bool {
    log "gen_poststate";
    ret set_in_poststate(bit_num(fcx, c),
                         node_id_to_ts_ann(fcx.ccx, id).states);
}

fn kill_prestate(fcx: &fn_ctxt, id: node_id, c: &tsconstr) -> bool {
    ret clear_in_prestate(bit_num(fcx, c),
                          node_id_to_ts_ann(fcx.ccx, id).states);
}

fn kill_poststate(fcx: &fn_ctxt, id: node_id, c: &tsconstr) -> bool {
    log "kill_poststate";
    ret clear_in_poststate(bit_num(fcx, c),
                           node_id_to_ts_ann(fcx.ccx, id).states);
}

fn clear_in_poststate_expr(fcx: &fn_ctxt, e: &@expr, t: &poststate) {
    alt e.node {
      expr_path(p) {
        alt ivec::last(p.node.idents) {
          some(i) {
            alt local_node_id_to_def(fcx, e.id) {
              some(def_local(d_id)) {
                clear_in_poststate_(bit_num(fcx, ninit(d_id.node, i)), t);
              }
              some(_) {/* ignore args (for now...) */ }
              _ {
                fcx.ccx.tcx.sess.bug("clear_in_poststate_expr: \
                                   unbound var");
              }
            }
          }
          _ { fcx.ccx.tcx.sess.bug("clear_in_poststate_expr"); }
        }
      }
      _ {/* do nothing */ }
    }
}

fn kill_poststate_(fcx : &fn_ctxt, c : &tsconstr, post : &poststate) -> bool {
    log "kill_poststate_";
    ret clear_in_poststate_(bit_num(fcx, c), post);
}

fn set_in_poststate_ident(fcx: &fn_ctxt, id: &node_id, ident: &ident,
                          t: &poststate) -> bool {
    ret set_in_poststate_(bit_num(fcx, ninit(id, ident)), t);
}

fn set_in_prestate_constr(fcx: &fn_ctxt, c: &tsconstr, t: &prestate) -> bool {
    ret set_in_poststate_(bit_num(fcx, c), t);
}

fn clear_in_poststate_ident(fcx: &fn_ctxt, id: &node_id, ident: &ident,
                            parent: &node_id) -> bool {
    ret kill_poststate(fcx, parent, ninit(id, ident));
}

fn clear_in_prestate_ident(fcx: &fn_ctxt, id: &node_id, ident: &ident,
                           parent: &node_id) -> bool {
    ret kill_prestate(fcx, parent, ninit(id, ident));
}

fn clear_in_poststate_ident_(fcx : &fn_ctxt, id : &node_id, ident : &ident,
                             post : &poststate) -> bool {
    ret kill_poststate_(fcx, ninit(id, ident), post);
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>Change bitvectors::relax_precond_block to use visit instead of walk<commit_after>import syntax::ast::*;
import syntax::visit;
import std::ivec;
import std::option::*;
import aux::*;
import tstate::ann::pre_and_post;
import tstate::ann::precond;
import tstate::ann::postcond;
import tstate::ann::prestate;
import tstate::ann::poststate;
import tstate::ann::relax_prestate;
import tstate::ann::relax_precond;
import tstate::ann::relax_poststate;
import tstate::ann::pps_len;
import tstate::ann::true_precond;
import tstate::ann::empty_prestate;
import tstate::ann::difference;
import tstate::ann::union;
import tstate::ann::intersect;
import tstate::ann::clone;
import tstate::ann::set_in_postcond;
import tstate::ann::set_in_poststate;
import tstate::ann::set_in_poststate_;
import tstate::ann::clear_in_poststate;
import tstate::ann::clear_in_prestate;
import tstate::ann::clear_in_poststate_;
import tritv::*;
import util::common::*;

fn bit_num(fcx: &fn_ctxt, c: &tsconstr) -> uint {
    let d = tsconstr_to_def_id(c);
    assert (fcx.enclosing.constrs.contains_key(d));
    let rslt = fcx.enclosing.constrs.get(d);
    alt c {
      ninit(_, _) {
        alt rslt {
          cinit(n, _, _) { ret n; }
          _ {
            fcx.ccx.tcx.sess.bug("bit_num: asked for init constraint," +
                                     " found a pred constraint");
          }
        }
      }
      npred(_, _, args) {
        alt rslt {
          cpred(_, descs) { ret match_args(fcx, descs, args); }
          _ {
            fcx.ccx.tcx.sess.bug("bit_num: asked for pred constraint," +
                                     " found an init constraint");
          }
        }
      }
    }
}

fn promises(fcx: &fn_ctxt, p: &poststate, c: &tsconstr) -> bool {
    ret promises_(bit_num(fcx, c), p);
}

fn promises_(n: uint, p: &poststate) -> bool { ret tritv_get(p, n) == ttrue; }

// v "happens after" u
fn seq_trit(u: trit, v: trit) -> trit {
    alt v { ttrue. { ttrue } tfalse. { tfalse } dont_care. { u } }
}

// idea: q "happens after" p -- so if something is
// 1 in q and 0 in p, it's 1 in the result; however,
// if it's 0 in q and 1 in p, it's 0 in the result
fn seq_tritv(p: &postcond, q: &postcond) {
    let i = 0u;
    assert (p.nbits == q.nbits);
    while i < p.nbits {
        tritv_set(i, p, seq_trit(tritv_get(p, i), tritv_get(q, i)));
        i += 1u;
    }
}

fn seq_postconds(fcx: &fn_ctxt, ps: &postcond[]) -> postcond {
    let sz = ivec::len(ps);
    if sz >= 1u {
        let prev = tritv_clone(ps.(0));
        for p: postcond  in ivec::slice(ps, 1u, sz) { seq_tritv(prev, p); }
        ret prev;
    } else { ret ann::empty_poststate(num_constraints(fcx.enclosing)); }
}

// Given a list of pres and posts for exprs e0 ... en,
// return the precondition for evaluating each expr in order.
// So, if e0's post is {x} and e1's pre is {x, y, z}, the entire
// precondition shouldn't include x.
fn seq_preconds(fcx: &fn_ctxt, pps: &pre_and_post[]) -> precond {
    let sz: uint = ivec::len(pps);
    let num_vars: uint = num_constraints(fcx.enclosing);

    fn seq_preconds_go(fcx: &fn_ctxt, pps: &pre_and_post[],
                       first: &pre_and_post) -> precond {
        let sz: uint = ivec::len(pps);
        if sz >= 1u {
            let second = pps.(0);
            assert (pps_len(second) == num_constraints(fcx.enclosing));
            let second_pre = clone(second.precondition);
            difference(second_pre, first.postcondition);
            let next_first = clone(first.precondition);
            union(next_first, second_pre);
            let next_first_post = clone(first.postcondition);
            seq_tritv(next_first_post, second.postcondition);
            ret seq_preconds_go(fcx, ivec::slice(pps, 1u, sz),
                                @{precondition: next_first,
                                  postcondition: next_first_post});
        } else { ret first.precondition; }
    }

    if sz >= 1u {
        let first = pps.(0);
        assert (pps_len(first) == num_vars);
        ret seq_preconds_go(fcx, ivec::slice(pps, 1u, sz), first);
    } else { ret true_precond(num_vars); }
}

fn intersect_states(p: &prestate, q: &prestate) -> prestate {
    let rslt = tritv_clone(p);
    tritv_intersect(rslt, q);
    ret rslt;
}

fn gen(fcx: &fn_ctxt, id: node_id, c: &tsconstr) -> bool {
    ret set_in_postcond(bit_num(fcx, c),
                        node_id_to_ts_ann(fcx.ccx, id).conditions);
}

fn declare_var(fcx: &fn_ctxt, c: &tsconstr, pre: prestate) -> prestate {
    let rslt = clone(pre);
    relax_prestate(bit_num(fcx, c), rslt);
    // idea is this is scoped
    relax_poststate(bit_num(fcx, c), rslt);
    ret rslt;
}

fn relax_precond_expr(e: &@expr, cx: &relax_ctxt,
                      vt: &visit::vt[relax_ctxt]) {
    relax_precond(cx.i as uint, expr_precond(cx.fcx.ccx, e));
    visit::visit_expr(e, cx, vt);
}

fn relax_precond_stmt(s: &@stmt, cx: &relax_ctxt,
                      vt: &visit::vt[relax_ctxt]) {
    relax_precond(cx.i as uint, stmt_precond(cx.fcx.ccx, *s));
    visit::visit_stmt(s, cx, vt);
}

type relax_ctxt = {fcx:fn_ctxt, i:node_id};

fn relax_precond_block_inner(b: &blk, cx: &relax_ctxt,
                             vt: &visit::vt[relax_ctxt]) {
    relax_precond(cx.i as uint, block_precond(cx.fcx.ccx, b));
    visit::visit_block(b, cx, vt);
}

fn relax_precond_block(fcx: &fn_ctxt, i: node_id, b:&blk) {
    let cx = {fcx: fcx, i: i};
    let visitor = visit::default_visitor[relax_ctxt]();
    visitor =
        @{visit_block: relax_precond_block_inner,
          visit_expr: relax_precond_expr,
          visit_stmt: relax_precond_stmt,
          visit_item: (fn (i: &@item, cx: &relax_ctxt,
                           vt: &visit::vt[relax_ctxt]) {})
          with *visitor};
    let v1 = visit::mk_vt(visitor);
    v1.visit_block(b, cx, v1);
}

fn gen_poststate(fcx: &fn_ctxt, id: node_id, c: &tsconstr) -> bool {
    log "gen_poststate";
    ret set_in_poststate(bit_num(fcx, c),
                         node_id_to_ts_ann(fcx.ccx, id).states);
}

fn kill_prestate(fcx: &fn_ctxt, id: node_id, c: &tsconstr) -> bool {
    ret clear_in_prestate(bit_num(fcx, c),
                          node_id_to_ts_ann(fcx.ccx, id).states);
}

fn kill_poststate(fcx: &fn_ctxt, id: node_id, c: &tsconstr) -> bool {
    log "kill_poststate";
    ret clear_in_poststate(bit_num(fcx, c),
                           node_id_to_ts_ann(fcx.ccx, id).states);
}

fn clear_in_poststate_expr(fcx: &fn_ctxt, e: &@expr, t: &poststate) {
    alt e.node {
      expr_path(p) {
        alt ivec::last(p.node.idents) {
          some(i) {
            alt local_node_id_to_def(fcx, e.id) {
              some(def_local(d_id)) {
                clear_in_poststate_(bit_num(fcx, ninit(d_id.node, i)), t);
              }
              some(_) {/* ignore args (for now...) */ }
              _ {
                fcx.ccx.tcx.sess.bug("clear_in_poststate_expr: \
                                   unbound var");
              }
            }
          }
          _ { fcx.ccx.tcx.sess.bug("clear_in_poststate_expr"); }
        }
      }
      _ {/* do nothing */ }
    }
}

fn kill_poststate_(fcx : &fn_ctxt, c : &tsconstr, post : &poststate) -> bool {
    log "kill_poststate_";
    ret clear_in_poststate_(bit_num(fcx, c), post);
}

fn set_in_poststate_ident(fcx: &fn_ctxt, id: &node_id, ident: &ident,
                          t: &poststate) -> bool {
    ret set_in_poststate_(bit_num(fcx, ninit(id, ident)), t);
}

fn set_in_prestate_constr(fcx: &fn_ctxt, c: &tsconstr, t: &prestate) -> bool {
    ret set_in_poststate_(bit_num(fcx, c), t);
}

fn clear_in_poststate_ident(fcx: &fn_ctxt, id: &node_id, ident: &ident,
                            parent: &node_id) -> bool {
    ret kill_poststate(fcx, parent, ninit(id, ident));
}

fn clear_in_prestate_ident(fcx: &fn_ctxt, id: &node_id, ident: &ident,
                           parent: &node_id) -> bool {
    ret kill_prestate(fcx, parent, ninit(id, ident));
}

fn clear_in_poststate_ident_(fcx : &fn_ctxt, id : &node_id, ident : &ident,
                             post : &poststate) -> bool {
    ret kill_poststate_(fcx, ninit(id, ident), post);
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>