[Ngms-svn] SVN-Commit: [90] [NMShell] add command line parser

Back to archive index

svnno****@sourc***** svnno****@sourc*****
2010年 1月 14日 (木) 14:25:05 JST


Revision: 90
          http://sourceforge.jp/projects/ngms/svn/view?view=rev&revision=90
Author:   osiire
Date:     2010-01-14 14:25:05 +0900 (Thu, 14 Jan 2010)

Log Message:
-----------
[NMShell] add command line parser

Modified Paths:
--------------
    trunk/source/NMShell/src/info/ngms/commands/ls.scala
    trunk/source/NMShell/src/info/ngms/nmshell/Main.scala
    trunk/source/NMShell/src/info/ngms/nmshell/NMCommand.scala
    trunk/source/NMShell/src/info/ngms/nmshell/NMCommandStream.scala
    trunk/source/NMShell/src/info/ngms/nmshell/NMCommandThread.scala
    trunk/source/NMShell/src/info/ngms/nmshell/NMShellCommandParser.scala
    trunk/source/NMShell/src/info/ngms/nmshell/NMShellConfigFile.scala
    trunk/source/NMShell/src/info/ngms/nmshell/NMShellEnvironment.scala
    trunk/source/NMShell/src/info/ngms/nmshell/NMShellPipe.scala
    trunk/source/NMTree/src/info/ngms/nmtree/NMFileSystemTree.scala
    trunk/source/NMTree/src/info/ngms/nmtree/NMPath.scala

Added Paths:
-----------
    trunk/source/NMShell/src/info/ngms/commands/cd.scala
    trunk/source/NMShell/test/CommandParserTest.scala

Added: trunk/source/NMShell/src/info/ngms/commands/cd.scala
===================================================================
--- trunk/source/NMShell/src/info/ngms/commands/cd.scala	                        (rev 0)
+++ trunk/source/NMShell/src/info/ngms/commands/cd.scala	2010-01-14 05:25:05 UTC (rev 90)
@@ -0,0 +1,51 @@
+/*
+ *  Next Generation Management System Project
+ *  Copyright(c) 2009, NGMS Project Team All Rights Reserved.
+ */
+package info.ngms.commands
+
+import info.ngms.nmshell.NMCommand
+import info.ngms.nmshell.NMCommandContext
+import info.ngms.nmshell.NMCommandStream
+import info.ngms.nmshell.NMCommandStreamKind
+import info.ngms.nmshell.NMCommandParameterInfo
+import info.ngms.nmshell.NMShellEnvironment
+import info.ngms.nmshell.NMRawStream
+import info.ngms.nmshell.RawStream
+import info.ngms.nmtree.NMPath
+
+class cd extends NMCommand {
+    val name = "cd"
+
+    private class Options {
+        var dst : Option[NMPath] = None
+    }
+    private val options : Options = new Options
+
+    def parseOption( args : Array[String] ) : Unit = {
+        if(args.length > 0) {
+            val p = new NMPath(args(0))
+            options.dst = Some(p)
+        }
+    }
+
+    def parameters : List[ NMCommandParameterInfo ] = {
+        Nil
+    }
+
+    def doWork( env : NMCommandContext ) : Unit = {
+        options.dst match {
+          case Some(path) => {
+              if(path.exists)
+                  NMShellEnvironment.currentPath = path
+               else
+                   print(env, "no such file or directory\n")
+          }
+          case _ =>
+              ()
+        }
+    }
+
+    def inputStreamKind  = RawStream()
+    def outputStreamKind = RawStream()
+}

Modified: trunk/source/NMShell/src/info/ngms/commands/ls.scala
===================================================================
--- trunk/source/NMShell/src/info/ngms/commands/ls.scala	2010-01-13 02:02:50 UTC (rev 89)
+++ trunk/source/NMShell/src/info/ngms/commands/ls.scala	2010-01-14 05:25:05 UTC (rev 90)
@@ -11,6 +11,7 @@
 import info.ngms.nmshell.NMCommandParameterInfo
 import info.ngms.nmshell.NMRawStream
 import info.ngms.nmshell.RawStream
