commit 65f3ba42356d9800e3836fac79d544560f0cb784
parent 12589fc26cadadc12e0553515826675575dd6142
Author: Matsuda Kenji <info@mtkn.jp>
Date: Wed, 15 Nov 2023 08:32:36 +0900
add parser
Diffstat:
M | main.go | | | 154 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- |
1 file changed, 147 insertions(+), 7 deletions(-)
diff --git a/main.go b/main.go
@@ -1,15 +1,60 @@
package main
import (
+ "context"
+ "errors"
"fmt"
+ "io"
"io/fs"
- "net"
"log"
+ "net"
+ "os"
+ "strings"
"git.mtkn.jp/lib9p"
"git.mtkn.jp/lib9p/client"
)
+type stat struct {
+ cwd string // current working directory.
+ f fs.File
+ fsys fs.FS
+}
+
+type token struct {
+ cmd string
+ err error
+}
+
+type cmd struct {
+ args []string
+ err error
+}
+
+func (c *cmd) run(s *stat) error {
+ if len(c.args) < 1 {
+ return errors.New("no command specified")
+ }
+ switch c.args[0] {
+ case "cd":
+ if len(c.args) != 2 {
+ return fmt.Errorf("usage: cd <dir>")
+ }
+ f, err := s.fsys.Open(c.args[1])
+ if err != nil {
+ return err
+ }
+ s.f = f
+ s.cwd = c.args[1]
+ return nil
+ case "pwd":
+ fmt.Println(s.cwd)
+ return nil
+ default:
+ return fmt.Errorf("unknown command %v", c.args[0])
+ }
+}
+
func main() {
conn, err := net.Dial("tcp", "127.0.0.1:5640")
if err != nil {
@@ -20,12 +65,107 @@ func main() {
if err != nil {
log.Fatalf("mount: %v", err)
}
- walk := func(path string, d fs.DirEntry, err error) error {
- fmt.Println(path)
- if err != nil {
- return err
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ tc := runTokenizer(ctx, os.Stdin)
+ cc := runParser(ctx, tc)
+ s := &stat{
+ fsys: lib9p.ExportFS{fsys},
+ }
+ for {
+ c := <-cc
+ if c.err == io.EOF {
+ break
+ } else if c.err != nil {
+ log.Println(c.err)
+ continue
+ }
+ if err := c.run(s); err != nil {
+ log.Println(err)
}
- return nil
}
- fs.WalkDir(lib9p.ExportFS{fsys}, ".", walk)
+}
+
+func read(r io.Reader) (string, error) {
+ b := make([]byte, 128)
+ n, err := r.Read(b)
+ if err != nil {
+ return "", err
+ }
+ return string(b[:n]), nil
+}
+
+func runTokenizer(ctx context.Context, r io.Reader) <-chan *token {
+ tc := make(chan *token)
+ go func() {
+ defer close(tc)
+L:
+ for {
+ select {
+ case <-ctx.Done():
+ break L
+ default:
+ }
+ str, err := read(r)
+ if err != nil {
+ select {
+ case tc <-&token{cmd: "", err: err}:
+ continue L
+ case <-ctx.Done():
+ break L
+ }
+ }
+ ts := strings.Split(str, " ")
+ for _, s := range ts {
+ t := &token{cmd: s, err: nil}
+ select {
+ case tc <- t:
+ case <-ctx.Done():
+ break L
+ }
+ }
+ }
+ }()
+ return tc
+}
+
+func runParser(ctx context.Context, tc <-chan *token) <-chan *cmd {
+ cc := make(chan *cmd)
+ go func() {
+ defer close(cc)
+L:
+ for {
+ c := new(cmd)
+M:
+ for {
+ select {
+ case <-ctx.Done():
+ break L
+ case t := <-tc:
+ if t.err != nil {
+ c.err = t.err
+ break M
+ }
+ end := false
+ if len(t.cmd) == 0 {
+ continue M
+ }
+ if t.cmd[len(t.cmd)-1] == '\n' {
+ t.cmd = t.cmd[:len(t.cmd)-1]
+ end = true
+ }
+ c.args = append(c.args, t.cmd)
+ if end {
+ break M
+ }
+ }
+ }
+ select {
+ case <-ctx.Done():
+ break L
+ case cc<- c:
+ }
+ }
+ }()
+ return cc
}
\ No newline at end of file