<commit_before>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#[feature(globs)];
use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{str};

static IP: &'static str = "127.0.0.1";
static PORT:        int = 4414;

fn main() {
    let addr = from_str::<SocketAddr>(format!("{:s}:{:d}", IP, PORT)).unwrap();
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen();
    let mut visitor_count = 0;

    println(format!("Listening on [{:s}] ...", addr.to_str()));

    for stream in acceptor.incoming() {
        // Spawn a task to handle the connection

	visitor_count += 1;
	let count = visitor_count;
        println!("Visitor count: {}", visitor_count);

	do spawn {
            let mut stream = stream;

            match stream {
                Some(ref mut s) => {
                             match s.peer_name() {
                                Some(pn) => {println(format!("Received connection from: [{:s}]", pn.to_str()));},
                                None => ()
                             }
                           },
                None => ()
            }

            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);
            println(format!("Received request :\n{:s}", request_str));

            let response: ~str =
                ~"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                 <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

                 \r\n";
            stream.write(response.as_bytes());
            println!("Connection terminates.");
	    println!("Count: {}", count);
        }
    }
}
<commit_msg>greets visitors by number<commit_after>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#[feature(globs)];
use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{str};

static IP: &'static str = "127.0.0.1";
static PORT:        int = 4414;

fn main() {
    let addr = from_str::<SocketAddr>(format!("{:s}:{:d}", IP, PORT)).unwrap();
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen();
    let mut visitor_count = 0;

    println(format!("Listening on [{:s}] ...", addr.to_str()));

    for stream in acceptor.incoming() {
        // Spawn a task to handle the connection

	visitor_count += 1;
	let count: int = visitor_count;
        println!("Visitor count: {}", visitor_count);

	do spawn {
            let mut stream = stream;

            match stream {
                Some(ref mut s) => {
                             match s.peer_name() {
                                Some(pn) => {println(format!("Received connection from: [{:s}]", pn.to_str()));},
                                None => ()
                             }
                           },
                None => ()
            }

            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);
            println(format!("Received request :\n{:s}", request_str));

            let response: ~str =
                ~"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                 <doctype !html><title>Hello, Rust!</title>

Greetings, visitor $$!

                 \r\n";
	    let new_response = std::str::replace(response, "$$", count.to_str());
            stream.write(new_response.as_bytes());
            println!("Connection terminates.");
	    println!("Count: {}", count);
        }
    }
}
<|endoftext|>


<commit_before>use alloc::arc::Arc;
use alloc::boxed::Box;
use collections::BTreeMap;
use core::sync::atomic::{AtomicUsize, Ordering};
use spin::RwLock;

use context;
use syscall::error::*;
use syscall::scheme::Scheme;
use scheme::{self, SchemeNamespace, SchemeId};
use scheme::user::{UserInner, UserScheme};

pub struct RootScheme {
    scheme_ns: SchemeNamespace,
    scheme_id: SchemeId,
    next_id: AtomicUsize,
    handles: RwLock<BTreeMap<usize, Arc<UserInner>>>,
    ls_handles: RwLock<BTreeMap<usize, AtomicUsize>>,
}

impl RootScheme {
    pub fn new(scheme_ns: SchemeNamespace, scheme_id: SchemeId) -> RootScheme {
        RootScheme {
            scheme_ns: scheme_ns,
            scheme_id: scheme_id,
            next_id: AtomicUsize::new(0),
            handles: RwLock::new(BTreeMap::new()),
            ls_handles: RwLock::new(BTreeMap::new()),
        }
    }
}

impl Scheme for RootScheme {
    fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
        use syscall::syscall::*;
        if uid == 0 {
            if flags & O_DIRECTORY == O_DIRECTORY {
                if flags & O_ACCMODE != O_RDONLY {
                    return Err(Error::new(EACCES));
                }
                let id = self.next_id.fetch_add(1, Ordering::SeqCst);
                self.ls_handles.write().insert(id, AtomicUsize::new(0));
                return Ok(id);
            }

            let context = {
                let contexts = context::contexts();
                let context = contexts.current().ok_or(Error::new(ESRCH))?;
                Arc::downgrade(&context)
            };

            let id = self.next_id.fetch_add(1, Ordering::SeqCst);

            let inner = {
                use scheme;
                let path_box = path.to_vec().into_boxed_slice();
                let mut schemes = scheme::schemes_mut();
                let inner = Arc::new(UserInner::new(self.scheme_id, id, path_box.clone(), flags, context));
                schemes.insert(self.scheme_ns, path_box, |scheme_id| {
                    inner.scheme_id.store(scheme_id, Ordering::SeqCst);
                    Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner))))
                })?;
                inner
            };

            self.handles.write().insert(id, inner);

            Ok(id)
        } else {
            Err(Error::new(EACCES))
        }
    }

    fn dup(&self, file: usize, _buf: &[u8]) -> Result<usize> {
        let mut handles = self.handles.write();
        let inner = {
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        let id = self.next_id.fetch_add(1, Ordering::SeqCst);
        handles.insert(id, inner);

        Ok(id)
    }

    fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        match &*inner {
            UserOrListInner::User(ref inner) => inner.read(buf),
            UserOrListInner::List(ref num) => {
                let scheme_ns = {
                    let contexts = context::contexts();
                    let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
                    let context = context_lock.read();
                    context.ens
                };

                let schemes = scheme::schemes();

                let scheme_name = schemes.iterName(scheme_ns).nth(num.load(Ordering::SeqCst)).0.as_bytes();

                let mut i = 0;
                while i < buf.len() && i < scheme_name.len() {
                    buf[i] = scheme_name[i];
                    i += 1;
                }

                num.fetch_add(1, Ordering::SeqCst);

                Ok(i)
            }
        }
    }

    fn write(&self, file: usize, buf: &[u8]) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        inner.write(buf)
    }

    fn fevent(&self, file: usize, flags: usize) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        inner.fevent(flags)
    }

    fn fpath(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        let mut i = 0;
        let scheme_path = b":";
        while i < buf.len() && i < scheme_path.len() {
            buf[i] = scheme_path[i];
            i += 1;
        }

        let mut j = 0;
        while i < buf.len() && j < inner.name.len() {
            buf[i] = inner.name[j];
            i += 1;
            j += 1;
        }

        Ok(i)
    }

    fn fsync(&self, file: usize) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        inner.fsync()
    }

    fn close(&self, file: usize) -> Result<usize> {
        self.handles.write().remove(&file).ok_or(Error::new(EBADF)).and(Ok(0))
    }
}
<commit_msg>Make it working<commit_after>use alloc::arc::Arc;
use alloc::boxed::Box;
use collections::BTreeMap;
use core::sync::atomic::{AtomicUsize, Ordering};
use spin::RwLock;

use context;
use syscall::error::*;
use syscall::scheme::Scheme;
use scheme::{self, SchemeNamespace, SchemeId};
use scheme::user::{UserInner, UserScheme};

pub struct RootScheme {
    scheme_ns: SchemeNamespace,
    scheme_id: SchemeId,
    next_id: AtomicUsize,
    handles: RwLock<BTreeMap<usize, Arc<UserInner>>>,
    ls_handles: RwLock<BTreeMap<usize, AtomicUsize>>,
}

impl RootScheme {
    pub fn new(scheme_ns: SchemeNamespace, scheme_id: SchemeId) -> RootScheme {
        RootScheme {
            scheme_ns: scheme_ns,
            scheme_id: scheme_id,
            next_id: AtomicUsize::new(0),
            handles: RwLock::new(BTreeMap::new()),
            ls_handles: RwLock::new(BTreeMap::new()),
        }
    }
}

impl Scheme for RootScheme {
    fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
        use syscall::flag::*;

        if uid == 0 {
            if flags & O_DIRECTORY == O_DIRECTORY {
                if flags & O_ACCMODE != O_RDONLY {
                    return Err(Error::new(EACCES));
                }
                let id = self.next_id.fetch_add(1, Ordering::SeqCst);
                self.ls_handles.write().insert(id, AtomicUsize::new(0));
                return Ok(id);
            }

            let context = {
                let contexts = context::contexts();
                let context = contexts.current().ok_or(Error::new(ESRCH))?;
                Arc::downgrade(&context)
            };

            let id = self.next_id.fetch_add(1, Ordering::SeqCst);

            let inner = {
                use scheme;
                let path_box = path.to_vec().into_boxed_slice();
                let mut schemes = scheme::schemes_mut();
                let inner = Arc::new(UserInner::new(self.scheme_id, id, path_box.clone(), flags, context));
                schemes.insert(self.scheme_ns, path_box, |scheme_id| {
                        inner.scheme_id.store(scheme_id, Ordering::SeqCst);
                        Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner))))
                    })?;
                inner
            };

            self.handles.write().insert(id, inner);

            Ok(id)
        } else {
            Err(Error::new(EACCES))
        }
    }

    fn dup(&self, file: usize, _buf: &[u8]) -> Result<usize> {
        let mut handles = self.handles.write();
        let inner = {
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        let id = self.next_id.fetch_add(1, Ordering::SeqCst);
        handles.insert(id, inner);

        Ok(id)
    }

    fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            handles.get(&file).map(Clone::clone)
        };

        if let Some(inner) = inner {
            inner.read(buf)
        } else {
            let scheme_ns = {
                let contexts = context::contexts();
                let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
                let context = context_lock.read();
                context.ens
            };

            let schemes = scheme::schemes();
            let mut schemes_iter = schemes.iter_name(scheme_ns);

            let num = {
                let handles = self.ls_handles.read();
                let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
                inner.load(Ordering::SeqCst)
            };

            if let Some(scheme) = schemes_iter.nth(num) {
                let mut i = 0;
                while i < buf.len() && i < scheme.0.len() {
                    buf[i] = scheme.0[i];
                    i += 1;
                }

                {
                    let handles = self.ls_handles.read();
                    let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
                    inner.fetch_add(1, Ordering::SeqCst)
                };

                Ok(i)
            } else {
                Ok(0)
            }
        }
    }

    fn write(&self, file: usize, buf: &[u8]) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        inner.write(buf)
    }

    fn fevent(&self, file: usize, flags: usize) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        inner.fevent(flags)
    }

    fn fpath(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        let mut i = 0;
        let scheme_path = b":";
        while i < buf.len() && i < scheme_path.len() {
            buf[i] = scheme_path[i];
            i += 1;
        }

        let mut j = 0;
        while i < buf.len() && j < inner.name.len() {
            buf[i] = inner.name[j];
            i += 1;
            j += 1;
        }

        Ok(i)
    }

    fn fsync(&self, file: usize) -> Result<usize> {
        let inner = {
            let handles = self.handles.read();
            let inner = handles.get(&file).ok_or(Error::new(EBADF))?;
            inner.clone()
        };

        inner.fsync()
    }

    fn close(&self, file: usize) -> Result<usize> {
        self.handles.write().remove(&file).ok_or(Error::new(EBADF)).and(Ok(0))
    }
}
<|endoftext|>


