2014-03-31 16:40:21 +00:00
#![ crate_id(name = " paste " , vers = " 1.0.0 " , author = " Arcterus " ) ]
2014-02-28 17:19:32 +00:00
/*
* This file is part of the uutils coreutils package .
*
* ( c ) Arcterus < arcterus @ mail . com >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
* /
2014-03-31 16:40:21 +00:00
#![ feature(macro_rules) ]
2014-02-28 17:19:32 +00:00
extern crate getopts ;
2014-04-07 22:43:34 +00:00
extern crate libc ;
2014-02-28 17:19:32 +00:00
use std ::io ;
use std ::os ;
#[ path = " ../common/util.rs " ]
mod util ;
static NAME : & 'static str = " paste " ;
static VERSION : & 'static str = " 1.0.0 " ;
2014-05-28 12:01:30 +00:00
#[ allow(dead_code) ]
2014-06-08 07:56:37 +00:00
fn main ( ) { os ::set_exit_status ( uumain ( os ::args ( ) ) ) ; }
2014-05-28 11:43:37 +00:00
2014-06-08 07:56:37 +00:00
pub fn uumain ( args : Vec < String > ) -> int {
2014-05-16 08:32:58 +00:00
let program = args . get ( 0 ) . clone ( ) ;
2014-02-28 17:19:32 +00:00
2014-05-30 08:35:54 +00:00
let opts = [
2014-02-28 17:19:32 +00:00
getopts ::optflag ( " s " , " serial " , " paste one file at a time instead of in parallel " ) ,
getopts ::optopt ( " d " , " delimiters " , " reuse characters from LIST instead of TABs " , " LIST " ) ,
getopts ::optflag ( " h " , " help " , " display this help and exit " ) ,
getopts ::optflag ( " V " , " version " , " output version information and exit " )
] ;
let matches = match getopts ::getopts ( args . tail ( ) , opts ) {
Ok ( m ) = > m ,
2014-06-15 10:50:40 +00:00
Err ( f ) = > crash! ( 1 , " {} " , f )
2014-02-28 17:19:32 +00:00
} ;
if matches . opt_present ( " help " ) {
println! ( " {} {} " , NAME , VERSION ) ;
println! ( " " ) ;
println! ( " Usage: " ) ;
println! ( " {0:s} [OPTION]... [FILE]... " , program ) ;
println! ( " " ) ;
print! ( " {} " , getopts ::usage ( " Write lines consisting of the sequentially corresponding lines from each FILE, separated by TABs, to standard output. " , opts ) ) ;
} else if matches . opt_present ( " version " ) {
println! ( " {} {} " , NAME , VERSION ) ;
} else {
let serial = matches . opt_present ( " serial " ) ;
let delimiters = match matches . opt_str ( " delimiters " ) {
Some ( m ) = > m ,
2014-05-28 06:33:39 +00:00
None = > " \t " . to_string ( )
2014-02-28 17:19:32 +00:00
} ;
2014-05-17 10:32:14 +00:00
paste ( matches . free , serial , delimiters . as_slice ( ) ) ;
2014-02-28 17:19:32 +00:00
}
2014-06-08 07:56:37 +00:00
2014-06-12 04:41:53 +00:00
0
2014-02-28 17:19:32 +00:00
}
2014-05-25 09:20:52 +00:00
fn paste ( filenames : Vec < String > , serial : bool , delimiters : & str ) {
2014-05-16 09:14:28 +00:00
let mut files : Vec < io ::BufferedReader < Box < Reader > > > = filenames . move_iter ( ) . map ( | name |
2014-05-07 23:55:53 +00:00
io ::BufferedReader ::new (
2014-05-17 10:32:14 +00:00
if name . as_slice ( ) = = " - " {
2014-05-09 00:12:57 +00:00
box io ::stdio ::stdin_raw ( ) as Box < Reader >
2014-05-07 23:55:53 +00:00
} else {
2014-05-09 00:12:57 +00:00
box crash_if_err! ( 1 , io ::File ::open ( & Path ::new ( name ) ) ) as Box < Reader >
2014-05-07 23:55:53 +00:00
}
)
2014-02-28 17:19:32 +00:00
) . collect ( ) ;
2014-05-25 09:20:52 +00:00
let delimiters : Vec < String > = delimiters . chars ( ) . map ( | x | x . to_str ( ) ) . collect ( ) ;
2014-02-28 17:19:32 +00:00
let mut delim_count = 0 ;
if serial {
for file in files . mut_iter ( ) {
2014-05-25 09:20:52 +00:00
let mut output = String ::new ( ) ;
2014-02-28 17:19:32 +00:00
loop {
2014-05-23 12:28:40 +00:00
match file . read_line ( ) {
Ok ( line ) = > {
output . push_str ( line . as_slice ( ) . trim_right ( ) ) ;
output . push_str ( delimiters . get ( delim_count % delimiters . len ( ) ) . as_slice ( ) ) ;
}
2014-02-28 17:19:32 +00:00
Err ( f ) = > if f . kind = = io ::EndOfFile {
break
} else {
crash! ( 1 , " {} " , f . to_str ( ) )
}
2014-05-23 12:28:40 +00:00
}
2014-02-28 17:19:32 +00:00
delim_count + = 1 ;
}
2014-05-23 12:28:40 +00:00
println! ( " {} " , output . as_slice ( ) . slice_to ( output . len ( ) - 1 ) ) ;
2014-02-28 17:19:32 +00:00
}
} else {
2014-03-22 08:18:52 +00:00
let mut eof = Vec ::from_elem ( files . len ( ) , false ) ;
2014-02-28 17:19:32 +00:00
loop {
2014-05-28 06:33:39 +00:00
let mut output = " " . to_string ( ) ;
2014-02-28 18:11:24 +00:00
let mut eof_count = 0 ;
for ( i , file ) in files . mut_iter ( ) . enumerate ( ) {
2014-03-22 08:18:52 +00:00
if * eof . get ( i ) {
2014-02-28 18:11:24 +00:00
eof_count + = 1 ;
} else {
match file . read_line ( ) {
2014-05-23 12:28:40 +00:00
Ok ( line ) = > output . push_str ( line . as_slice ( ) . slice_to ( line . len ( ) - 1 ) ) ,
2014-02-28 18:11:24 +00:00
Err ( f ) = > if f . kind = = io ::EndOfFile {
2014-03-22 08:18:52 +00:00
* eof . get_mut ( i ) = true ;
2014-02-28 18:11:24 +00:00
eof_count + = 1 ;
} else {
crash! ( 1 , " {} " , f . to_str ( ) ) ;
}
2014-02-28 17:19:32 +00:00
}
2014-02-28 18:11:24 +00:00
}
2014-05-23 12:28:40 +00:00
output . push_str ( delimiters . get ( delim_count % delimiters . len ( ) ) . as_slice ( ) ) ;
2014-02-28 18:11:24 +00:00
delim_count + = 1 ;
2014-02-28 17:19:32 +00:00
}
2014-02-28 18:11:24 +00:00
if files . len ( ) = = eof_count {
2014-02-28 17:19:32 +00:00
break ;
}
2014-05-23 12:28:40 +00:00
println! ( " {} " , output . as_slice ( ) . slice_to ( output . len ( ) - 1 ) ) ;
2014-02-28 18:11:24 +00:00
delim_count = 0 ;
2014-02-28 17:19:32 +00:00
}
}
}