func main() { c := cmd.AppCtx() opts.NewFlag("D", "debug", &c.Debug) cmd.UnixIO("err") args := opts.Parse() if len(args) == 1 && ismode(args[0]) { args = append([]string{"mode"}, args...) } if len(args) == 0 || len(args)%2 != 0 { cmd.Warn("wrong number of arguments") opts.Usage() } nd := chd(args...) in := cmd.In("in") var err error for m := range in { switch d := m.(type) { case zx.Dir: cmd.Dprintf("got %T %s\n", d, d["Upath"]) if cerr := ch(d, nd); cerr != nil { cmd.Warn("%s", cerr) err = cerr } default: // ignored cmd.Dprintf("got %T\n", m) } } if err != nil { cmd.Exit(err) } }
func ignored(year, day string) bool { if lastyear != "" && strings.Split(year, ".")[0] > lastyear { cmd.Dprintf("ignored %s\n", year) return true } if day != "" && lastday != "" && strings.Split(day, ".")[0] > lastday { cmd.Dprintf("ignored %s %s\n", year, day) return true } return false }
func main() { cmd.UnixIO("err") c := cmd.AppCtx() opts.NewFlag("D", "debug", &c.Debug) opts.NewFlag("u", "unix IO", &ux) opts.NewFlag("g", "get contents", &gflag) if cmd.Args()[0] == "gf" { gflag = true } args := opts.Parse() if ux { cmd.UnixIO() } if len(args) == 0 { args = append(args, ".,1") } var dc <-chan face{} if !gflag { dc = cmd.Dirs(args...) } else { dc = cmd.Files(args...) } out := cmd.Out("out") var err error for m := range dc { cmd.Dprintf("got %T\n", m) switch m := m.(type) { case error: err = m cmd.Warn("%s", m) if !ux { m := fmt.Errorf("%s: %s", cmd.Args()[0], m) if ok := out <- m; !ok { close(dc, cerror(out)) } } case zx.Dir: if !ux { if ok := out <- m; !ok { close(dc, cerror(out)) } } else { printf("%s\n", m.Fmt()) } case []byte: if ok := out <- m; !ok { close(dc, cerror(out)) } } } if err := cerror(dc); err != nil { if !ux { out <- fmt.Errorf("%s: %s", cmd.Args()[0], err) } cmd.Exit(err) } cmd.Exit(err) }
func edit(t *ink.Txt) { in := t.Events() for ev := range in { cmd.Warn("got text: %v", ev.Args) switch ev.Args[0] { case "start": continue // Example: keep only a single view vs := t.Views() for _, v := range vs { if v != ev.Src { t.CloseView(v) } } // Example: do some edits from the program. go edits(t) case "tag": if len(ev.Args) == 1 || ev.Args[1] != "Del" { continue } t.Close() case "end": // Example: delete the text when all views are gone vs := t.Views() cmd.Dprintf("views %v\n", t.Views()) if len(vs) == 0 { t.Close() return } } } }
func mv1(src, dst zx.Dir) error { cmd.VWarn("%s %s", src["Upath"], dst["Upath"]) cmd.Dprintf("mv1: %s %s %s %s\n", src.SAddr(), src["Rpath"], dst.SAddr(), dst["Rpath"]) if dry { return nil } return cmd.Move(src["path"], dst["path"]) }
func TestBib2ref(t *testing.T) { c := cmd.AppCtx() c.Debug = testing.Verbose() lnc := b2s(cmd.ByteLines(cmd.Get("/zx/lib/bib/zx.bib", 0, -1))) rc := bib2ref(lnc) for ln := range rc { cmd.Dprintf("%s", ln) } }
func runFiles(fn func(nm string, c chan []byte, dc chan bool)) { var lnc chan []byte var dc chan bool in := cmd.Lines(cmd.In("in")) out := cmd.Out("out") nm := "in" for m := range in { cmd.Dprintf("got %T\n", m) switch m := m.(type) { case zx.Dir: if pflag { p := m["Upath"] if p == "" { p = m["path"] } nm = p } if dc != nil { close(lnc) <-dc } dc = nil lnc = nil if ok := out <- m; !ok { close(in, cerror(out)) } case []byte: if dc == nil { lnc = make(chan []byte) dc = make(chan bool, 1) go fn(nm, lnc, dc) } if ok := lnc <- m; !ok { close(in, cerror(lnc)) close(out, cerror(lnc)) } default: if dc != nil { close(lnc) <-dc } dc = nil lnc = nil if ok := out <- m; !ok { close(lnc, cerror(out)) close(in, cerror(out)) } } } if dc != nil { close(lnc, cerror(in)) <-dc } cmd.Exit(cerror(in)) }
// Run print lines in the current app context. func main() { c := cmd.AppCtx() cmd.UnixIO("err") opts.NewFlag("D", "debug", &c.Debug) opts.NewFlag("1", "collect all files (not one msg per file)", &one) ux := false opts.NewFlag("u", "use unix out", &ux) args := opts.Parse() if ux { cmd.UnixIO("out") } if len(args) != 0 { cmd.SetIn("in", cmd.Files(args...)) } buf := &bytes.Buffer{} in := cmd.In("in") out := cmd.Out("out") for m := range in { switch m := m.(type) { case []byte: buf.Write(m) case zx.Dir: if !one && buf.Len() > 0 { if ok := out <- buf.Bytes(); !ok { close(in, cerror(out)) break } buf = &bytes.Buffer{} } if !one && !ux { if ok := out <- m; !ok { close(in, cerror(out)) break } } case error: cmd.Warn("%s", m) default: cmd.Dprintf("ignored %T\n", m) if !ux { if ok := out <- m; !ok { close(in, cerror(out)) break } } } } if buf.Len() > 0 { out <- buf.Bytes() } if err := cerror(in); err != nil { cmd.Fatal(err) } }
func TestBibLoad(t *testing.T) { BibTexOk = true c := cmd.AppCtx() c.Debug = testing.Verbose() b, err := Load("/zx/lib/bib") if err != nil { t.Fatalf("load: %s", err) } if testing.Verbose() { b.WriteTo(os.Stdout) } cmd.Dprintf("cite plan 9 networks:\n") refs := b.Cites("VisageFS") for _, r := range refs { cmd.Dprintf("got:\n%s\n", strings.Join(r.Reference(), "\n")) } if len(refs) == 0 { t.Fatalf("did not find visage in bib") } }
func TestLoad(t *testing.T) { BibTexOk = false c := cmd.AppCtx() c.Debug = testing.Verbose() b, err := Load("/zx/lib/bib") if err != nil { t.Fatalf("load: %s", err) } if testing.Verbose() { b.WriteTo(os.Stdout) } cmd.Dprintf("cite plan 9 networks:\n") refs := b.Cites("plan", "9", "networks") for _, r := range refs { cmd.Dprintf("got:\n%s\n", strings.Join(r.Reference(), "\n")) } if len(refs) != 2 { t.Fatalf("wrong count for plan 9 networks at lsub bib") } }
// Run cols in the current app context. func main() { c := cmd.AppCtx() opts.NewFlag("D", "debug", &c.Debug) opts.NewFlag("w", "wid: set max line width", &wid) opts.NewFlag("n", "ncols: set number of columns", &ncols) opts.NewFlag("u", "use unix output", &ux) cmd.UnixIO("err") args := opts.Parse() if ux { cmd.UnixIO("out") } if len(args) != 0 { cmd.SetIn("in", cmd.Files(args...)) } in := cmd.In("in") for m := range in { switch m := m.(type) { default: // ignored & forwarded cmd.Dprintf("got %T\n", m) continue case zx.Dir: cmd.Dprintf("got %T %s\n", m, m["Upath"]) add(strings.TrimSpace(m["name"])) case error: if m != nil { cmd.Warn("%s", m) } case []byte: cmd.Dprintf("got %T [%d]\n", m, len(m)) words := strings.Fields(strings.TrimSpace(string(m))) add(words...) } } col() if err := cerror(in); err != nil { cmd.Fatal("in %s", err) } }
func replre(s string, re *sre.ReProg, to string, glob bool) string { rfrom := []rune(s) rto := []rune(to) nrefs := 0 for i := 0; i < len(rto)-1; i++ { if nb := rto[i+1]; rto[i] == '\\' { if nb >= '0' && nb <= '9' { nb -= '0' rto[i] = nb nrefs++ n := copy(rto[i+1:], rto[i+2:]) rto = rto[:i+1+n] } else if nb == '\\' { n := copy(rto[i+1:], rto[i+2:]) rto = rto[:i+1+n] } } } st := 0 for { cmd.Dprintf("re match [%d:%d]\n", st, len(rfrom)) rg := re.ExecRunes(rfrom, st, len(rfrom)) if len(rg) == 0 { break } r0 := rg[0] var ns []rune ns = append(ns, rfrom[:r0.P0]...) if nrefs == 0 { ns = append(ns, rto...) } else { for _, r := range rto { if r > 10 { ns = append(ns, r) continue } if r < rune(len(rg)) { t := rfrom[rg[r].P0:rg[r].P1] ns = append(ns, t...) } } } st = len(ns) ns = append(ns, rfrom[r0.P1:]...) rfrom = ns if !glob { break } } return string(rfrom) }
func kq(dir, wcmd string) { w, err := fswatch.New() if err != nil { cmd.Fatal("kqueue: %s", err) } cmd.Dprintf("(re)read %s\n", dir) if err := w.Add(dir); err != nil { cmd.Fatal("kqueue: %s", err) } if err != nil { cmd.Fatal("watch: %s", err) } var pc chan string if once { w.Once() } pc = w.Changes() for p := range pc { if wcmd == "" { cmd.Warn("%s", p) continue } cln := strings.Replace(wcmd, "%", p, -1) cmd.Dprintf("run %s\n", cln) out, err := exec.Command("sh", "-c", cln).CombinedOutput() cmd.Out("out") <- out if err != nil { cmd.Warn("run: %s", err) } } if err := cerror(pc); err != nil { cmd.Fatal(err) } cmd.Exit(nil) }
// Example of how to update the text from the API while the user edits it, // again, mostly for testing. func edits(t *ink.Txt) { time.Sleep(5 * time.Second) t.Ins([]rune("ZZZ\n"), 3) time.Sleep(1 * time.Second) rs := t.Del(3, 4) cmd.Dprintf("did del %s\n", string(rs)) time.Sleep(1 * time.Second) x := t.GetText() x.Ins([]rune("XXX\n"), 2) x.Ins([]rune("XXX\n"), x.Len()) t.SetMark("xx", 30) t.PutText() for i := 0; i < 30; i++ { time.Sleep(time.Second) t.MarkIns("xx", []rune(fmt.Sprintf("--%d--\n", i))) } }
func b2s(in <-chan []byte) <-chan string { rc := make(chan string) go func() { for x := range in { if ok := rc <- string(x); !ok { close(in, cerror(rc)) } } close(rc, cerror(in)) }() return rc } func (b *Bib) loadBib(fn string) error { lnc := b2s(cmd.ByteLines(cmd.Get(fn, 0, zx.All))) ln := <-lnc if !strings.Contains(ln, "bib2ref ok") { close(lnc, "not for me") return nil } cmd.Dprintf("add file %s\n", fn) return b.loadLines(bib2ref(lnc)) } func bib2ref(lnc <-chan string) chan string { rc := make(chan string) go parseBib(lnc, rc) return rc } func parseBib(lnc <-chan string, outc chan<- string) { for r, err := parse1Bib(lnc); err != io.EOF; r, err = parse1Bib(lnc) { for _, ln := range r { outc <- ln } outc <- "\n" } close(outc, cerror(lnc)) } // trim space and no final , func cleanLn(ln string) string { ln = strings.TrimSpace(ln) if len(ln) > 0 && ln[len(ln)-1] == ',' { ln = ln[:len(ln)-1] } return ln } func parse1Bib(lnc <-chan string) ([]string, error) { for { ln, ok := <-lnc if !ok { return nil, io.EOF } ln = cleanLn(ln) if ln == "" { continue } if ln[0] != '@' { continue } out := []string{} brace := strings.IndexRune(ln, '{') if brace < 0 { continue } ln = ln[brace+1:] toks := strings.Fields(ln) if len(toks) > 0 { out = append(out, "%K "+toks[0]+"\n") } for fld, err := parseField(lnc); err != io.EOF && fld != nil; fld, err = parseField(lnc) { out = append(out, fld...) } return out, nil } } var keys = map[string]string{ "author": "A", "title": "T", "note": "O", "booktitle": "B", "series": "S", "year": "D", "location": "C", "address": "C", "pages": "P", "url": "O", "publisher": "I", "key": "K", "volume": "V", "journal": "J", "keywords": "K", "organization": "I", } func parseField(lnc <-chan string) ([]string, error) { for { ln, ok := <-lnc if !ok { return nil, io.EOF } ln = cleanLn(ln) if ln == "" { return nil, nil } if ln[0] == '%' { continue } toks := strings.SplitN(ln, "=", 2) if len(toks) != 2 { continue } fname := strings.ToLower(strings.TrimSpace(toks[0])) if k := keys[fname]; k != "" { val := parseValue(k, toks[1]) for i, v := range val { val[i] = fmt.Sprintf("%%%s %s\n", k, strings.TrimSpace(v)) } return val, nil } } } func parseValue(key, ln string) []string { ln = strings.TrimSpace(ln) if len(ln) == 0 { return nil } if ln[0] == '"' { ln = ln[1:] if len(ln) > 0 && ln[len(ln)-1] == '"' { ln = ln[:len(ln)-1] } } else if len(ln) > 0 && ln[0] == '{' { ln = ln[1:] if len(ln) > 0 && ln[len(ln)-1] == '}' { ln = ln[:len(ln)-1] } } nln := "" incaps := 0 for _, r := range ln { switch r { case '\\', '\'': continue case '{': incaps++ case '}': incaps-- default: if incaps <= 0 || key == "A" { nln += string(r) } else { nln += strings.ToUpper(string(r)) } } } ln = nln if key == "A" { return strings.Split(ln, " and ") } if key == "K" { return strings.Split(ln, ",") } return []string{strings.TrimSpace(ln)} }
func lns(nm string, in chan []byte, donec chan bool) { last := []string{} nln := 0 cmd.Dprintf("nhd %d ntl %d nfrom %d\n", nhd, ntl, nfrom) var err error for m := range in { s := string(m) lout := false nln++ if all { if pflag { _, err = cmd.Printf("%s:%-5d %s", nm, nln, s) } else if nflag { _, err = cmd.Printf("%-5d %s", nln, s) } else { _, err = cmd.Printf("%s", s) } if err != nil { close(in, err) } continue } if ntl == 0 && nfrom == 0 && nhd > 0 && nln > nhd { close(in) close(donec) return } for _, a := range addrs { cmd.Dprintf("tl match %d of ? in %s\n", nln, a) if a.Matches(nln, 0) { lout = true if pflag { _, err = cmd.Printf("%s:%-5d %s", nm, nln, s) } else if nflag { _, err = cmd.Printf("%-5d %s", nln, s) } else { _, err = cmd.Printf("%s", s) } if err != nil { close(in, err) } break } } if nln >= nfrom || ntl > 0 { if lout { s = "" /*already there */ } if nln >= nfrom || ntl > 0 && len(last) < ntl { last = append(last, s) } else { copy(last, last[1:]) last[len(last)-1] = s } } } if !all && (ntl > 0 || nfrom > 0) { // if len(last) == 3 and nln is 10 // last[0] is -3 or 10-2 // last[1] is -2 or 10-1 // last[2] is -1 or 10 for i := 0; i < len(last); i++ { for _, a := range addrs { if a.P0 > 0 && a.P1 > 0 { // done already continue } cmd.Dprintf("tl match %d of %d in %s\n", nln-len(last)+1+i, nln, a) if a.Matches(nln-len(last)+1+i, nln) && last[i] != "" { if pflag { _, err = cmd.Printf("%s:%-5d %s", nm, nln-len(last)+1+i, last[i]) } else if nflag { _, err = cmd.Printf("%-5d %s", nln-len(last)+1+i, last[i]) } else { _, err = cmd.Printf("%s", last[i]) } if err != nil { close(donec, err) return } last[i] = "" /* because if empty it still contains \n */ break } } } } close(donec) }
// Run rem in the current app context. func main() { c := cmd.AppCtx() cmd.UnixIO("err") opts.NewFlag("D", "debug", &c.Debug) opts.NewFlag("v", "verbose; print the calls made in the order they are made.", &c.Verb) opts.NewFlag("a", "remove all", &aflag) opts.NewFlag("f", "quiet, called 'force' in unix", &fflag) opts.NewFlag("n", "dry run; report removes but do not do them", &dry) args := opts.Parse() if len(args) != 0 { cmd.SetIn("in", cmd.Dirs(args...)) } c.Verb = c.Verb || dry in := cmd.In("in") var err error for m := range in { switch d := m.(type) { case zx.Dir: cmd.Dprintf("got %T %s\n", d, d["upath"]) dirs = append(dirs, d) case error: cmd.Warn("%s", d) default: // ignored cmd.Dprintf("ignored %T\n", m) } } if aflag { for i := 0; i < len(dirs); i++ { if dirs[i] == nil { continue } pi := dirs[i]["path"] for j := 1; j < len(dirs); j++ { if i == j || dirs[j] == nil { continue } pj := dirs[j]["path"] if zx.HasPrefix(pj, pi) { dirs[j] = nil } } } } for i := len(dirs) - 1; i >= 0; i-- { if dirs[i] == nil { continue } if cerr := rmf(dirs[i]); cerr != nil { if !fflag { cmd.Warn("%s", cerr) err = cerr } } } if err == nil { err = cerror(in) if err != nil { cmd.Fatal(err) } } cmd.Exit(err) }
func find(dump, dpref, rel string, dc chan<- zx.Dir, ufile zx.Dir) { droot := fpath.Join(dump, dpref) years, err := cmd.GetDir(droot) if err != nil { cmd.Warn("%s", err) return } for i := len(years) - 1; i >= 0; i-- { year := years[i]["name"] if ignored(year, "") { continue } ypath := years[i]["path"] days, err := cmd.GetDir(ypath) if err != nil { cmd.Warn("%s: %s", ypath, err) continue } lastsz, lastmt, lastm := "", "", "" for j := len(days) - 1; j >= 0; j-- { day := days[j]["name"] if ignored(year, day) { continue } fpath := fpath.Join(days[j]["path"], rel) d, err := cmd.Stat(fpath) if err != nil { if !force { cmd.Dprintf("find: %s", err) return } continue } newm, newsz, newmt := d["mode"], d["size"], d["mtime"] if newsz == lastsz && newmt == lastmt && newm == lastm { continue } lastm, lastsz, lastmt = newm, newsz, newmt d["upath"] = ufile["path"] d["uupath"] = ufile["upath"] if ok := dc <- d; !ok { return } if !all { return } } } } func report(dc chan zx.Dir, donec chan bool) { last := "" for d := range dc { if last == "" { last = d["Upath"] if last == "" { last = d["path"] } } p := d["path"] cmd.Dprintf("found '%s'\n", p) var err error switch { case xcmd != "": _, err = cmd.Printf("%s %s %s\n", xcmd, p, last) case dflag: dcmd := fmt.Sprintf(`9 diff -n %s %s`, p, last) _, err = cmd.Printf("%s\n", dcmd) if err != nil { cmd.Warn("diff: %s", err) continue } case lflag: _, err = cmd.Printf("%s\n", d.Fmt()) case cflag: _, err = cmd.Printf("cp %s %s\n", p, d["Upath"]) default: _, err = cmd.Printf("%s\n", d["path"]) } if err != nil { close(dc, err) } last = p } close(donec, cerror(dc)) } func hist(in <-chan face{}) error { dc := make(chan zx.Dir) ec := make(chan bool) go report(dc, ec) var sts error for m := range in { switch m := m.(type) { case zx.Dir: cmd.Dprintf("got %T %s\n", m, m["path"]) file := m["path"] if m["upath"] == "" { m["upath"] = m["path"] } ddir := dump dpref := "" rel := "" switch { case zx.HasPrefix(file, "/zx"): if ddir == "" { ddir = "/dump" } dpref = "/zx" rel = zx.Suffix(file, "/zx") case zx.HasPrefix(file, "/u/gosrc/src/clive"): if ddir == "" { ddir = "/u/dump" } dpref = "clive" rel = zx.Suffix(file, "/u/gosrc/src/clive") case zx.HasPrefix(file, "/u"): if ddir == "" { ddir = "/u/dump" } els := zx.Elems(file) if len(els) < 3 { cmd.Warn("%s: too few path elements", m["upath"]) sts = errNoDump continue } dpref = els[1] rel = zx.Path(els[2:]...) default: cmd.Warn("%s: %s", m["upath"], errNoDump) sts = errNoDump continue } find(ddir, dpref, rel, dc, m.Dup()) default: cmd.Dprintf("got %T\n", m) } } close(dc, cerror(in)) <-ec if sts == nil { sts = cerror(ec) } if sts == nil { sts = cerror(in) } return sts } // Run cnt in the current app context. func main() { c := cmd.AppCtx() cmd.UnixIO("err") opts.NewFlag("D", "debug", &c.Debug) opts.NewFlag("f", "force search past file removals", &force) opts.NewFlag("l", "produce a long listing (or print just the name)", &lflag) opts.NewFlag("c", "copy the file from the dump", &cflag) opts.NewFlag("d", "print file differences", &dflag) opts.NewFlag("x", "cmd: print lines to execute this command between versions", &xcmd) opts.NewFlag("a", "list all copies that differ, not just the last one.", &all) opts.NewFlag("p", "dumpdir: path to dump (default is /dump or /u/dump)", &dump) t := time.Now() when := t opts.NewFlag("w", "date: backward search start time (default is now)", &when) ux := false opts.NewFlag("u", "unix IO", &ux) args := opts.Parse() if (all && cflag) || (force && !all) { cmd.Warn("incompatible flags") opts.Usage() } if ux { cmd.UnixIO("out") } lastyear = "" lastday = "" if !t.Equal(when) { y := when.Year() m := when.Month() d := when.Day() if y == 0 { y = t.Year() } lastyear = fmt.Sprintf("%04d", y) lastday = fmt.Sprintf("%02d%02d", m, d) } if len(args) != 0 { cmd.SetIn("in", cmd.Dirs(args...)) } in := cmd.In("in") if err := hist(in); err != nil { cmd.Fatal(err) } }