import java.io.FileNotFoundException import java.io.File import java.io.FileInputStream import scala.collection.mutable.HashMap class InvalidArgumentException extends Exception {} class GetOpt(f:String) { var _params:List[Tuple2[String,Boolean]] = null var _opt:HashMap[Any,Any] = null var _rest:Array[String] = null _params = f.toList.foldLeft(List[Tuple2[String,Boolean]]()) { (l,c) => c match { case ':' => l match { case List() => throw new InvalidArgumentException case h::r => (h._1,true)::r } case k => (k.toString,false)::l } }.reverse def parse(a:Array[String]):GetOpt = { def _parse(o:HashMap[Any,Any],l:List[String]):Tuple2[HashMap[Any,Any],List[String]] = l match { case List() => (o,List()) case h::r => h.toList match { case '-'::k => { _params.find { e => e._1 == new String(k.toArray) } match { case Some(Tuple2(_,true)) => { if (r.size == 0) throw new InvalidArgumentException o.update(new String(k.toArray),r.head) _parse(o,r.tail) } case Some(Tuple2(_,false)) => { o.update(new String(k.toArray),true) _parse(o,r) } case _ => throw new InvalidArgumentException } } case _ => (o,l) } } _parse(new HashMap[Any,Any],a.toList) match { case Tuple2(o,r) => { _opt = o; _rest = r.toArray } } this } def getopt(k:String):Any = _opt.isDefinedAt(k) match { case true => _opt.apply(k) case _ => false } def rest:Array[String] = _rest } class CTail(n:Int,f:Boolean,i:File) { val s:FileInputStream = new FileInputStream(i) def this(o:GetOpt) =this(o.getopt("n") match { case Some(false) => 10; case n => n.asInstanceOf[String].toInt },o.getopt("f").asInstanceOf[Boolean],new File(o.rest.apply(0))) def tailn:Unit = { val BUF_SIZE:Int = 4096 val e:Long = i.length def _tailn(p:Long,n:Int,b:Array[Byte]):Array[Byte] = { var t:Array[Byte] = null var l:Int = n (p > BUF_SIZE) match { case true => { t = new Array[Byte](BUF_SIZE) s.getChannel.position(p - BUF_SIZE) s.read(t,0,BUF_SIZE) } case _ => { t = new Array[Byte](p.toInt) s.read(t,0,p.toInt) } } t = t.reverse.takeWhile { c => if (c == '\n') l = l - 1; (l > 0) }.reverse ((p <= BUF_SIZE) || (l == 0)) match { case true => t ++ b case _ => _tailn(p - BUF_SIZE, l, t ++ b) } } print(new String(_tailn(e, n, new Array[Byte](0)))) s.getChannel.position(e) } def tailf:Unit = { def _tailf(b:List[Byte]):List[Byte] = { val c:Int = s.read (c >= 0) match { case true => _tailf(b + c.toByte) case _ => b } } print(new String(_tailf(List[Byte]()).toArray)) Thread.sleep(100) tailf } def tail:CTail = { tailn if (f) tailf this } def close:Unit = s.close } object Tail { def main(args:Array[String]):Unit = { try { val o:GetOpt = new GetOpt("n:f").parse(args) (new CTail(o)).tail.close } catch { case e:InvalidArgumentException => println("usage: scala Tail [-n ] [-f] file") case e:FileNotFoundException => print("file not found.") case e:Exception => e.printStackTrace } } }