github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/cmds/exp/ed/ed.go (about) 1 // Copyright 2019 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // This `ed` is intended to be a feature-complete mimick of [GNU Ed](https://www.gnu.org/software/ed//). It is a close enough mimick that the [GNU Ed Man Page](https://www.gnu.org/software/ed/manual/ed_manual.html) should be a reliable source of documentation. Divergence from the man page is generally considered a bug (unless it's an added feature). 6 // 7 // There are a few known differences: 8 // 9 // - `ed` uses `go`'s `regexp` package, and as such may have a somewhat different regular expression syntax. Note, however, that backreferences follow the `ed` syntax of `\<ref>`, not the `go` syntax of `$<ref>`. 10 // - there has been little/no attempt to make particulars like error messages match `GNU Ed`. 11 // - rather than being an error, the 'g' option for 's' simply overrides any specified count. 12 // - does not support "traditional" mode 13 // 14 // The following has been implemented: 15 // - Full line address parsing (including RE and markings) 16 // - Implmented commands: !, #, =, E, H, P, Q, W, a, c, d, e, f, h, i, j, k, l, m, n, p, q, r, s, t, u, w, x, y, z 17 // 18 // The following has *not* yet been implemented, but will be eventually: 19 // - Unimplemented commands: g, G, v, V 20 // - does not (yet) support "loose" mode 21 // - does not (yet) support "restricted" mod 22 package main 23 24 import ( 25 "bufio" 26 "flag" 27 "fmt" 28 "os" 29 ) 30 31 // flags 32 var ( 33 fSuppress = flag.Bool("s", false, "suppress counts") 34 fPrompt = flag.String("p", "*", "specify a command prompt") 35 ) 36 37 // current FileBuffer 38 var buffer *FileBuffer 39 40 // current ed state 41 var state struct { 42 fileName string // current filename 43 lastErr error 44 printErr bool 45 prompt bool 46 winSize int 47 lastRep string 48 lastSub string 49 } 50 51 // Parse input and run command 52 func run(cmd string) (e error) { 53 ctx := &Context{ 54 cmd: cmd, 55 } 56 if ctx.addrs, ctx.cmdOffset, e = buffer.ResolveAddrs(cmd); e != nil { 57 return 58 } 59 if len(cmd) <= ctx.cmdOffset { 60 // no command, default to print 61 ctx.cmd += "p" 62 } 63 if exe, ok := cmds[ctx.cmd[ctx.cmdOffset]]; ok { 64 buffer.Start() 65 if e = exe(ctx); e != nil { 66 return 67 } 68 buffer.End() 69 } else { 70 return fmt.Errorf("invalid command: %v", cmd[ctx.cmdOffset]) 71 } 72 return 73 } 74 75 // Entry point 76 func main() { 77 var e error 78 flag.Usage = func() { 79 fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [-s] [-p <prompt>] [file]\n", os.Args[0]) 80 flag.PrintDefaults() 81 } 82 flag.Parse() 83 flag.Visit(func(f *flag.Flag) { 84 if f.Name == "p" { 85 state.prompt = true 86 } 87 }) 88 args := flag.Args() 89 if len(args) > 1 { // we only accept one additional argument 90 flag.Usage() 91 os.Exit(1) 92 } 93 buffer = NewFileBuffer(nil) 94 if len(args) == 1 { // we were given a file name 95 state.fileName = args[0] 96 // try to read in the file 97 if _, e = os.Stat(state.fileName); os.IsNotExist(e) && !*fSuppress { 98 fmt.Fprintf(os.Stderr, "%s: No such file or directory", state.fileName) 99 // this is not fatal, we just start with an empty buffer 100 } else { 101 if buffer, e = FileToBuffer(state.fileName); e != nil { 102 fmt.Fprintln(os.Stderr, e) 103 os.Exit(1) 104 } 105 if !*fSuppress { 106 fmt.Println(buffer.Size()) 107 } 108 } 109 } 110 state.winSize = 22 // we don't actually support getting the real window size 111 inScan := bufio.NewScanner(os.Stdin) 112 if state.prompt { 113 fmt.Printf("%s", *fPrompt) 114 } 115 for inScan.Scan() { 116 cmd := inScan.Text() 117 e = run(cmd) 118 if e != nil { 119 state.lastErr = e 120 if !*fSuppress && state.printErr { 121 fmt.Println(e) 122 } else { 123 fmt.Println("?") 124 } 125 } 126 if state.prompt { 127 fmt.Printf("%s", *fPrompt) 128 } 129 } 130 if inScan.Err() != nil { 131 fmt.Fprintf(os.Stderr, "error reading stdin: %v", inScan.Err()) 132 os.Exit(1) 133 } 134 }