<commit_before>extern crate rustbox;
extern crate chrono;

use rustbox::*;
use chrono::*;

use screen::common::*;
use utility::string::*;
use model::ShowItem;
use model::ShowReplyItem;
use reply_model::*;

pub struct Show<'a> {
    rustbox: &'a rustbox::RustBox,
    scrollY: usize,
    y: usize,
    replier_max_width: usize,
    time_max_width: usize,
}

impl<'a> Show<'a> {
    pub fn new(rustbox: &'a rustbox::RustBox) -> Self {
        Show {
            rustbox: &rustbox,
            scrollY: 0,
            y: 0,
            replier_max_width: 14,
            time_max_width: 5,
        }
    }
    pub fn print(&mut self, title: &str, item: &ShowItem) {

        self.y = 2;

        self.print_header(&format!("{} - {} [{}/{}]",
                                   item.title,
                                   title,
                                   item.page,
                                   item.max_page));
        self.print_body(&item);
    }

    fn print_separator_top(&mut self, reply: &ShowReplyItem) {
        if self.can_print() {
            let (replier_name, time) = make_separator_content(&reply);
            let s = self.build_separator_top(&replier_name, &time);
            self.print_separator_line(&s);
        }
    }

    fn print_separator_bottom(&mut self) {
        if self.can_print() {
            let s = self.build_separator_bottom();
            self.print_separator_line(&s);
        }
    }

    fn print_separator_line(&mut self, s: &str) {
        self.rustbox.print(0,
                           self.scrolledY(),
                           rustbox::RB_NORMAL,
                           Color::Green,
                           Color::Black,
                           &s);
    }

    fn print_header(&mut self, text: &str) {
        let title_len = jks_len(text);
        let padding = (if self.rustbox.width() >= title_len {
            self.rustbox.width() - title_len
        } else {
            0
        }) / 2;

        let header_bottom = seq_str_gen(0, self.rustbox.width(), "─", "");

        clearline(&self.rustbox, self.rustbox.width(), 0, 0);
        self.rustbox.print(padding,
                           0,
                           rustbox::RB_BOLD,
                           Color::White,
                           Color::Black,
                           text);
        self.rustbox.print(0,
                           1,
                           rustbox::RB_BOLD,
                           Color::Yellow,
                           Color::Black,
                           &header_bottom);
    }

    pub fn print_body(&mut self, item: &ShowItem) {
        let width = self.body_width();
        let rows = self.body_height();
        let rustbox = self.rustbox;

        for (i, reply) in item.replies.iter().take(rows).enumerate() {

            self.print_reply(&reply.body, 0);

            self.print_separator_top(&reply);
            self.y += 1;

            self.print_separator_bottom();
            self.y += 1;
        }
    }

    fn print_reply_line(&mut self, s: String) {
        self.rustbox.print(0,
                           self.scrolledY(),
                           rustbox::RB_NORMAL,
                           Color::White,
                           Color::Black,
                           &s);
    }

    fn print_reply(&mut self, vec: &Vec<NodeType>, depth: usize) {

        let rustbox = self.rustbox;

        let padding = seq_str_gen(0, depth, "├─", "");
        let mut line = String::new();
        let mut is_first = true;

        let vec_clean = clean_reply_body(vec);
        for (j, node) in vec_clean.iter().enumerate() {
            match node.clone() {
                NodeType::Text(n) => {
                    if n.data != "" {
                        line = format!("{}{}", line, n.data);
                    }
                }
                NodeType::Image(n) => {
                    if n.data != "" {
                        line = format!("{}[img {}]", line, n.data);
                    }
                }
                NodeType::BlockQuote(n) => {
                    self.print_reply(&n.data, depth + 1);
                    is_first = false;
                }
                NodeType::Br(n) => {
                    if !line.is_empty() {
                        if self.can_print() {
                            self.print_reply_line(format!(" {}{}", padding, line));
                        }
                        line = String::new();
                        is_first = false;
                    }

                    // prevent first line empty
                    if !is_first {
                        self.y += 1;
                    }

                }
            }
        }

        if !line.is_empty() {
            if self.can_print() {
                self.print_reply_line(format!(" {}{}  ", padding, line));
            }
            line = String::new();
            self.y += 1;
        }

    }

    fn build_separator_arguments(&mut self) -> (usize, usize, String) {
        let separator_width = self.body_width();
        let separator_padding_width = if self.rustbox.width() > separator_width {
            self.rustbox.width() - separator_width
        } else {
            0
        } / 2;

        let separator_padding = seq_str_gen(0, separator_padding_width, " ", "");

        (separator_width, separator_padding_width, separator_padding)
    }

    fn build_separator_top(&mut self, replier_name: &str, time: &str) -> String {
        let (separator_width, separator_padding_width, separator_padding) =
            self.build_separator_arguments();
        make_separator_top(separator_width,
                           &separator_padding,
                           self.replier_max_width,
                           &replier_name,
                           self.time_max_width,
                           &time)
    }

    fn build_separator_bottom(&mut self) -> String {
        let (separator_width, separator_padding_width, separator_padding) =
            self.build_separator_arguments();
        make_separator_bottom(separator_width, &separator_padding)
    }

    pub fn resetY(&mut self) {
        self.scrollY = 0;
    }

    pub fn scrollUp(&mut self, value: usize) -> bool {
        let tmp = self.scrollY;
        if tmp > value {
            self.scrollY = tmp - value;
            true
        } else if tmp != 0 {
            self.scrollY = 0;
            true
        } else {
            false
        }
    }

    pub fn scrollDown(&mut self, value: usize) -> bool {
        let tmp = self.scrollY;
        if tmp < 10000 {
            self.scrollY = tmp + value;
            return true;
        }
        false
    }

    pub fn body_height(&self) -> usize {
        if self.rustbox.height() >= 3 {
            self.rustbox.height() - 3
        } else {
            0
        }
    }

    pub fn body_width(&self) -> usize {
        if self.rustbox.width() >= 2 {
            self.rustbox.width() - 2
        } else {
            0
        }
    }

    fn can_print(&self) -> bool {
        self.y > self.scrollY + 1
    }

    fn scrolledY(&self) -> usize {
        self.y - self.scrollY
    }
}

fn make_separator_content(reply: &ShowReplyItem) -> (String, String) {
    let now = Local::now();

    let replier_name = reply.username.clone();

    let published_at = reply.published_at.clone();

    let published_at_dt = match Local.datetime_from_str(&published_at, "%d/%m/%Y %H:%M") {
        Ok(v) => v,
        Err(e) => now,
    };
    let time = published_at_format(&(now - published_at_dt));
    (replier_name, time)
}

fn clean_reply_body(vec: &Vec<NodeType>) -> Vec<NodeType> {
    // clean up lines (end)
    let vec2 = {
        let vec_length = vec.len();
        let vec_check_cleanup = vec.clone();

        // check if last 4 elements match the EMPTY PATTERN
        let is_last4_empty = vec_check_cleanup.iter()
                                              .rev()
                                              .take(4)
                                              .enumerate()
                                              .all(|(j, node)| match node.clone() {
                                                  NodeType::Br(n) => j == 1 || j == 2 || j == 3,
                                                  NodeType::Text(n) => j == 0 && n.data.is_empty(),
                                                  _ => false,
                                              });

        let vec_short_length = if vec_length > 4 && is_last4_empty {
            vec_length - 4
        } else {
            vec_length
        };

        vec.iter().take(vec_short_length)
    };

    // clean up lines (start)
    let vec3 = {
        let vec2_cloned = vec2.clone();
        let mut result: Vec<NodeType> = Vec::new();
        for (j, node) in vec2_cloned.enumerate() {
            let node2 = node.clone();
            let node3 = node.clone();
            match node2 {
                NodeType::Br(n) => {
                    if !result.is_empty() {
                        result.push(node3);
                    }
                }
                _ => result.push(node3),
            }
        }
        result.clone()
    };

    vec3
}

fn make_separator_replier_name(separator_width: usize,
                               separator_padding: &str,
                               replier_max_width: usize,
                               replier_name: &str)
                               -> String {
    let replier_name_len = jks_len(&replier_name);
    let replier_name_spacing_width = replier_max_width - replier_name_len;
    let is_replier_name_spacing_width_odd = replier_name_spacing_width & 1 == 1;
    let replier_name_right_spacing_width = replier_name_spacing_width / 2;
    let replier_name_left_spacing_width = if is_replier_name_spacing_width_odd {
        replier_name_right_spacing_width + 1
    } else {
        replier_name_right_spacing_width
    };

    let replier_name_left_spacing = seq_str_gen(0, replier_name_left_spacing_width, "─", "");
    let replier_name_right_spacing = seq_str_gen(0, replier_name_right_spacing_width, "─", "");

    let separator_replier = format!("{}{}{}{}{}",
                                    "╭",
                                    replier_name_left_spacing,
                                    replier_name,
                                    replier_name_right_spacing,
                                    "");

    return separator_replier;
}

fn make_separator_time(separator_width: usize,
                       separator_padding: &str,
                       time_max_width: usize,
                       time: &str)
                       -> String {
    let time_len = jks_len(&time);
    let time_spacing_width = if time_max_width > time_len {
        time_max_width - time_len
    } else {
        0
    };

    let is_time_spacing_width_odd = time_spacing_width & 1 == 1;
    let time_right_spacing_width = time_spacing_width / 2;
    let time_left_spacing_width = if is_time_spacing_width_odd {
        time_right_spacing_width + 1
    } else {
        time_right_spacing_width
    };

    let time_left_spacing = seq_str_gen(0, time_left_spacing_width, "─", "");
    let time_right_spacing = seq_str_gen(0, time_right_spacing_width, "─", "");

    let separator_time = format!("{}{}{}{}{}",
                                 "",
                                 time_left_spacing,
                                 time,
                                 time_right_spacing,
                                 "╮");

    return separator_time;
}