+import info.ngms.nmshell.NMShellEnvironment
 import info.ngms.nmtree.NMTreeElements
 
 class ls extends NMCommand {
@@ -24,16 +25,8 @@
     }
 
     def doWork( env : NMCommandContext ) : Unit = {
-        env.stdout match {
-            case NMRawStream(stream) => {
-                for(c <- "this is ls command\n") {
-                    stream.write(c)
-                }
-                stream.close
-            }
-            case _ =>
-                println("not support stream type")
-        }
+        val current = NMShellEnvironment.currentPath
+        current.children.foreach( p => print(env, p.basename + "\n"))
     }
 
     def inputStreamKind  = RawStream()

Modified: trunk/source/NMShell/src/info/ngms/nmshell/Main.scala
===================================================================
--- trunk/source/NMShell/src/info/ngms/nmshell/Main.scala	2010-01-13 02:02:50 UTC (rev 89)
+++ trunk/source/NMShell/src/info/ngms/nmshell/Main.scala	2010-01-14 05:25:05 UTC (rev 90)
@@ -4,19 +4,27 @@
  */
 package info.ngms.nmshell
 
+import java.io.OutputStreamWriter
 import info.ngms.nmtree.NMTree
 import info.ngms.nmtree.NMPath
 import info.ngms.nmtree.NMTreeImplementations
 
 object Main {
+
+    private def parseArgs( args : Array[String] ) : Unit = {
+
+    }
+
     def main(args : Array[String]) : Unit = {
+        parseArgs(args)
         NMTree.init( NMShellEnvironment )
         val root = new NMPath(NMPath.root)
         val config : NMShellConfigFile = new NMShellConfigFile(NMShellConfigFile.defaultPath)
         config.rootType match {
-            case NMTreeImplementations.RowFileSystem =>
+            case NMTreeImplementations.RowFileSystem => {
                 val fs = new info.ngms.nmtree.NMFileSystemTree( config.rootPath, root )
                 NMTree.mount( root, fs )
+            }
         }
         while(true)
             mainLoop()
@@ -26,30 +34,52 @@
         print(NMShellEnvironment.currentPath.toString + " $")
     }
 
+    private class CommandStruct {
+        var parsed : Command = null
+        var instance : NMCommand = null
+        var context : NMCommandContext = null
+    }
+
     def mainLoop() : Unit = {
         showPrompt()
         val line = readLine()
         try {
-            val cmds = NMShellCommandParser.parse(NMShellCommandParser.line, line).get
-            cmds match {
-              case Nil =>
+            val cmd = NMShellCommandParser.parse(NMShellCommandParser.line, line).get
+            cmd match {
+              case Exit =>
+                  System.exit(0)
+              case Statements(Nil) =>
                   ()
-              case _ =>
-                  NMShellCommandHistory.add(line)
-                  val cmdInstances = cmds.map( n => SearchCommandInstance(n._1, n._2) )
-                  val contexts = cmdInstances.map( cmd => new NMCommandContext(cmd.name) )
-                  val cmdp = cmdInstances.zip(contexts)
-                  connectCommandInstances(cmdp)
-                  NMShellEnvironment.startCommandJoiner(cmdInstances.length)
-                  cmdp.foreach(spawnCommand)
-                  NMShellEnvironment.join()
+              case Statements(sts) =>
+                  //NMShellCommandHistory.add(sts)
+                  sts.foreach( st => {
+                      val cts =
+                          st.cmds.map( parsed => {
+                              val ct = new CommandStruct;
+                              ct.parsed = parsed
+                              ct.instance = SearchCommandInstance(parsed.name)
+                              ct.context = new NMCommandContext(parsed.name)
+                              ct
+                          })
+                          // 以下3行は順番に注意
+                          cts.foreach(parseCommandArgs)
+                          connectCommandInstances(cts)
+                          cts.foreach(redirect)
+                          if(!st.background) {
+                              NMShellEnvironment.startCommandJoiner(cts.length)
+                              cts.foreach(spawnCommand)
+                              NMShellEnvironment.join()
+                          } else {
+                              cts.foreach(spawnCommand)
+                          }
+                  })
             }
         } catch {
             case _ => ()
         }
     }
 
-    def SearchCommandInstance( name : String, args : List[String] ) : NMCommand = {
+    def SearchCommandInstance( name : String ) : NMCommand = {
         try {
             Class.forName("info.ngms.commands." + name).newInstance().asInstanceOf[NMCommand]
         } catch {
@@ -60,20 +90,62 @@
         }
     }
 
-    private def connectCommandInstances( cmds : List[(NMCommand, NMCommandContext)] ) {
+    private def parseCommandArgs(ct : CommandStruct ) : Unit = {
+        ct.instance.parseOption(ct.parsed.args.toArray)
+    }
+
+    private def redirect( ct : CommandStruct ) : Unit = {
+        // input redirect
+        ct.parsed.input_path match {
+            case Some(path) if path.exists =>
+                () //未実装
+            case _ =>
+                ()
+        }
+        // output redirect
+        ct.parsed.out_redirects.foreach( redirect => {
+            redirect match {
+              case Dup(frm, dst) => () // 未実装
+              case Redirect(NumDescriptor(n), rtype, path) =>
+                 setStream(ct.context, n,
+                         NMRawStream(new Stream[Int] {
+                             val stream = NMTree.createStream(path)
+                             val writer = new OutputStreamWriter(stream.output)
+                             def read = None
+                             def write(x : Int) = writer.write(x)
+                             def flush = writer.flush
+                             def close = { writer.close; stream.close }
+                         }))
+              case _ => ()
+            }
+        })
+    }
+
+    private def setStream( instance : NMCommandContext, n : Int, stream : NMCommandStream ) : Unit = {
+        n match  {
+          case 1 =>
+              instance.stdout = stream
+          case 2 =>
+              instance.stderr = stream
+          case _ =>
+              ()
+        }
+    }
+
+    private def connectCommandInstances( cts : List[CommandStruct] ) {
         var stdin =  NMShellEnvironment.stdin
         var stdout = NMShellEnvironment.stdout
         var stderr = NMShellEnvironment.stderr
 
-        cmds.head._2.stdin = stdin
-        cmds.head._2.stderr = stderr
-        cmds.last._2.stdout = stdout
-        cmds.zip(cmds.tail).foreach {
+        cts.head.context.stdin = stdin
+        cts.head.context.stderr = stderr
+        cts.last.context.stdout = stdout
+        cts.zip(cts.tail).foreach {
             x =>
-                val cmd1 = x._1._1
-                val ctx1 = x._1._2
-                val cmd2 = x._2._1
-                val ctx2 = x._2._2
+                val cmd1 = x._1.instance
+                val ctx1 = x._1.context
+                val cmd2 = x._2.instance
+                val ctx2 = x._2.context
 
                 if(cmd1.outputStreamKind == cmd2.inputStreamKind){
                     ctx1.stdout = createStream(cmd1.outputStreamKind)
@@ -99,8 +171,8 @@
         }
     }
 
-    def spawnCommand( cmdp : (NMCommand, NMCommandContext) ) : Unit = {
-        val runnable : Runnable = new NMCommandThread( cmdp._1, cmdp._2 )
+    def spawnCommand( ct : CommandStruct ) : Unit = {
+        val runnable : Runnable = new NMCommandThread( ct.instance, ct.context )
         (new Thread( runnable )).start
     }
 }

Modified: trunk/source/NMShell/src/info/ngms/nmshell/NMCommand.scala
===================================================================
--- trunk/source/NMShell/src/info/ngms/nmshell/NMCommand.scala	2010-01-13 02:02:50 UTC (rev 89)
+++ trunk/source/NMShell/src/info/ngms/nmshell/NMCommand.scala	2010-01-14 05:25:05 UTC (rev 90)
@@ -25,4 +25,25 @@
      * @return 出力ストリームの種類
      */
     def outputStreamKind : NMCommandStreamKind
+
+    def print_stream( stream : NMCommandStream, msg : String ) : Unit = {
+        stream match {
+            case NMRawStream(stream) => {
+                for(c <- msg) {
+                    stream.write(c)
+                }
+                stream.flush
+            }
+            case _ =>
+                ()
+        }
+    }
+
+    def print( env : NMCommandContext, msg : String ) : Unit = {
+        print_stream(env.stdout, msg)
+    }
+
+    def print_err( env : NMCommandContext, msg : String ) : Unit = {
+        print_stream(env.stderr, msg)
+    }
 }

Modified: trunk/source/NMShell/src/info/ngms/nmshell/NMCommandStream.scala
===================================================================
--- trunk/source/NMShell/src/info/ngms/nmshell/NMCommandStream.scala	2010-01-13 02:02:50 UTC (rev 89)
+++ trunk/source/NMShell/src/info/ngms/nmshell/NMCommandStream.scala	2010-01-14 05:25:05 UTC (rev 90)
@@ -44,6 +44,11 @@
   def read() : Option[T]
 
   /**
+   * ストリームをフラッシュする
+   */
+  def flush() : Unit
+
+  /**
    * ストリームを閉じる。
    */
   def close : Unit

Modified: trunk/source/NMShell/src/info/ngms/nmshell/NMCommandThread.scala
===================================================================
--- trunk/source/NMShell/src/info/ngms/nmshell/NMCommandThread.scala	2010-01-13 02:02:50 UTC (rev 89)
+++ trunk/source/NMShell/src/info/ngms/nmshell/NMCommandThread.scala	2010-01-14 05:25:05 UTC (rev 90)
@@ -10,7 +10,9 @@
             NMShellEnvironment.addCommandContext(Thread.currentThread.getId(), context)
             cmd.doWork( context )
         } catch {
-        case _ => ()
+            case e =>
+                print(e.getMessage)
+                e.printStackTrace
         } finally {
             NMShellEnvironment.removeCommandContext(Thread.currentThread.getId())
         }

Modified: trunk/source/NMShell/src/info/ngms/nmshell/NMShellCommandParser.scala
===================================================================
--- trunk/source/NMShell/src/info/ngms/nmshell/NMShellCommandParser.scala	2010-01-13 02:02:50 UTC (rev 89)
+++ trunk/source/NMShell/src/info/ngms/nmshell/NMShellCommandParser.scala	2010-01-14 05:25:05 UTC (rev 90)
@@ -6,13 +6,127 @@
 
 import scala.util.parsing.combinator.Parsers
 import scala.util.parsing.combinator.RegexParsers
+import info.ngms.nmtree.NMPath
 
+private[nmshell] abstract class Line
+private[nmshell] case class Statements( sts : List[Statement]) extends Line
+private[nmshell] case object Exit extends Line
+
+private[nmshell] class Statement (val cmds : List[Command]) {
+    var background : Boolean = false
+}
+
+private[nmshell] abstract class RedirectType
+private[nmshell] case object NormalRedirect extends RedirectType
+private[nmshell] case object AppendRedirect extends RedirectType
+
+private[nmshell] abstract class OutRedirect
+private[nmshell] case class Dup( val frm : Descriptor, val dst : Descriptor ) extends OutRedirect
+private[nmshell] case class Redirect( val frm : Descriptor, val rtype : RedirectType, val path : NMPath ) extends OutRedirect
+
+private[nmshell] abstract class Descriptor
+private[nmshell] case object Close extends Descriptor
+private[nmshell] case class NumDescriptor(n : Int) extends Descriptor
+
+private[nmshell] abstract class OutCase
+private[nmshell] case class OutPath( path : NMPath ) extends OutCase
+private[nmshell] case class OutDescriptor( dest : Descriptor ) extends OutCase
+
+class Command( val name : String, val args : List[String]) {
+    var out_redirects : List[OutRedirect] = Nil
+    var input_path : Option[NMPath] = None
+}
+
 object NMShellCommandParser extends RegexParsers {
-    def line = repsep( cmd, pipe ) <~ rep(space)
+    def line = statements | exit
+
+    def exit = ":exit" <~ optional_spaces ^^ { case _ => Exit }
+
+    def statements = rep1sep(statement, statement_sep) <~ optional_spaces ^^ {
+        case sts => Statements(sts)
+    }
+    def statement_sep = ";" <~ rep(";")
+
+    def statement = statement_body ~ opt(background) <~ optional_spaces ^^ {
+        case st ~ Some(_) => { st.background = true; st }
+        case st ~ None => st
+    }
+    def background = "&"
+
+    def statement_body = head_exp ~ opt(piped_tail) ^^ {
+        case h ~ Some(exps) => new Statement( h :: exps )
+        case h ~ None => new Statement( List(h) )
+    }
+
+    def head_exp = (exp ~ opt(in_redirect_exp)) ^^ {
+        case exp ~ Some(path) => { exp.input_path = Some(path); exp }
+        case exp ~ None => exp
+    }
+
+    def in_redirect_exp = "<" ~ spaces ~> path
+    def piped_tail = pipe ~> rep1sep( exp, pipe )
     def pipe = "|"
-    def cmd = cmdName ~ rep(space) ~ repsep(arg, spaces) <~ rep(space) ^^ { case cmd ~ sp ~ args => (cmd, args) }
-    def cmdName = "[^ ]+".r
-    def arg = "[^| ]+".r
-    def space = " "
+
+    def exp : Parser[Command] = (((optional_spaces ~> command) <~ optional_spaces) ~ out_redirects) <~ optional_spaces ^^ {
+        case cmd ~ rs => {
+            cmd.out_redirects = rs
+            cmd
+        }
+    }
+
+    def dd(x : Option[Descriptor]) = x.getOrElse(NumDescriptor(1))
+
+    def out_redirects = repsep( out_redirect, spaces ) <~ optional_spaces
+
+    def out_redirect = ((opt(file_descriptor) ~ out_redirect_symbol ~ out_case1) | (opt(file_descriptor) ~ out_redirect_symbol ~ out_case2)) ^^ {
+        case frm ~ _ ~ OutDescriptor(dst) => Dup( dd(frm), dst )
+        case frm ~ rtype ~ OutPath(path) => Redirect( dd(frm), rtype, path )
+    }
+
+    def path = cmd_string ^^ { case p => new NMPath(p) }
+
+    def out_case1 : Parser[OutCase] = "&" ~> opt(file_descriptor) ^^ {
+        case None => OutDescriptor(NumDescriptor(1))
+        case Some(d : Descriptor) => OutDescriptor(d)
+    }
+    def out_case2 : Parser[OutCase] = optional_spaces ~> path ^^ { case path => OutPath(path) }
+
+    def out_redirect_symbol = (">" | ">>") ^^ {
+        case ">" => NormalRedirect
+        case ">>" => AppendRedirect
+    }
+
+    def file_descriptor = (number | "-") ^^ {
+        case "-" => Close
+        case num => NumDescriptor(Integer.parseInt(num))
+    }
+    def number = "[1-9]+[0-9]*".r
+
+    def command = command_name ~ repsep(cmd_string, spaces) ^^ {
+        case name ~ args => new Command(name, args)
+    }
+    def command_name = "[^ :<>|&`\"]+".r
+
+    def cmd_string = ("\"" ~> double_quote_escaped_string) <~ "\"" | space_escaped_string
+
+    def double_quote_escaped_string = rep(double_quote_escaped_char) ^^ {
+        case l => l.foldLeft ("") { (a,b) => a + b }
+    }
+
+    def double_quote_escaped_char = non_double_quote_char | double_double_quote
+    def non_double_quote_char = "[^\"<>|&`]".r
+    def double_double_quote = "\"\"" ^^ { case _ => "\"" }
+
+    def space_escaped_string = rep(space_escaped_char)  ^^ {
+        case l => l.foldLeft ("") { (a,b) => a + b }
+    }
+
+    def space_escaped_char = non_space_char | escape_space_char
+    def non_space_char = "[^ <>|&`]".r
+    def escape_space_char = """\ """
+
+    def expand_command = "`" ~> command <~ "`"
+
     def spaces = " +".r
+    def optional_spaces = opt(spaces)
 }

Modified: trunk/source/NMShell/src/info/ngms/nmshell/NMShellConfigFile.scala
===================================================================
--- trunk/source/NMShell/src/info/ngms/nmshell/NMShellConfigFile.scala	2010-01-13 02:02:50 UTC (rev 89)
+++ trunk/source/NMShell/src/info/ngms/nmshell/NMShellConfigFile.scala	2010-01-14 05:25:05 UTC (rev 90)
@@ -6,6 +6,7 @@
 
 object NMShellConfigFile {
     val defaultPath = "share/ngms/ngms.conf"
+    val userPath = "~/.ngms/ngms.conf"
 }
 
 /**
@@ -13,6 +14,7 @@
  */
 class NMShellConfigFile ( path : String ) {
     // 未実装
-    val rootPath = "/"
+    val rootPath = "./share/ngms/data"
+    val initialUser = "root"
     val rootType = info.ngms.nmtree.NMTreeImplementations.RowFileSystem
 }
\ No newline at end of file

Modified: trunk/source/NMShell/src/info/ngms/nmshell/NMShellEnvironment.scala
===================================================================
--- trunk/source/NMShell/src/info/ngms/nmshell/NMShellEnvironment.scala	2010-01-13 02:02:50 UTC (rev 89)
+++ trunk/source/NMShell/src/info/ngms/nmshell/NMShellEnvironment.scala	2010-01-14 05:25:05 UTC (rev 90)
@@ -6,6 +6,7 @@
 
 import info.ngms.nmtree.NMTree
 import info.ngms.nmtree.NMPath
+import info.ngms.nmtree.NMUser
 import info.ngms.nmtree.NMTreeElements
 import info.ngms.nmtree.NMStreamElem
 import info.ngms.nmtree.NMTreeElements
@@ -35,7 +36,23 @@
         pc.set(pc.take + ( id -> c ))
     }
 
+    def closeStream( stream : NMCommandStream ) : Unit = {
+        stream match {
+        case NMRawStream(stream) => stream.close
+        case _ => ()
+        }
+    }
+
     def removeCommandContext( id : Long ) : Unit = {
+        val context = getCommandContext(id)
+        context match {
+        case Some(context) => {
+                closeStream(context.stdin)
+                closeStream(context.stdout)
+                closeStream(context.stderr)
+            }
+        case _ => ()
+        }
         pc.set(pc.take - id )
         commandEndNotify.write(())
     }
@@ -61,37 +78,45 @@
      * 標準入力
      */
     val stdin : NMCommandStream = {
-      NMRawStream(new Stream[Int]{
-    def read = Some(System.in.read)
-    def write(x : Int) = ()
-    def close = ()
-      })
+        NMRawStream(new Stream[Int]{
+            def read = Some(System.in.read)
+            def write(x : Int) = ()
+            def flush = ()
+            def close = ()
+        })
     }
 
     /**
      * 標準出力
      */
     val stdout : NMCommandStream = {
-      NMRawStream(new Stream[Int]{
-    def read = None
-    def write(x : Int) = System.out.write(x)
-    def close = ()
-      })
+          NMRawStream(new Stream[Int]{
+              def read = None
+              def write(x : Int) = System.out.write(x)
+              def flush = ()
+              def close = ()
+          })
     }
 
     /**
      * 標準エラー
      */
     val stderr : NMCommandStream = {
-      NMRawStream(new Stream[Int]{
-    def read = None
-    def write(x : Int) = System.err.write(x)
-    def close = ()
-      })
-    }
+          NMRawStream(new Stream[Int]{
+              def read = None
+              def write(x : Int) = System.err.write(x)
+              def flush = ()
+              def close = ()
+          })
+      }
 
     /**
-     *
+     * 現在のパス
      */
     var currentPath : NMPath = new NMPath(NMPath.root)
+
+    /**
+     * 現在のユーザー
+     */
+    var currentUser : NMUser = NMUser.root
 }

Modified: trunk/source/NMShell/src/info/ngms/nmshell/NMShellPipe.scala
===================================================================
--- trunk/source/NMShell/src/info/ngms/nmshell/NMShellPipe.scala	2010-01-13 02:02:50 UTC (rev 89)
+++ trunk/source/NMShell/src/info/ngms/nmshell/NMShellPipe.scala	2010-01-14 05:25:05 UTC (rev 90)
@@ -26,6 +26,8 @@
         }
     }
 
