9fans.net/go@v0.0.7/cmd/sam/io.go (about) 1 package main 2 3 import ( 4 "log" 5 "os" 6 "os/exec" 7 "unicode/utf8" 8 ) 9 10 const ( 11 NSYSFILE = 3 12 NOFILE = 128 13 ) 14 15 func checkqid(f *File) { 16 w := whichmenu(f) 17 for i := 1; i < len(file); i++ { 18 g := file[i] 19 if w == i { 20 continue 21 } 22 if os.SameFile(f.info, g.info) { 23 warn_SS(Wdupfile, &f.name, &g.name) 24 } 25 } 26 } 27 28 var genc string 29 30 func writef(f *File) { 31 newfile := 0 32 samename := Strcmp(&genstr, &f.name) == 0 33 name := Strtoc(&f.name) 34 info, err := os.Stat(name) 35 if err != nil { 36 newfile++ 37 } else if samename && (!os.SameFile(f.info, info) || f.info.Size() != info.Size() || !f.info.ModTime().Equal(info.ModTime())) { 38 f.info = info 39 warn_S(Wdate, &genstr) 40 return 41 } 42 genc = string(genstr.s) 43 iofile, err = os.Create(genc) 44 if err != nil { 45 error_r(Ecreate, genc, err) 46 } 47 dprint("%s: ", genc) 48 if info, err := iofile.Stat(); err == nil && info.Mode()&os.ModeAppend != 0 && info.Size() > 0 { 49 error_(Eappend) 50 } 51 n := writeio(f) 52 if len(f.name.s) == 0 || samename { 53 if addr.r.p1 == 0 && addr.r.p2 == f.b.nc { 54 f.cleanseq = f.seq 55 } 56 mod := Clean 57 if f.cleanseq != f.seq { 58 mod = Dirty 59 } 60 state(f, mod) 61 } 62 if newfile != 0 { 63 dprint("(new file) ") 64 } 65 if addr.r.p2 > 0 && filereadc(f, addr.r.p2-1) != '\n' { 66 warn(Wnotnewline) 67 } 68 closeio(n) 69 if len(f.name.s) == 0 || samename { 70 if info, err := os.Stat(name); err == nil { 71 f.info = info 72 checkqid(f) 73 } 74 } 75 } 76 77 func readio(f *File, nulls *bool, setdate, toterm bool) Posn { 78 p := addr.r.p2 79 *nulls = false 80 b := 0 81 var nt Posn 82 if f.unread { 83 nt = bufload(&f.b, 0, iofile, nulls) 84 if toterm { 85 raspload(f) 86 } 87 } else { 88 var nr int 89 for nt = 0; ; nt += nr { 90 var buf [BLOCKSIZE]byte 91 n, err := iofile.Read(buf[b:]) 92 if err != nil || n == 0 { 93 break 94 } 95 n += b 96 b = 0 97 nr := 0 98 s := buf[:n] 99 for len(s) > 0 { 100 if s[0] < utf8.RuneSelf { 101 if s[0] != 0 { 102 genbuf[nr] = rune(s[0]) 103 nr++ 104 } else { 105 *nulls = true 106 } 107 s = s[1:] 108 continue 109 } 110 if utf8.FullRune(s) { 111 r, w := utf8.DecodeRune(s) 112 if r != 0 { 113 genbuf[nr] = r 114 nr++ 115 } else { 116 *nulls = true 117 } 118 s = s[w:] 119 continue 120 } 121 b = copy(buf[:], s) 122 break 123 } 124 loginsert(f, p, genbuf[:nr]) 125 } 126 } 127 if b != 0 { 128 *nulls = true 129 } 130 if *nulls { 131 warn(Wnulls) 132 } 133 if setdate { 134 if info, err := iofile.Stat(); err == nil { 135 f.info = info 136 checkqid(f) 137 } 138 } 139 return nt 140 } 141 142 func writeio(f *File) Posn { 143 p := addr.r.p1 144 for p < addr.r.p2 { 145 var n int 146 if addr.r.p2-p > BLOCKSIZE { 147 n = BLOCKSIZE 148 } else { 149 n = addr.r.p2 - p 150 } 151 bufread(&f.b, p, genbuf[:n]) 152 c := []byte(string(genbuf[:n])) // TODO(rsc) 153 if nw, err := iofile.Write(c); err != nil || nw != len(c) { 154 // free(c) 155 if p > 0 { 156 p += n 157 } 158 break 159 } 160 // free(c) 161 p += n 162 } 163 return p - addr.r.p1 164 } 165 166 func closeio(p Posn) { 167 iofile.Close() 168 iofile = nil 169 if p >= 0 { 170 dprint("#%d\n", p) 171 } 172 } 173 174 var remotefd0 IOFile = os.Stdin 175 var remotefd1 IOFile = os.Stdout 176 177 func bootterm(machine string, argv []string) { 178 if machine != "" { 179 cmd := exec.Command(argv[0], argv[1:]...) 180 cmd.Stdin = remotefd0 181 cmd.Stdout = remotefd1 182 if err := cmd.Start(); err != nil { 183 log.Fatal(err) 184 } 185 if err := cmd.Wait(); err != nil { 186 log.Fatalf("samterm: %v", err) 187 } 188 os.Exit(0) 189 } 190 191 cmd := exec.Command(samterm, argv[1:]...) 192 r1, w1, err := os.Pipe() 193 if err != nil { 194 log.Fatal(err) 195 } 196 r2, w2, err := os.Pipe() 197 if err != nil { 198 log.Fatal(err) 199 } 200 cmd.Stdin = r1 201 cmd.Stdout = w2 202 cmd.Stderr = os.Stderr 203 err = cmd.Start() 204 if err != nil { 205 log.Fatalf("samterm: %v", err) 206 } 207 r1.Close() 208 w2.Close() 209 210 os.Stdin = r2 211 os.Stdout = w1 212 } 213 214 func connectto(machine string, files []string) { 215 av := append([]string{RX, machine, rsamname, "-R"}, files...) 216 cmd := exec.Command(av[0], av[1:]...) 217 stdin, err := cmd.StdinPipe() 218 if err != nil { 219 log.Fatal(err) 220 } 221 stdout, err := cmd.StdoutPipe() 222 if err != nil { 223 log.Fatal(err) 224 } 225 err = cmd.Start() 226 if err != nil { 227 log.Fatalf("%s: %v", RX, err) 228 } 229 remotefd0 = stdout.(IOFile) 230 remotefd1 = stdin.(IOFile) 231 } 232 233 func startup(machine string, Rflag bool, argv []string, files []string) { 234 if machine != "" { 235 connectto(machine, files) 236 } 237 if !Rflag { 238 bootterm(machine, argv) 239 } 240 downloaded = true 241 outTs(Hversion, VERSION) 242 }