fn make_separator_top(separator_width: usize,
                      separator_padding: &str,
                      replier_max_width: usize,
                      replier_name: &str,
                      time_max_width: usize,
                      time: &str)
                      -> String {

    let separator_replier = make_separator_replier_name(separator_width,
                                                        &separator_padding,
                                                        replier_max_width,
                                                        &replier_name);

    let separator_replier_width = jks_len(&separator_replier);

    let separator_time = make_separator_time(separator_width,
                                             &separator_padding,
                                             time_max_width,
                                             &time);

    let separator_time_width = jks_len(&separator_time);

    let separator_top_middle_width = if separator_width >=
                                        (separator_replier_width + separator_time_width) {
        separator_width - separator_replier_width - separator_time_width
    } else {
        0
    };

    let separator_top_middle = seq_str_gen(0, separator_top_middle_width, " ", "");
    let separator_top = format!("{}{}{}{}{}",
                                separator_padding,
                                separator_top_middle,
                                separator_replier,
                                separator_time,
                                separator_padding);
    return separator_top;
}

fn make_separator_bottom(separator_width: usize, separator_padding: &str) -> String {
    let style_box_width = 1;
    let separator_bottom_middle_width = if separator_width > style_box_width {
        separator_width - style_box_width
    } else {
        0
    };
    let separator_bottom_middle = seq_str_gen(0, separator_bottom_middle_width, "─", "");

    let separator_bottom = format!("{}{}{}{}",
                                   separator_padding,
                                   separator_bottom_middle,
                                   "╯",
                                   separator_padding);
    return separator_bottom;
}

fn published_at_format(duration: &Duration) -> String {
    let weeks = duration.num_weeks();
    let days = duration.num_days();
    let hours = duration.num_hours();
    let minutes = duration.num_minutes();

    if weeks > 0 {
        format!("{}w", weeks)
    } else if days > 0 {
        format!("{}d", days)
    } else if hours > 0 {
        format!("{}h", hours)
    } else if minutes > 0 {
        format!("{}m", minutes)
    } else {
        String::from("1m")
    }
}

fn seq_str_gen(start: usize, end: usize, sym: &str, join_sym: &str) -> String {
    (start..end).map(|_| sym.clone()).collect::<Vec<_>>().join(&join_sym)
}
<commit_msg>show - prevent allow to scrolldown forever<commit_after>extern crate rustbox;
extern crate chrono;

use rustbox::*;
use chrono::*;

use screen::common::*;
use utility::string::*;
use model::ShowItem;
use model::ShowReplyItem;
use reply_model::*;

pub struct Show<'a> {
    rustbox: &'a rustbox::RustBox,
    scrollY: usize,
    y: usize,
    replier_max_width: usize,
    time_max_width: usize,
    is_scroll_to_end: bool
}

impl<'a> Show<'a> {
    pub fn new(rustbox: &'a rustbox::RustBox) -> Self {
        Show {
            rustbox: &rustbox,
            scrollY: 0,
            y: 0,
            replier_max_width: 14,
            time_max_width: 5,
            is_scroll_to_end: false
        }
    }
    pub fn print(&mut self, title: &str, item: &ShowItem) {

        self.y = 2;

        self.print_header(&format!("{} - {} [{}/{}]",
                                   item.title,
                                   title,
                                   item.page,
                                   item.max_page));
        self.print_body(&item);
    }

    fn print_separator_top(&mut self, reply: &ShowReplyItem) {
        if self.can_print() {
            let (replier_name, time) = make_separator_content(&reply);
            let s = self.build_separator_top(&replier_name, &time);
            self.print_separator_line(&s);
        }
    }

    fn print_separator_bottom(&mut self) {
        if self.can_print() {
            let s = self.build_separator_bottom();
            self.print_separator_line(&s);
        }
    }

    fn print_separator_line(&mut self, s: &str) {
        self.rustbox.print(0,
                           self.scrolledY(),
                           rustbox::RB_NORMAL,
                           Color::Green,
                           Color::Black,
                           &s);
    }

    fn print_header(&mut self, text: &str) {
        let title_len = jks_len(text);
        let padding = (if self.rustbox.width() >= title_len {
            self.rustbox.width() - title_len
        } else {
            0
        }) / 2;

        let header_bottom = seq_str_gen(0, self.rustbox.width(), "─", "");

        clearline(&self.rustbox, self.rustbox.width(), 0, 0);
        self.rustbox.print(padding,
                           0,
                           rustbox::RB_BOLD,
                           Color::White,
                           Color::Black,
                           text);
        self.rustbox.print(0,
                           1,
                           rustbox::RB_BOLD,
                           Color::Yellow,
                           Color::Black,
                           &header_bottom);
    }

    pub fn print_body(&mut self, item: &ShowItem) {
        let width = self.body_width();
        let rows = self.body_height();
        let rustbox = self.rustbox;

        for (i, reply) in item.replies.iter().take(rows).enumerate() {

            self.print_reply(&reply.body, 0);

            self.print_separator_top(&reply);
            self.y += 1;

            self.print_separator_bottom();
            self.y += 1;
        }

        self.is_scroll_to_end = self.scrolledY() < self.body_height();
    }

    fn print_reply_line(&mut self, s: String) {
        self.rustbox.print(0,
                           self.scrolledY(),
                           rustbox::RB_NORMAL,
                           Color::White,
                           Color::Black,
                           &s);
    }

    fn print_reply(&mut self, vec: &Vec<NodeType>, depth: usize) {

        let rustbox = self.rustbox;

        let padding = seq_str_gen(0, depth, "├─", "");
        let mut line = String::new();
        let mut is_first = true;

        let vec_clean = clean_reply_body(vec);
        for (j, node) in vec_clean.iter().enumerate() {
            match node.clone() {
                NodeType::Text(n) => {
                    if n.data != "" {
                        line = format!("{}{}", line, n.data);
                    }
                }
                NodeType::Image(n) => {
                    if n.data != "" {
                        line = format!("{}[img {}]", line, n.data);
                    }
                }
                NodeType::BlockQuote(n) => {
                    self.print_reply(&n.data, depth + 1);
                    is_first = false;
                }
                NodeType::Br(n) => {
                    if !line.is_empty() {
                        if self.can_print() {
                            self.print_reply_line(format!(" {}{}", padding, line));
                        }
                        line = String::new();
                        is_first = false;
                    }

                    // prevent first line empty
                    if !is_first {
                        self.y += 1;
                    }

                }
            }
        }

        if !line.is_empty() {
            if self.can_print() {
                self.print_reply_line(format!(" {}{}  ", padding, line));
            }
            line = String::new();
            self.y += 1;
        }

    }

    fn build_separator_arguments(&mut self) -> (usize, usize, String) {
        let separator_width = self.body_width();
        let separator_padding_width = if self.rustbox.width() > separator_width {
            self.rustbox.width() - separator_width
        } else {
            0
        } / 2;

        let separator_padding = seq_str_gen(0, separator_padding_width, " ", "");

        (separator_width, separator_padding_width, separator_padding)
    }

    fn build_separator_top(&mut self, replier_name: &str, time: &str) -> String {
        let (separator_width, separator_padding_width, separator_padding) =
            self.build_separator_arguments();
        make_separator_top(separator_width,
                           &separator_padding,
                           self.replier_max_width,
                           &replier_name,
                           self.time_max_width,
                           &time)
    }

    fn build_separator_bottom(&mut self) -> String {
        let (separator_width, separator_padding_width, separator_padding) =
            self.build_separator_arguments();
        make_separator_bottom(separator_width, &separator_padding)
    }

    pub fn resetY(&mut self) {
        self.scrollY = 0;
    }

    pub fn scrollUp(&mut self, value: usize) -> bool {
        let tmp = self.scrollY;
        if tmp > value {
            self.scrollY = tmp - value;
            true
        } else if tmp != 0 {
            self.scrollY = 0;
            true
        } else {
            false
        }
    }

    pub fn scrollDown(&mut self, value: usize) -> bool {

        if !self.is_scroll_to_end {
            let min_to_scroll = self.scrollY + self.body_height();
            if self.y >= min_to_scroll + value {
                self.scrollY += value;
                return true;
            } else if self.y >= min_to_scroll {
                self.scrollY += self.y - min_to_scroll;
                return true;
            }
        }

        false
    }

    pub fn body_height(&self) -> usize {
        if self.rustbox.height() >= 3 {
            self.rustbox.height() - 3
        } else {
            0
        }
    }

    pub fn body_width(&self) -> usize {
        if self.rustbox.width() >= 2 {
            self.rustbox.width() - 2
        } else {
            0
        }
    }

    fn can_print(&self) -> bool {
        self.y > self.scrollY + 1
    }

    fn scrolledY(&self) -> usize {
        self.y - self.scrollY
    }
}

fn make_separator_content(reply: &ShowReplyItem) -> (String, String) {
    let now = Local::now();

    let replier_name = reply.username.clone();

    let published_at = reply.published_at.clone();

    let published_at_dt = match Local.datetime_from_str(&published_at, "%d/%m/%Y %H:%M") {
        Ok(v) => v,
        Err(e) => now,
    };
    let time = published_at_format(&(now - published_at_dt));
    (replier_name, time)
}