+    def flush() = ()
+
     def close {
         mbox send End
     }

Added: trunk/source/NMShell/test/CommandParserTest.scala
===================================================================
--- trunk/source/NMShell/test/CommandParserTest.scala	                        (rev 0)
+++ trunk/source/NMShell/test/CommandParserTest.scala	2010-01-14 05:25:05 UTC (rev 90)
@@ -0,0 +1,76 @@
+package info.ngms.nmshell.test
+
+import org.scalatest.FunSuite
+import org.scalatest.BeforeAndAfterEach
+import info.ngms.nmshell._
+import info.ngms.nmshell.NMShellCommandParser._
+
+class CommandParserTest extends FunSuite with BeforeAndAfterEach {
+
+    test("name") {
+        val input = "cd /config"
+        val line = NMShellCommandParser.parse(NMShellCommandParser.line, input).get
+        line match {
+            case Exit => assert(false)
+            case Statements(sts) => {
+                assert(sts.length == 1)
+                assert(sts.head.cmds.head.name === "cd")
+                assert(sts.head.cmds.head.args.head === "/config")
+            }
+        }
+    }
+
+    test("pipe") {
+        val input = " foo -la | bar -args "
+        val line = NMShellCommandParser.parse(NMShellCommandParser.line, input).get
+        line match {
+            case Exit => assert(false)
+            case Statements(st :: Nil) => {
+                st.cmds match {
+                    case cmd1 :: cmd2 :: Nil => {
+                        assert(cmd1.name === "foo")
+                        assert(cmd2.name === "bar")
+                        assert(cmd2.args.head === "-args")
+                    }
+                    case _ => assert(false)
+                }
+            }
+            case _ => assert(false)
+        }
+    }
+
+    test("exit") {
+        val input = ":exit"
+        val line = NMShellCommandParser.parse(NMShellCommandParser.line, input).get
+        line match {
+            case Exit => ()
+            case _ => assert(false)
+        }
+    }
+
+    test("redirect1") {
+        val input = " foo -la > /path/to"
+        val line = NMShellCommandParser.parse(NMShellCommandParser.line, input).get
+        line match {
+            case Statements(st :: Nil) => {
+                st.cmds match {
+                    case cmd1 :: Nil => {
+                        assert(cmd1.name === "foo")
+                        assert(cmd1.out_redirects.length === 1)
+                        cmd1.out_redirects.head match {
+                            case Redirect(NumDescriptor(n), NormalRedirect, path) => {
+                                assert(n === 1)
+                                assert(path.canonical === "/path/to")
+                            }
+                            case _ => assert(false)
+                        }
+                    }
+                    case _ => assert(false)
+                }
+            }
+            case _ => assert(false)
+        }
+    }
+}
+
+