fn clean_reply_body(vec: &Vec<NodeType>) -> Vec<NodeType> {
    // clean up lines (end)
    let vec2 = {
        let vec_length = vec.len();
        let vec_check_cleanup = vec.clone();

        // check if last 4 elements match the EMPTY PATTERN
        let is_last4_empty = vec_check_cleanup.iter()
                                              .rev()
                                              .take(4)
                                              .enumerate()
                                              .all(|(j, node)| match node.clone() {
                                                  NodeType::Br(n) => j == 1 || j == 2 || j == 3,
                                                  NodeType::Text(n) => j == 0 && n.data.is_empty(),
                                                  _ => false,
                                              });

        let vec_short_length = if vec_length > 4 && is_last4_empty {
            vec_length - 4
        } else {
            vec_length
        };

        vec.iter().take(vec_short_length)
    };

    // clean up lines (start)
    let vec3 = {
        let vec2_cloned = vec2.clone();
        let mut result: Vec<NodeType> = Vec::new();
        for (j, node) in vec2_cloned.enumerate() {
            let node2 = node.clone();
            let node3 = node.clone();
            match node2 {
                NodeType::Br(n) => {
                    if !result.is_empty() {
                        result.push(node3);
                    }
                }
                _ => result.push(node3),
            }
        }
        result.clone()
    };

    vec3
}

fn make_separator_replier_name(separator_width: usize,
                               separator_padding: &str,
                               replier_max_width: usize,
                               replier_name: &str)
                               -> String {
    let replier_name_len = jks_len(&replier_name);
    let replier_name_spacing_width = replier_max_width - replier_name_len;
    let is_replier_name_spacing_width_odd = replier_name_spacing_width & 1 == 1;
    let replier_name_right_spacing_width = replier_name_spacing_width / 2;
    let replier_name_left_spacing_width = if is_replier_name_spacing_width_odd {
        replier_name_right_spacing_width + 1
    } else {
        replier_name_right_spacing_width
    };

    let replier_name_left_spacing = seq_str_gen(0, replier_name_left_spacing_width, "─", "");
    let replier_name_right_spacing = seq_str_gen(0, replier_name_right_spacing_width, "─", "");

    let separator_replier = format!("{}{}{}{}{}",
                                    "╭",
                                    replier_name_left_spacing,
                                    replier_name,
                                    replier_name_right_spacing,
                                    "");

    return separator_replier;
}

fn make_separator_time(separator_width: usize,
                       separator_padding: &str,
                       time_max_width: usize,
                       time: &str)
                       -> String {
    let time_len = jks_len(&time);
    let time_spacing_width = if time_max_width > time_len {
        time_max_width - time_len
    } else {
        0
    };

    let is_time_spacing_width_odd = time_spacing_width & 1 == 1;
    let time_right_spacing_width = time_spacing_width / 2;
    let time_left_spacing_width = if is_time_spacing_width_odd {
        time_right_spacing_width + 1
    } else {
        time_right_spacing_width
    };

    let time_left_spacing = seq_str_gen(0, time_left_spacing_width, "─", "");
    let time_right_spacing = seq_str_gen(0, time_right_spacing_width, "─", "");

    let separator_time = format!("{}{}{}{}{}",
                                 "",
                                 time_left_spacing,
                                 time,
                                 time_right_spacing,
                                 "╮");

    return separator_time;
}

fn make_separator_top(separator_width: usize,
                      separator_padding: &str,
                      replier_max_width: usize,
                      replier_name: &str,
                      time_max_width: usize,
                      time: &str)
                      -> String {

    let separator_replier = make_separator_replier_name(separator_width,
                                                        &separator_padding,
                                                        replier_max_width,
                                                        &replier_name);

    let separator_replier_width = jks_len(&separator_replier);

    let separator_time = make_separator_time(separator_width,
                                             &separator_padding,
                                             time_max_width,
                                             &time);

    let separator_time_width = jks_len(&separator_time);

    let separator_top_middle_width = if separator_width >=
                                        (separator_replier_width + separator_time_width) {
        separator_width - separator_replier_width - separator_time_width
    } else {
        0
    };

    let separator_top_middle = seq_str_gen(0, separator_top_middle_width, " ", "");
    let separator_top = format!("{}{}{}{}{}",
                                separator_padding,
                                separator_top_middle,
                                separator_replier,
                                separator_time,
                                separator_padding);
    return separator_top;
}

fn make_separator_bottom(separator_width: usize, separator_padding: &str) -> String {
    let style_box_width = 1;
    let separator_bottom_middle_width = if separator_width > style_box_width {
        separator_width - style_box_width
    } else {
        0
    };
    let separator_bottom_middle = seq_str_gen(0, separator_bottom_middle_width, "─", "");

    let separator_bottom = format!("{}{}{}{}",
                                   separator_padding,
                                   separator_bottom_middle,
                                   "╯",
                                   separator_padding);
    return separator_bottom;
}

fn published_at_format(duration: &Duration) -> String {
    let weeks = duration.num_weeks();
    let days = duration.num_days();
    let hours = duration.num_hours();
    let minutes = duration.num_minutes();

    if weeks > 0 {
        format!("{}w", weeks)
    } else if days > 0 {
        format!("{}d", days)
    } else if hours > 0 {
        format!("{}h", hours)
    } else if minutes > 0 {
        format!("{}m", minutes)
    } else {
        String::from("1m")
    }
}

fn seq_str_gen(start: usize, end: usize, sym: &str, join_sym: &str) -> String {
    (start..end).map(|_| sym.clone()).collect::<Vec<_>>().join(&join_sym)
}
<|endoftext|>


<commit_before>use libc::c_int;
use libc;
use result::ShellError;
use result::ShellResult;
use std::mem;
use std::sync::Arc;
use std::sync::RwLock;
use result::check_errno;
use result::ShellResultExt;
use std::process::Child;
use std::process::Command;
use local_shell::current_shell;
use std::io::Read;

#[derive(Debug)]
pub struct ShellChildCore {
    command_line: String,
    child: Child,
    has_group: bool
}

impl ShellChildCore {
    fn new(command_line: String, child: Child,
           has_group: bool) -> ShellChildCore {
        ShellChildCore {
            command_line: command_line,
            child: child,
            has_group: has_group
        }
    }

    pub fn signal(&self, sig: c_int) -> ShellResult {
        let kill_pid = if self.has_group {
            -(self.child.id() as i32)
        } else {
            self.child.id() as i32
        };

        info!("Sending signal {} to {}", sig, self.child.id());
        unsafe {
            check_errno("kill", libc::kill(kill_pid, sig))?;
        }
        Ok(())
    }

    pub fn wait_null(&self) -> ShellResult {
        unsafe {
            let mut info = mem::uninitialized::<libc::siginfo_t>();
            check_errno("waitid",
                        libc::waitid(
                            libc::P_PID,
                            self.child.id() as u32,
                            &mut info as *mut libc::siginfo_t,
                            libc::WEXITED | libc::WNOWAIT))?;
        }
        Ok(())
    }

    pub fn wait(mut self) -> ShellResult {
        ShellResult::from_status(self.command_line, self.child.wait()?)
    }
}

pub type ShellChildArc = Arc<RwLock<Option<ShellChildCore>>>;

/// Job which is a process leader.
/// This wraps Arc<RwLock<ShellChildCore>> and provides helper functions.
pub struct ShellChild(ShellChildArc);

impl ShellChild {
    pub fn new(line: String, mut command: Command, has_group: bool)
            -> Result<ShellChild, ShellError> {
        let shell = current_shell();
        let mut lock = shell.lock().unwrap();
        if lock.signaled() {
            return Err(ShellError::from_signal(line, 101))
        }
        let child = command.spawn()?;
        let process = Arc::new(RwLock::new(
                Some(ShellChildCore::new(line, child, has_group))));
        lock.add_process(&process);
        Ok(ShellChild(process))
    }

    pub fn signal(&self, signal: c_int) -> ShellResult {
        let process = &self.0;
        let process = process.read().unwrap();
        process.as_ref().ok_or(ShellError::NoSuchProcess)?.signal(signal)
    }

    /// Sends a SIGTERM to a process group, then wait a process leader.
    pub fn terminate(self) -> ShellResult {
        self.signal(libc::SIGTERM)?;
        match self.wait() {
            Ok(()) | Err(ShellError::Status(_, _)) => Ok(()),
            err => err
        }
    }

    /// Wait for termination of the process.
    pub fn wait(self) -> ShellResult {
        {
            let data = self.0.read().unwrap();
            data.as_ref().ok_or(ShellError::NoSuchProcess)?.wait_null()?;
        }
        {
            let shell = current_shell();
            let mut lock = shell.lock().unwrap();
            lock.remove_process(&self.0);
        }
        let mut data = self.0.write().unwrap();
        data.take().ok_or(ShellError::NoSuchProcess)?.wait()
    }

    pub fn stdout_utf8(self) -> Result<String, ShellError> {
        let mut string = String::new();
        {
            let mut lock = self.0.write().unwrap();
            let lock = lock.as_mut().ok_or(ShellError::NoSuchProcess)?;
            lock.child.stdout.as_mut().unwrap().read_to_string(&mut string)?;
        }
        self.wait()?;
        Ok(string)
    }
}
<commit_msg>Mark Child in ShellChild public<commit_after>use libc::c_int;
use libc;
use result::ShellError;
use result::ShellResult;
use std::mem;
use std::sync::Arc;
use std::sync::RwLock;
use result::check_errno;
use result::ShellResultExt;
use std::process::Child;
use std::process::Command;
use local_shell::current_shell;
use std::io::Read;

#[derive(Debug)]
pub struct ShellChildCore {
    command_line: String,
    pub child: Child,
    has_group: bool
}

impl ShellChildCore {
    fn new(command_line: String, child: Child,
           has_group: bool) -> ShellChildCore {
        ShellChildCore {
            command_line: command_line,
            child: child,
            has_group: has_group
        }
    }

    pub fn signal(&self, sig: c_int) -> ShellResult {
        let kill_pid = if self.has_group {
            -(self.child.id() as i32)
        } else {
            self.child.id() as i32
        };

        info!("Sending signal {} to {}", sig, self.child.id());
        unsafe {
            check_errno("kill", libc::kill(kill_pid, sig))?;
        }
        Ok(())
    }

    pub fn wait_null(&self) -> ShellResult {
        unsafe {
            let mut info = mem::uninitialized::<libc::siginfo_t>();
            check_errno("waitid",
                        libc::waitid(
                            libc::P_PID,
                            self.child.id() as u32,
                            &mut info as *mut libc::siginfo_t,
                            libc::WEXITED | libc::WNOWAIT))?;
        }
        Ok(())
    }

    pub fn wait(mut self) -> ShellResult {
        ShellResult::from_status(self.command_line, self.child.wait()?)
    }
}

pub type ShellChildArc = Arc<RwLock<Option<ShellChildCore>>>;

/// Job which is a process leader.
/// This wraps Arc<RwLock<ShellChildCore>> and provides helper functions.
pub struct ShellChild(pub ShellChildArc);

impl ShellChild {
    pub fn new(line: String, mut command: Command, has_group: bool)
            -> Result<ShellChild, ShellError> {
        let shell = current_shell();
        let mut lock = shell.lock().unwrap();
        if lock.signaled() {
            return Err(ShellError::from_signal(line, 101))
        }
        let child = command.spawn()?;
        let process = Arc::new(RwLock::new(
                Some(ShellChildCore::new(line, child, has_group))));
        lock.add_process(&process);
        Ok(ShellChild(process))
    }

    pub fn signal(&self, signal: c_int) -> ShellResult {
        let process = &self.0;
        let process = process.read().unwrap();
        process.as_ref().ok_or(ShellError::NoSuchProcess)?.signal(signal)
    }

    /// Sends a SIGTERM to a process group, then wait a process leader.
    pub fn terminate(self) -> ShellResult {
        self.signal(libc::SIGTERM)?;
        match self.wait() {
            Ok(()) | Err(ShellError::Status(_, _)) => Ok(()),
            err => err
        }
    }

    /// Wait for termination of the process.
    pub fn wait(self) -> ShellResult {
        {
            let data = self.0.read().unwrap();
            data.as_ref().ok_or(ShellError::NoSuchProcess)?.wait_null()?;
        }
        {
            let shell = current_shell();
            let mut lock = shell.lock().unwrap();
            lock.remove_process(&self.0);
        }
        let mut data = self.0.write().unwrap();
        data.take().ok_or(ShellError::NoSuchProcess)?.wait()
    }

    pub fn stdout_utf8(self) -> Result<String, ShellError> {
        let mut string = String::new();
        {
            let mut lock = self.0.write().unwrap();
            let lock = lock.as_mut().ok_or(ShellError::NoSuchProcess)?;
            lock.child.stdout.as_mut().unwrap().read_to_string(&mut string)?;
        }
        self.wait()?;
        Ok(string)
    }
}
<|endoftext|>


<commit_before>use libc::{c_int, c_longlong, c_void, size_t};
use Addr;
use core::mem::transmute;
use core::ptr::null_mut;
use core::fmt;
use prelude::*;

#[lang = "eh_personality"]
pub extern "C" fn eh_personality() {}

#[lang = "eh_unwind_resume"]
pub extern "C" fn eh_unwind_resume() {}

#[lang = "panic_fmt"]
pub extern "C" fn panic_fmt(fmt: fmt::Arguments, file: &str, line: u32) -> ! {
    use system::OS;

    let text = format!("Panicked at '{}', {}:{}\0", fmt, file, line);

    let mut buffer = Vec::with_capacity(text.len());
    for &c in text.as_bytes() {
        buffer.push(c);
        if c == b'%' {
            buffer.push(b'%');
        }
    }

    OS::panic(buffer.as_ptr(), buffer.len() as i32, "HALT\0".as_ptr());
    loop {}
}

// use std::sync::atomic::{AtomicUsize, Ordering};
// static ALLOC_COUNTER: AtomicUsize = AtomicUsize::new(0);
// static DEALLOC_COUNTER: AtomicUsize = AtomicUsize::new(0);

#[no_mangle]
pub extern "C" fn malloc(size: size_t) -> *mut c_void {
    // ALLOC_COUNTER.fetch_add(1, Ordering::SeqCst);

    let memalign =
        unsafe { transmute::<Addr, extern "C" fn(size_t, size_t) -> *mut c_void>(0x8023ea88) };
    memalign(0xFFFFFFFC, size)
}

#[no_mangle]
pub extern "C" fn posix_memalign(memptr: *mut *mut c_void,
                                 alignment: size_t,
                                 size: size_t)
                                 -> c_int {
    // ALLOC_COUNTER.fetch_add(1, Ordering::SeqCst);

    let memalign =
        unsafe { transmute::<Addr, extern "C" fn(size_t, size_t) -> *mut c_void>(0x8023ea88) };
    unsafe {
        *memptr = memalign(alignment, size);
    }
    0
}

#[no_mangle]
pub extern "C" fn free(ptr: *mut c_void) {
    // DEALLOC_COUNTER.fetch_add(1, Ordering::SeqCst);

    let free = unsafe { transmute::<Addr, extern "C" fn(*mut c_void)>(0x8023eac0) };
    free(ptr);
}

#[no_mangle]
pub extern "C" fn realloc(ptr: *mut c_void, size: size_t) -> *mut c_void {
    let new_data = malloc(size);

    if ptr != null_mut() {
        let mut dst = new_data as *mut u8;
        let mut src = ptr as *mut u8;

        for _ in 0..size {
            unsafe {
                *dst = *src;
                dst = dst.offset(1);
                src = src.offset(1);
            }
        }

        free(ptr); // TODO Test
    }

    new_data
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn _Unwind_Resume() {
    // FIXME
}

#[no_mangle]
pub extern "C" fn strlen(string: *const u8) -> size_t {
    let mut counter = 0;
    let mut string = string;
    while unsafe { *string } != 0 {
        string = unsafe { string.offset(1) };
        counter += 1;
    }
    counter
}

#[cfg_attr(all(feature = "weak", not(windows), not(target_os = "macos")), linkage = "weak")]
#[no_mangle]
pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
    let mut i = 0;
    while i < n {
        *dest.offset(i as isize) = *src.offset(i as isize);
        i += 1;
    }
    dest
}

#[cfg_attr(all(feature = "weak", not(windows), not(target_os = "macos")), linkage = "weak")]
#[no_mangle]
pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
    if src < dest as *const u8 {
        // copy from end
        let mut i = n;
        while i != 0 {
            i -= 1;
            *dest.offset(i as isize) = *src.offset(i as isize);
        }
    } else {
        // copy from beginning
        let mut i = 0;
        while i < n {
            *dest.offset(i as isize) = *src.offset(i as isize);
            i += 1;
        }
    }
    dest
}

#[cfg_attr(all(feature = "weak", not(windows), not(target_os = "macos")), linkage = "weak")]
#[no_mangle]
pub unsafe extern "C" fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 {
    let mut i = 0;
    while i < n {
        *s.offset(i as isize) = c as u8;
        i += 1;
    }
    s
}

#[cfg_attr(all(feature = "weak", not(windows), not(target_os = "macos")), linkage = "weak")]
#[no_mangle]
pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 {
    let mut i = 0;
    while i < n {
        let a = *s1.offset(i as isize);
        let b = *s2.offset(i as isize);
        if a != b {
            return a as i32 - b as i32;
        }
        i += 1;
    }
    0
}<commit_msg>Support libm properly<commit_after>use libc::{c_int, c_void, size_t};
use Addr;
use core::mem::transmute;
use core::ptr::null_mut;
use core::fmt;
use prelude::*;

#[no_mangle]
pub unsafe extern "C" fn __errno() -> *mut c_int {
    static mut __errno: c_int = 0;
    &mut __errno
}

#[lang = "eh_personality"]
pub extern "C" fn eh_personality() {}

#[lang = "eh_unwind_resume"]
pub extern "C" fn eh_unwind_resume() {}

#[lang = "panic_fmt"]
pub extern "C" fn panic_fmt(fmt: fmt::Arguments, file: &str, line: u32) -> ! {
    use system::OS;

    let text = format!("Panicked at '{}', {}:{}\0", fmt, file, line);

    let mut buffer = Vec::with_capacity(text.len());
    for &c in text.as_bytes() {
        buffer.push(c);
        if c == b'%' {
            buffer.push(b'%');
        }
    }

    OS::panic(buffer.as_ptr(), buffer.len() as i32, "HALT\0".as_ptr());
    loop {}
}

// use std::sync::atomic::{AtomicUsize, Ordering};
// static ALLOC_COUNTER: AtomicUsize = AtomicUsize::new(0);
// static DEALLOC_COUNTER: AtomicUsize = AtomicUsize::new(0);

#[no_mangle]
pub extern "C" fn malloc(size: size_t) -> *mut c_void {
    // ALLOC_COUNTER.fetch_add(1, Ordering::SeqCst);

    let memalign =
        unsafe { transmute::<Addr, extern "C" fn(size_t, size_t) -> *mut c_void>(0x8023ea88) };
    memalign(0xFFFFFFFC, size)
}

#[no_mangle]
pub extern "C" fn posix_memalign(memptr: *mut *mut c_void,
                                 alignment: size_t,
                                 size: size_t)
                                 -> c_int {
    // ALLOC_COUNTER.fetch_add(1, Ordering::SeqCst);

    let memalign =
        unsafe { transmute::<Addr, extern "C" fn(size_t, size_t) -> *mut c_void>(0x8023ea88) };
    unsafe {
        *memptr = memalign(alignment, size);
    }
    0
}

#[no_mangle]
pub extern "C" fn free(ptr: *mut c_void) {
    // DEALLOC_COUNTER.fetch_add(1, Ordering::SeqCst);

    let free = unsafe { transmute::<Addr, extern "C" fn(*mut c_void)>(0x8023eac0) };
    free(ptr);
}

#[no_mangle]
pub extern "C" fn realloc(ptr: *mut c_void, size: size_t) -> *mut c_void {
    let new_data = malloc(size);

    if ptr != null_mut() {
        let mut dst = new_data as *mut u8;
        let mut src = ptr as *mut u8;

        for _ in 0..size {
            unsafe {
                *dst = *src;
                dst = dst.offset(1);
                src = src.offset(1);
            }
        }

        free(ptr); // TODO Test
    }

    new_data
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn _Unwind_Resume() {
    // FIXME
}

#[no_mangle]
pub extern "C" fn strlen(string: *const u8) -> size_t {
    let mut counter = 0;
    let mut string = string;
    while unsafe { *string } != 0 {
        string = unsafe { string.offset(1) };
        counter += 1;
    }
    counter
}

#[cfg_attr(all(feature = "weak", not(windows), not(target_os = "macos")), linkage = "weak")]
#[no_mangle]
pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
    let mut i = 0;
    while i < n {
        *dest.offset(i as isize) = *src.offset(i as isize);
        i += 1;
    }
    dest
}