Modified: trunk/source/NMTree/src/info/ngms/nmtree/NMFileSystemTree.scala
===================================================================
--- trunk/source/NMTree/src/info/ngms/nmtree/NMFileSystemTree.scala	2010-01-13 02:02:50 UTC (rev 89)
+++ trunk/source/NMTree/src/info/ngms/nmtree/NMFileSystemTree.scala	2010-01-14 05:25:05 UTC (rev 90)
@@ -33,7 +33,9 @@
         file.createNewFile()
         new {
             val input : InputStream = new FileInputStream( file )
-            val output : OutputStream = new FileOutputStream( file )
+            val output : OutputStream = {
+                new FileOutputStream( file )
+            }
             def close : Unit =
                 input.close
                 output.close

Modified: trunk/source/NMTree/src/info/ngms/nmtree/NMPath.scala
===================================================================
--- trunk/source/NMTree/src/info/ngms/nmtree/NMPath.scala	2010-01-13 02:02:50 UTC (rev 89)
+++ trunk/source/NMTree/src/info/ngms/nmtree/NMPath.scala	2010-01-14 05:25:05 UTC (rev 90)
@@ -133,21 +133,24 @@
     }
 
     private object PathParser extends RegexParsers {
-       def emptyName( e : Element ) = {
-           e match {
-             case Name(n) if (n.length == 0) => true
-             case _ => false
-           }
-       }
-       def seps = separator <~ rep(separator)
+        def emptyName( e : Element ) = {
+            e match {
+            case Name(n) if (n.length == 0) => true
+            case _ => false
+            }
+        }
 
-       def path = opt(seps) ~ repsep( elem, seps ) ~ opt(seps) ^^
-           { case head ~ elems ~ _ => new InnerPath( head, elems.filter( e => !emptyName(e)))}
-       def elem = "[^/]+".r ^^ {
-           case "." => DOT
-           case ".." => UP
-           case n => Name(n)
-       }
+        def seps = separator <~ rep(separator)
+
+        def elem = "[^/]+".r ^^ {
+            case "." => DOT
+            case ".." => UP
+            case n => Name(n)
+        }
+
+        def path = opt(seps) ~ repsep( elem, seps ) ~ opt(seps) ^^ {
+            case head ~ elems ~ _ => new InnerPath( head, elems.filter( e => !emptyName(e)))
+        }
    }
 
     private def makeInnerPath( path : String ) : InnerPath = {




Ngms-svn メーリングリストの案内
Back to archive index