#[cfg_attr(all(feature = "weak", not(windows), not(target_os = "macos")), linkage = "weak")]
#[no_mangle]
pub unsafe extern "C" fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
    if src < dest as *const u8 {
        // copy from end
        let mut i = n;
        while i != 0 {
            i -= 1;
            *dest.offset(i as isize) = *src.offset(i as isize);
        }
    } else {
        // copy from beginning
        let mut i = 0;
        while i < n {
            *dest.offset(i as isize) = *src.offset(i as isize);
            i += 1;
        }
    }
    dest
}

#[cfg_attr(all(feature = "weak", not(windows), not(target_os = "macos")), linkage = "weak")]
#[no_mangle]
pub unsafe extern "C" fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8 {
    let mut i = 0;
    while i < n {
        *s.offset(i as isize) = c as u8;
        i += 1;
    }
    s
}

#[cfg_attr(all(feature = "weak", not(windows), not(target_os = "macos")), linkage = "weak")]
#[no_mangle]
pub unsafe extern "C" fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32 {
    let mut i = 0;
    while i < n {
        let a = *s1.offset(i as isize);
        let b = *s2.offset(i as isize);
        if a != b {
            return a as i32 - b as i32;
        }
        i += 1;
    }
    0
}<|endoftext|>


<commit_before>//  _   _
// | |_| |__   ___  ___ __ _
// | __| '_ \ / _ \/ __/ _` |
// | |_| | | |  __/ (_| (_| |
//  \__|_| |_|\___|\___\__,_|
//
// licensed under the MIT license <http://opensource.org/licenses/MIT>
//
// util.rs
//   various utility functions for doings things we need to do.

use std::old_io::stdio::{stdin};
use std::old_io::{File, Open, ReadWrite,
              TempDir, Command, SeekSet};
use time::{get_time};
use std::env::{var_string, home_dir};
use std::old_io::process::{InheritFd};
use term::{stdout};
use term::attr::Attr::{Bold};
use std::old_io::{IoError};
use std::os::errno;
use std::cmp::{Ordering};
use time::{strftime, strptime, at, Tm};
use std::iter::{repeat};
use rustc_serialize::json::{as_pretty_json};

use ::{DATEFMT, DATEFMT_SHORT, ThecaItem};
use errors::{ThecaError, GenericError};
use lineformat::{LineFormat};

pub use libc::{
    STDIN_FILENO,
    STDOUT_FILENO,
    STDERR_FILENO
};

// c calls for TIOCGWINSZ
pub mod c {
    extern crate libc;
    pub use self::libc::{
        c_int,
        c_uint,
        c_ushort,
        c_ulong,
        c_uchar,
        STDOUT_FILENO,
        isatty
    };
    use std::mem::zeroed;
    #[derive(Copy)]
    pub struct Winsize {
        pub ws_row: c_ushort,
        pub ws_col: c_ushort
    }
    #[repr(C)]
    #[derive(Copy)]
    pub struct Termios {
        pub c_iflag: c_uint,
        pub c_oflag: c_uint,
        pub c_cflag: c_uint,
        pub c_lflag: c_uint,
        pub c_line: c_uchar,
        pub c_cc: [c_uchar; 32us],
        pub c_ispeed: c_uint,
        pub c_ospeed: c_uint,
    }
    impl Termios {
        pub fn new() -> Termios {
            unsafe {zeroed()}
        }
    }
    pub fn tcgetattr(fd: c_int, termios_p: &mut Termios) -> c_int {
        extern {fn tcgetattr(fd: c_int, termios_p: *mut Termios) -> c_int;}
        unsafe {tcgetattr(fd, termios_p as *mut _)}
    }
    pub fn tcsetattr(fd: c_int, optional_actions: c_int, termios_p: &Termios) -> c_int {
        extern {fn tcsetattr(fd: c_int, optional_actions: c_int,
                              termios_p: *const Termios) -> c_int;}
        unsafe {tcsetattr(fd, optional_actions, termios_p as *const _)}
    }
    pub const ECHO:c_uint = 8;
    pub const TCSANOW: c_int = 0;
    #[cfg(any(target_os = "linux", target_os = "android"))]
    static TIOCGWINSZ: c_ulong = 0x5413;
    #[cfg(any(target_os = "macos", target_os = "ios"))]
    static TIOCGWINSZ: c_ulong = 0x40087468;
    extern {
        pub fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int;
    }
    pub unsafe fn dimensions() -> Winsize {
        let mut window: Winsize = zeroed();
        ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut window as *mut Winsize);
        window
    }
    pub fn istty(fd: c_int) -> bool {
        let isit = unsafe {isatty(fd as i32)};
        isit != 0
    }
}

fn set_term_echo(echo: bool) -> Result<(), ThecaError> {
    let mut t = c::Termios::new();
    try_errno!(c::tcgetattr(STDIN_FILENO, &mut t));
    match echo {
        true => t.c_lflag |= c::ECHO,  // on
        false => t.c_lflag &= !c::ECHO  // off
    };
    try_errno!(c::tcsetattr(STDIN_FILENO, c::TCSANOW, &mut t));
    Ok(())
}

// unsafety wrapper
pub fn termsize() -> usize {
    let ws = unsafe {c::dimensions()};
    if ws.ws_col <= 0 || ws.ws_row <= 0 {
        0
    }
    else {
        ws.ws_col as usize
    }
}

pub fn drop_to_editor(contents: &String) -> Result<String, ThecaError> {
    // setup temporary directory
    let tmpdir = try!(TempDir::new("theca"));
    // setup temporary file to write/read
    let tmppath = tmpdir.path().join(get_time().sec.to_string());
    let mut tmpfile = try!(File::open_mode(&tmppath, Open, ReadWrite));
    try!(tmpfile.write_line(&contents[]));
    let editor = match var_string("VISUAL") {
        Ok(v) => v,
        Err(_) => match var_string("EDITOR") {
            Ok(v) => v,
            Err(_) => specific_fail_str!("neither $VISUAL nor $EDITOR is set.")
        }
    };
    // lets start `editor` and edit the file at `tmppath`
    // first we need to set STDIN, STDOUT, and STDERR to those that theca is
    // currently using so we can display the editor
    let mut editor_command = Command::new(editor);
    editor_command.arg(tmppath.display().to_string());
    editor_command.stdin(InheritFd(STDIN_FILENO));
    editor_command.stdout(InheritFd(STDOUT_FILENO));
    editor_command.stderr(InheritFd(STDERR_FILENO));
    let editor_proc = editor_command.spawn();
    match try!(editor_proc).wait().is_ok() {
        true => {
            // finished editing, time to read `tmpfile` for the final output
            // seek to start of `tmpfile`
            try!(tmpfile.seek(0, SeekSet));
            Ok(try!(tmpfile.read_to_string()).trim().to_string())
        }
        false => specific_fail_str!("the editor broke... I think")
    }
}

pub fn get_password() -> Result<String, ThecaError> {
    // should really turn off terminal echo...
    print!("Key: ");
    let tty = c::istty(STDIN_FILENO);
    if tty {try!(set_term_echo(false));}
    let mut stdin = stdin();
    // since this only reads one line of stdin it could still feasibly
    // be used with `-` to set note body?
    let key = try!(stdin.read_line());
    if tty {try!(set_term_echo(true));}
    println!("");
    Ok(key.trim().to_string())
}

pub fn get_yn_input() -> Result<bool, ThecaError> {
    let mut stdin = stdin();
    let mut answer;
    let yes = vec!["y", "Y", "yes", "YES", "Yes"];
    let no = vec!["n", "N", "no", "NO", "No"];
    loop {
        print!("[y/n]# ");
        let mut input = try!(stdin.read_line());
        input = input.trim().to_string();
        match yes.iter().any(|n| &n[] == input) {
            true => {
                answer = true;
                break;
            },
            false => {
                match no.iter().any(|n| &n[] == input) {
                    true => {
                        answer = false;
                        break;
                    },
                    false => ()
                }
            }
        };
        println!("invalid input.");
    }
    Ok(answer)
}

pub fn pretty_line(bold: &str, plain: &String, tty: bool) -> Result<(), ThecaError> {
    let mut t = match stdout() {
        Some(t) => t,
        None => specific_fail_str!("could not retrieve standard output.")
    };
    if tty {try!(t.attr(Bold));}
    try!(write!(t, "{}", bold.to_string()));
    if tty {try!(t.reset());}
    try!(write!(t, "{}", plain));
    Ok(())
}

pub fn format_field(value: &String, width: usize, truncate: bool) -> String {
    if value.len() > width && width > 3 && truncate {
        format!("{: <1$.1$}...", value, width-3)
    } else {
        format!("{: <1$.1$}", value, width)
    }
}

fn print_header(line_format: &LineFormat) -> Result<(), ThecaError> {
    let mut t = match stdout() {
        Some(t) => t,
        None => specific_fail_str!("could not retrieve standard output.")
    };
    let column_seperator: String = repeat(' ').take(line_format.colsep).collect();
    let header_seperator: String = repeat('-').take(line_format.line_width()).collect();
    let tty = c::istty(STDOUT_FILENO);
    let status = match line_format.status_width == 0 {
        true => "".to_string(),
        false => format_field(
            &"status".to_string(),
            line_format.status_width,
            false
        )+&*column_seperator
    };
    if tty {try!(t.attr(Bold));}
    try!(write!(
                t,
                "{1}{0}{2}{0}{3}{4}\n{5}\n",
                column_seperator,
                format_field(&"id".to_string(), line_format.id_width, false),
                format_field(&"title".to_string(), line_format.title_width, false),
                status,
                format_field(&"last touched".to_string(), line_format.touched_width, false),
                header_seperator
            ));
    if tty {try!(t.reset());}
    Ok(())
}

pub fn sorted_print(
    notes: &mut Vec<ThecaItem>,
    limit: usize,
    condensed: bool,
    json: bool,
    datesort: bool,
    reverse: bool,
    search_body: bool
) -> Result<(), ThecaError> {
    let line_format = try!(LineFormat::new(notes, condensed, search_body));
    let limit = match limit != 0 && notes.len() >= limit {
        true => limit,
        false => notes.len()
    };
    if !condensed && !json {
        try!(print_header(&line_format));
    }
    if datesort {
        notes.sort_by(|a, b| match cmp_last_touched(&*a.last_touched, &*b.last_touched) {
            Ok(o) => o,
            Err(_) => a.last_touched.cmp(&b.last_touched) // FIXME(?)
            // Err(_) => Ordering::Equal                  // FIXME(?)
        });
    }
    match json {
        false => {
            if reverse {notes.reverse();}
            for n in notes[0..limit].iter() {
                try!(n.print(&line_format, search_body));
            }
        },
        true => {
            if reverse { notes.reverse(); }
            println!("{}", as_pretty_json(&notes[0..limit].to_vec()))
        }
    };

    Ok(())
}

pub fn find_profile_folder(profile_folder: &String) -> Result<Path, ThecaError> {
    if !profile_folder.is_empty() {
        Ok(Path::new(profile_folder.to_string()))
    } else {
        match home_dir() {
            Some(ref p) => Ok(p.join(".theca")),
            None => specific_fail_str!("failed to find your home directory")
        }
    }
}

pub fn parse_last_touched(lt: &str) -> Result<Tm, ThecaError> {
    Ok(at(try!(strptime(lt, DATEFMT)).to_timespec()))
}

pub fn localize_last_touched_string(lt: &str) -> Result<String, ThecaError> {
    let t = try!(parse_last_touched(lt));
    Ok(try!(strftime(DATEFMT_SHORT, &t)))
}

pub fn cmp_last_touched(a: &str, b: &str) -> Result<Ordering, ThecaError> {
    let a_tm = try!(parse_last_touched(a));
    let b_tm = try!(parse_last_touched(b));
    Ok(a_tm.cmp(&b_tm))
}
<commit_msg>line styling<commit_after>//  _   _
// | |_| |__   ___  ___ __ _
// | __| '_ \ / _ \/ __/ _` |
// | |_| | | |  __/ (_| (_| |
//  \__|_| |_|\___|\___\__,_|
//
// licensed under the MIT license <http://opensource.org/licenses/MIT>
//
// util.rs
//   various utility functions for doings things we need to do.

use std::old_io::stdio::{stdin};
use std::old_io::{File, Open, ReadWrite,
              TempDir, Command, SeekSet};
use time::{get_time};
use std::env::{var_string, home_dir};
use std::old_io::process::{InheritFd};
use term::{stdout};
use term::attr::Attr::{Bold};
use std::old_io::{IoError};
use std::os::errno;
use std::cmp::{Ordering};
use time::{strftime, strptime, at, Tm};
use std::iter::{repeat};
use rustc_serialize::json::{as_pretty_json};

use ::{DATEFMT, DATEFMT_SHORT, ThecaItem};
use errors::{ThecaError, GenericError};
use lineformat::{LineFormat};

pub use libc::{
    STDIN_FILENO,
    STDOUT_FILENO,
    STDERR_FILENO
};

// c calls for TIOCGWINSZ
pub mod c {
    extern crate libc;
    pub use self::libc::{
        c_int,
        c_uint,
        c_ushort,
        c_ulong,
        c_uchar,
        STDOUT_FILENO,
        isatty
    };
    use std::mem::zeroed;
    #[derive(Copy)]
    pub struct Winsize {
        pub ws_row: c_ushort,
        pub ws_col: c_ushort
    }
    #[repr(C)]
    #[derive(Copy)]
    pub struct Termios {
        pub c_iflag: c_uint,
        pub c_oflag: c_uint,
        pub c_cflag: c_uint,
        pub c_lflag: c_uint,
        pub c_line: c_uchar,
        pub c_cc: [c_uchar; 32us],
        pub c_ispeed: c_uint,
        pub c_ospeed: c_uint,
    }
    impl Termios {
        pub fn new() -> Termios {
            unsafe {zeroed()}
        }
    }
    pub fn tcgetattr(fd: c_int, termios_p: &mut Termios) -> c_int {
        extern {fn tcgetattr(fd: c_int, termios_p: *mut Termios) -> c_int;}
        unsafe {tcgetattr(fd, termios_p as *mut _)}
    }
    pub fn tcsetattr(
        fd: c_int,
        optional_actions: c_int,
        termios_p: &Termios
    ) -> c_int {
        extern {fn tcsetattr(fd: c_int, optional_actions: c_int,
                              termios_p: *const Termios) -> c_int;}
        unsafe {tcsetattr(fd, optional_actions, termios_p as *const _)}
    }
    pub const ECHO:c_uint = 8;
    pub const TCSANOW: c_int = 0;
    #[cfg(any(target_os = "linux", target_os = "android"))]
    static TIOCGWINSZ: c_ulong = 0x5413;
    #[cfg(any(target_os = "macos", target_os = "ios"))]
    static TIOCGWINSZ: c_ulong = 0x40087468;
    extern {
        pub fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int;
    }
    pub unsafe fn dimensions() -> Winsize {
        let mut window: Winsize = zeroed();
        ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut window as *mut Winsize);
        window
    }
    pub fn istty(fd: c_int) -> bool {
        let isit = unsafe {isatty(fd as i32)};
        isit != 0
    }
}

fn set_term_echo(echo: bool) -> Result<(), ThecaError> {
    let mut t = c::Termios::new();
    try_errno!(c::tcgetattr(STDIN_FILENO, &mut t));
    match echo {
        true => t.c_lflag |= c::ECHO,  // on
        false => t.c_lflag &= !c::ECHO  // off
    };
    try_errno!(c::tcsetattr(STDIN_FILENO, c::TCSANOW, &mut t));
    Ok(())
}

// unsafety wrapper
pub fn termsize() -> usize {
    let ws = unsafe {c::dimensions()};
    if ws.ws_col <= 0 || ws.ws_row <= 0 {
        0
    }
    else {
        ws.ws_col as usize
    }
}

pub fn drop_to_editor(contents: &String) -> Result<String, ThecaError> {
    // setup temporary directory
    let tmpdir = try!(TempDir::new("theca"));
    // setup temporary file to write/read
    let tmppath = tmpdir.path().join(get_time().sec.to_string());
    let mut tmpfile = try!(File::open_mode(&tmppath, Open, ReadWrite));
    try!(tmpfile.write_line(&contents[]));
    let editor = match var_string("VISUAL") {
        Ok(v) => v,
        Err(_) => match var_string("EDITOR") {
            Ok(v) => v,
            Err(_) => specific_fail_str!("neither $VISUAL nor $EDITOR is set.")
        }
    };
    // lets start `editor` and edit the file at `tmppath`
    // first we need to set STDIN, STDOUT, and STDERR to those that theca is
    // currently using so we can display the editor
    let mut editor_command = Command::new(editor);
    editor_command.arg(tmppath.display().to_string());
    editor_command.stdin(InheritFd(STDIN_FILENO));
    editor_command.stdout(InheritFd(STDOUT_FILENO));
    editor_command.stderr(InheritFd(STDERR_FILENO));
    let editor_proc = editor_command.spawn();
    match try!(editor_proc).wait().is_ok() {
        true => {
            // finished editing, time to read `tmpfile` for the final output
            // seek to start of `tmpfile`
            try!(tmpfile.seek(0, SeekSet));
            Ok(try!(tmpfile.read_to_string()).trim().to_string())
        }
        false => specific_fail_str!("the editor broke... I think")
    }
}

pub fn get_password() -> Result<String, ThecaError> {
    // should really turn off terminal echo...
    print!("Key: ");
    let tty = c::istty(STDIN_FILENO);
    if tty {try!(set_term_echo(false));}
    let mut stdin = stdin();
    // since this only reads one line of stdin it could still feasibly
    // be used with `-` to set note body?
    let key = try!(stdin.read_line());
    if tty {try!(set_term_echo(true));}
    println!("");
    Ok(key.trim().to_string())
}

pub fn get_yn_input() -> Result<bool, ThecaError> {
    let mut stdin = stdin();
    let mut answer;
    let yes = vec!["y", "Y", "yes", "YES", "Yes"];
    let no = vec!["n", "N", "no", "NO", "No"];
    loop {
        print!("[y/n]# ");
        let mut input = try!(stdin.read_line());
        input = input.trim().to_string();
        match yes.iter().any(|n| &n[] == input) {
            true => {
                answer = true;
                break;
            },
            false => {
                match no.iter().any(|n| &n[] == input) {
                    true => {
                        answer = false;
                        break;
                    },
                    false => ()
                }
            }
        };
        println!("invalid input.");
    }
    Ok(answer)
}

pub fn pretty_line(
    bold: &str,
    plain: &String,
    tty: bool
) -> Result<(), ThecaError> {
    let mut t = match stdout() {
        Some(t) => t,
        None => specific_fail_str!("could not retrieve standard output.")
    };
    if tty {try!(t.attr(Bold));}
    try!(write!(t, "{}", bold.to_string()));
    if tty {try!(t.reset());}
    try!(write!(t, "{}", plain));
    Ok(())
}

pub fn format_field(value: &String, width: usize, truncate: bool) -> String {
    if value.len() > width && width > 3 && truncate {
        format!("{: <1$.1$}...", value, width-3)
    } else {
        format!("{: <1$.1$}", value, width)
    }
}

fn print_header(line_format: &LineFormat) -> Result<(), ThecaError> {
    let mut t = match stdout() {
        Some(t) => t,
        None => specific_fail_str!("could not retrieve standard output.")
    };
    let column_seperator: String = repeat(' ').take(line_format.colsep)
                                              .collect();
    let header_seperator: String = repeat('-').take(line_format.line_width())
                                              .collect();
    let tty = c::istty(STDOUT_FILENO);
    let status = match line_format.status_width == 0 {
        true => "".to_string(),
        false => format_field(
            &"status".to_string(),
            line_format.status_width,
            false
        )+&*column_seperator
    };
    if tty {try!(t.attr(Bold));}
    try!(write!(
                t,
                "{1}{0}{2}{0}{3}{4}\n{5}\n",
                column_seperator,
                format_field(&"id".to_string(), line_format.id_width, false),
                format_field(
                    &"title".to_string(),
                    line_format.title_width,
                    false
                ),
                status,
                format_field(
                    &"last touched".to_string(),
                    line_format.touched_width,
                    false
                ),
                header_seperator
            ));
    if tty {try!(t.reset());}
    Ok(())
}

pub fn sorted_print(
    notes: &mut Vec<ThecaItem>,
    limit: usize,
    condensed: bool,
    json: bool,
    datesort: bool,
    reverse: bool,
    search_body: bool
) -> Result<(), ThecaError> {
    let line_format = try!(LineFormat::new(notes, condensed, search_body));
    let limit = match limit != 0 && notes.len() >= limit {
        true => limit,
        false => notes.len()
    };
    if !condensed && !json {
        try!(print_header(&line_format));
    }
    if datesort {
        notes.sort_by(|a, b| match cmp_last_touched(
            &*a.last_touched,
            &*b.last_touched
        ) {
            Ok(o) => o,
            Err(_) => a.last_touched.cmp(&b.last_touched) // FIXME(?)
            // Err(_) => Ordering::Equal                  // FIXME(?)
        });
    }
    match json {
        false => {
            if reverse {notes.reverse();}
            for n in notes[0..limit].iter() {
                try!(n.print(&line_format, search_body));
            }
        },
        true => {
            if reverse { notes.reverse(); }
            println!("{}", as_pretty_json(&notes[0..limit].to_vec()))
        }
    };

    Ok(())
}

pub fn find_profile_folder(
    profile_folder: &String
) -> Result<Path, ThecaError> {
    if !profile_folder.is_empty() {
        Ok(Path::new(profile_folder.to_string()))
    } else {
        match home_dir() {
            Some(ref p) => Ok(p.join(".theca")),
            None => specific_fail_str!("failed to find your home directory")
        }
    }
}

pub fn parse_last_touched(lt: &str) -> Result<Tm, ThecaError> {
    Ok(at(try!(strptime(lt, DATEFMT)).to_timespec()))
}

pub fn localize_last_touched_string(lt: &str) -> Result<String, ThecaError> {
    let t = try!(parse_last_touched(lt));
    Ok(try!(strftime(DATEFMT_SHORT, &t)))
}

pub fn cmp_last_touched(a: &str, b: &str) -> Result<Ordering, ThecaError> {
    let a_tm = try!(parse_last_touched(a));
    let b_tm = try!(parse_last_touched(b));
    Ok(a_tm.cmp(&b_tm))
}
<|endoftext|>


<commit_before>//!
//! The [CIPHERS](static.CIPHERS.html) static hash map is built during the
//! compilation of the crate, using `build.rs`. It parses a file derived from
//! the [IANA TLS Cipher Suite
//! Registry](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4)
//! to automatically extract parameters and add all known ciphersuites.

#![allow(non_camel_case_types)]

use phf;

enum_from_primitive! {
/// Key exchange methods
#[derive(Clone,Debug,PartialEq)]
#[repr(u8)]
pub enum TlsCipherKx {
    Null = 0,
    Psk,
    Krb5,
    Srp,
    Rsa,
    Dh,
    Dhe,
    Ecdh,
    Ecdhe,
    Eccpwd,
    Tls13,
}
}

enum_from_primitive! {
/// Authentication methods
#[derive(Clone,Debug,PartialEq)]
#[repr(u8)]
pub enum TlsCipherAu {
    Null = 0,
    Psk,
    Krb5,
    Srp,
    Srp_Dss,
    Srp_Rsa,
    Dss,
    Rsa,
    Dhe,
    Ecdsa,
    Eccpwd,
    Tls13,
}
}

enum_from_primitive! {
/// Encryption methods
#[derive(Clone,Debug,PartialEq)]
#[repr(u8)]
pub enum TlsCipherEnc {
    Null,
    Des,
    TripleDes,
    Rc2,
    Rc4,
    Aria,
    Idea,
    Seed,
    Aes,
    Camellia,
    Chacha20_Poly1305,
    Sm4,
}
}

enum_from_primitive! {
/// Encryption modes
#[derive(Clone,Debug,PartialEq)]
#[repr(u8)]
pub enum TlsCipherEncMode {
    Null,
    Cbc,
    Ccm,
    Gcm,
}
}

enum_from_primitive! {
/// Message Authentication Code (MAC) methods
#[derive(Clone,Debug,PartialEq)]
#[repr(u8)]
pub enum TlsCipherMac {
    Null,
    HmacMd5,
    HmacSha1,
    HmacSha256,
    HmacSha384,
    Aead,
}
}

/// TLS Ciphersuite
#[derive(Debug)]
pub struct TlsCipherSuite {
    pub name: &'static str,
    pub id: u16,
    pub kx: TlsCipherKx,
    pub au: TlsCipherAu,
    pub enc: TlsCipherEnc,
    pub enc_mode: TlsCipherEncMode,
    pub enc_size: u16,
    pub mac: TlsCipherMac,
    pub mac_size: u16,
}

include!(concat!(env!("OUT_DIR"), "/codegen.rs"));

impl TlsCipherSuite {
    pub fn from_id(id: u16) -> Option<&'static TlsCipherSuite> {
        CIPHERS.get(&id)
    }

    pub fn from_name<'a>(name: &'a str) -> Option<&'static TlsCipherSuite> {
        CIPHERS.values().find(|&v| v.name == name)
    }
}

#[cfg(test)]
mod tests {
    use crate::tls_ciphers::{TlsCipherKx, TlsCipherSuite, CIPHERS};

    #[test]
    fn test_cipher_count() {
        println!("loaded: {} cipher suites", CIPHERS.len());
        assert!(CIPHERS.len() > 0);
    }

    #[test]
    fn test_cipher_from_id() {
        match TlsCipherSuite::from_id(0xc025) {
            Some(ref cipher) => {
                println!("Found cipher: {:?}", cipher);
            }
            None => assert!(false),
        }
    }

    #[test]
    fn test_cipher_from_name() {
        match TlsCipherSuite::from_name("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384") {
            Some(ref cipher) => {
                println!("Found cipher: {:?}", cipher);
            }
            None => assert!(false),
        }
    }

    #[test]
    fn test_cipher_filter() {
        let ecdhe_ciphers: Vec<&TlsCipherSuite> = CIPHERS
            .values()
            .filter(|c| c.kx == TlsCipherKx::Ecdhe)
            .collect();
        assert!(ecdhe_ciphers.len() > 20);
    }
}
<commit_msg>Add Copy trait to ciphersuite components<commit_after>//!
//! The [CIPHERS](static.CIPHERS.html) static hash map is built during the
//! compilation of the crate, using `build.rs`. It parses a file derived from
//! the [IANA TLS Cipher Suite
//! Registry](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4)
//! to automatically extract parameters and add all known ciphersuites.

#![allow(non_camel_case_types)]

use phf;

enum_from_primitive! {
/// Key exchange methods
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(u8)]
pub enum TlsCipherKx {
    Null = 0,
    Psk,
    Krb5,
    Srp,
    Rsa,
    Dh,
    Dhe,
    Ecdh,
    Ecdhe,
    Aecdh,
    Eccpwd,
    Tls13,
}
}

enum_from_primitive! {
/// Authentication methods
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(u8)]
pub enum TlsCipherAu {
    Null = 0,
    Psk,
    Krb5,
    Srp,
    Srp_Dss,
    Srp_Rsa,
    Dss,
    Rsa,
    Dhe,
    Ecdsa,
    Eccpwd,
    Tls13,
}
}

enum_from_primitive! {
/// Encryption methods
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(u8)]
pub enum TlsCipherEnc {
    Null,
    Des,
    TripleDes,
    Rc2,
    Rc4,
    Aria,
    Idea,
    Seed,
    Aes,
    Camellia,
    Chacha20_Poly1305,
    Sm4,
}
}

enum_from_primitive! {
/// Encryption modes
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(u8)]
pub enum TlsCipherEncMode {
    Null,
    Cbc,
    Ccm,
    Gcm,
}
}

enum_from_primitive! {
/// Message Authentication Code (MAC) methods
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(u8)]
pub enum TlsCipherMac {
    Null,
    HmacMd5,
    HmacSha1,
    HmacSha256,
    HmacSha384,
    Aead,
}
}

/// TLS Ciphersuite
#[derive(Debug)]
pub struct TlsCipherSuite {
    pub name: &'static str,
    pub id: u16,
    pub kx: TlsCipherKx,
    pub au: TlsCipherAu,
    pub enc: TlsCipherEnc,
    pub enc_mode: TlsCipherEncMode,
    pub enc_size: u16,
    pub mac: TlsCipherMac,
    pub mac_size: u16,
}

include!(concat!(env!("OUT_DIR"), "/codegen.rs"));

impl TlsCipherSuite {
    pub fn from_id(id: u16) -> Option<&'static TlsCipherSuite> {
        CIPHERS.get(&id)
    }

    pub fn from_name<'a>(name: &'a str) -> Option<&'static TlsCipherSuite> {
        CIPHERS.values().find(|&v| v.name == name)
    }
}

#[cfg(test)]
mod tests {
    use crate::tls_ciphers::{TlsCipherKx, TlsCipherSuite, CIPHERS};

    #[test]
    fn test_cipher_count() {
        println!("loaded: {} cipher suites", CIPHERS.len());
        assert!(CIPHERS.len() > 0);
    }

    #[test]
    fn test_cipher_from_id() {
        match TlsCipherSuite::from_id(0xc025) {
            Some(ref cipher) => {
                println!("Found cipher: {:?}", cipher);
            }
            None => assert!(false),
        }
    }

    #[test]
    fn test_cipher_from_name() {
        match TlsCipherSuite::from_name("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384") {
            Some(ref cipher) => {
                println!("Found cipher: {:?}", cipher);
            }
            None => assert!(false),
        }
    }

    #[test]
    fn test_cipher_filter() {
        let ecdhe_ciphers: Vec<&TlsCipherSuite> = CIPHERS
            .values()
            .filter(|c| c.kx == TlsCipherKx::Ecdhe)
            .collect();
        assert!(ecdhe_ciphers.len() > 20);
    }
}
<|endoftext|>