9fans.net/go@v0.0.7/cmd/sam/xec.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "os" 6 "strings" 7 ) 8 9 var Glooping int 10 var nest int 11 12 func resetxec() { 13 nest = 0 14 Glooping = nest 15 } 16 17 func cmdexec(f *File, cp *Cmd) bool { 18 if f != nil && f.unread { 19 load(f) 20 } 21 if f == nil && (cp.addr == nil || cp.addr.type_ != '"') && !strings.ContainsRune("bBnqUXY!", cp.cmdc) && cp.cmdc != 'c'|0x100 && (cp.cmdc != 'D' || cp.ctext == nil) { 22 error_(Enofile) 23 } 24 i := lookup(cp.cmdc) 25 if i >= 0 && cmdtab[i].defaddr != aNo { 26 ap := cp.addr 27 if ap == nil && cp.cmdc != '\n' { 28 ap = newaddr() 29 cp.addr = ap 30 ap.type_ = '.' 31 if cmdtab[i].defaddr == aAll { 32 ap.type_ = '*' 33 } 34 } else if ap != nil && ap.type_ == '"' && ap.next == nil && cp.cmdc != '\n' { 35 ap.next = newaddr() 36 ap.next.type_ = '.' 37 if cmdtab[i].defaddr == aAll { 38 ap.next.type_ = '*' 39 } 40 } 41 if cp.addr != nil { /* may be false for '\n' (only) */ 42 if f != nil { 43 addr = address(ap, f.dot, 0) 44 } else { /* a " */ 45 addr = address(ap, Address{}, 0) 46 } 47 f = addr.f 48 } 49 } 50 current(f) 51 switch cp.cmdc { 52 case '{': 53 var a Address 54 if cp.addr != nil { 55 a = address(cp.addr, f.dot, 0) 56 } else { 57 a = f.dot 58 } 59 for cp = cp.ccmd; cp != nil; cp = cp.next { 60 a.f.dot = a 61 cmdexec(a.f, cp) 62 } 63 default: 64 return cmdtab[i].fn(f, cp) 65 } 66 return true 67 } 68 69 func a_cmd(f *File, cp *Cmd) bool { 70 return fappend(f, cp, addr.r.p2) 71 } 72 73 func b_cmd(f *File, cp *Cmd) bool { 74 debug("%c ctext=%q\n", cp.cmdc, string(cp.ctext.s)) 75 if cp.cmdc == 'b' { 76 f = tofile(cp.ctext) 77 } else { 78 f = getfile(cp.ctext) 79 } 80 if f.unread { 81 load(f) 82 } else if nest == 0 { 83 filename(f) 84 } 85 return true 86 } 87 88 func c_cmd(f *File, cp *Cmd) bool { 89 logdelete(f, addr.r.p1, addr.r.p2) 90 f.ndot.r.p2 = addr.r.p2 91 f.ndot.r.p1 = f.ndot.r.p2 92 return fappend(f, cp, addr.r.p2) 93 } 94 95 func d_cmd(f *File, cp *Cmd) bool { 96 logdelete(f, addr.r.p1, addr.r.p2) 97 f.ndot.r.p2 = addr.r.p1 98 f.ndot.r.p1 = f.ndot.r.p2 99 return true 100 } 101 102 func D_cmd(f *File, cp *Cmd) bool { 103 closefiles(f, cp.ctext) 104 return true 105 } 106 107 func e_cmd(f *File, cp *Cmd) bool { 108 if getname(f, cp.ctext, cp.cmdc == 'e') == 0 { 109 error_(Enoname) 110 } 111 edit(f, cp.cmdc) 112 return true 113 } 114 115 func f_cmd(f *File, cp *Cmd) bool { 116 getname(f, cp.ctext, true) 117 filename(f) 118 return true 119 } 120 121 func g_cmd(f *File, cp *Cmd) bool { 122 if f != addr.f { 123 panic_("g_cmd f!=addr.f") 124 } 125 compile(cp.re) 126 if execute(f, addr.r.p1, addr.r.p2) != (cp.cmdc == 'v') { 127 f.dot = addr 128 return cmdexec(f, cp.ccmd) 129 } 130 return true 131 } 132 133 func i_cmd(f *File, cp *Cmd) bool { 134 return fappend(f, cp, addr.r.p1) 135 } 136 137 func k_cmd(f *File, cp *Cmd) bool { 138 f.mark = addr.r 139 return true 140 } 141 142 func m_cmd(f *File, cp *Cmd) bool { 143 addr2 := address(cp.caddr, f.dot, 0) 144 if cp.cmdc == 'm' { 145 move(f, addr2) 146 } else { 147 fcopy(f, addr2) 148 } 149 return true 150 } 151 152 func n_cmd(f *File, cp *Cmd) bool { 153 for _, f := range file { 154 if f == cmd { 155 continue 156 } 157 Strduplstr(&genstr, &f.name) 158 filename(f) 159 } 160 return true 161 } 162 163 func p_cmd(f *File, cp *Cmd) bool { 164 return display(f) 165 } 166 167 func q_cmd(f *File, cp *Cmd) bool { 168 trytoquit() 169 if downloaded { 170 outT0(Hexit) 171 return true 172 } 173 return false 174 } 175 176 func s_cmd(f *File, cp *Cmd) bool { 177 didsub := 0 178 delta := 0 179 180 n := cp.num 181 op := -1 182 compile(cp.re) 183 for p1 := addr.r.p1; p1 <= addr.r.p2 && execute(f, p1, addr.r.p2); { 184 if sel.p[0].p1 == sel.p[0].p2 { /* empty match? */ 185 if sel.p[0].p1 == op { 186 p1++ 187 continue 188 } 189 p1 = sel.p[0].p2 + 1 190 } else { 191 p1 = sel.p[0].p2 192 } 193 op = sel.p[0].p2 194 n-- 195 if n > 0 { 196 continue 197 } 198 Strzero(&genstr) 199 for i := 0; i < len(cp.ctext.s); i++ { // i reassigned below 200 c := cp.ctext.s[i] 201 if c == '\\' && i+1 < len(cp.ctext.s) { 202 i++ 203 c = cp.ctext.s[i] 204 if '1' <= c && c <= '9' { 205 j := c - '0' 206 if sel.p[j].p2-sel.p[j].p1 > BLOCKSIZE { 207 error_(Elongtag) 208 } 209 bufread(&f.b, sel.p[j].p1, genbuf[:sel.p[j].p2-sel.p[j].p1]) 210 Strinsert(&genstr, tmprstr(genbuf[:(sel.p[j].p2-sel.p[j].p1)]), len(genstr.s)) 211 } else { 212 Straddc(&genstr, c) 213 } 214 } else if c != '&' { 215 Straddc(&genstr, c) 216 } else { 217 if sel.p[0].p2-sel.p[0].p1 > BLOCKSIZE { 218 error_(Elongrhs) 219 } 220 bufread(&f.b, sel.p[0].p1, genbuf[:sel.p[0].p2-sel.p[0].p1]) 221 Strinsert(&genstr, tmprstr(genbuf[:sel.p[0].p2-sel.p[0].p1]), len(genstr.s)) 222 } 223 } 224 if sel.p[0].p1 != sel.p[0].p2 { 225 logdelete(f, sel.p[0].p1, sel.p[0].p2) 226 delta -= sel.p[0].p2 - sel.p[0].p1 227 } 228 if len(genstr.s) > 0 { 229 loginsert(f, sel.p[0].p2, genstr.s) 230 delta += len(genstr.s) 231 } 232 didsub = 1 233 if !cp.flag { 234 break 235 } 236 } 237 if didsub == 0 && nest == 0 { 238 error_(Enosub) 239 } 240 f.ndot.r.p1 = addr.r.p1 241 f.ndot.r.p2 = addr.r.p2 + delta 242 return true 243 } 244 245 func u_cmd(f *File, cp *Cmd) bool { 246 n := cp.num 247 if n >= 0 { 248 for { 249 tmp35 := n 250 n-- 251 if !(tmp35 != 0) || !(undo(true) != 0) { 252 break 253 } 254 } 255 } else { 256 for { 257 tmp36 := n 258 n++ 259 if !(tmp36 != 0) || !(undo(false) != 0) { 260 break 261 } 262 } 263 } 264 return true 265 } 266 267 func w_cmd(f *File, cp *Cmd) bool { 268 fseq := f.seq 269 if getname(f, cp.ctext, false) == 0 { 270 error_(Enoname) 271 } 272 if fseq == seq { 273 error_s(Ewseq, genc) 274 } 275 writef(f) 276 return true 277 } 278 279 func x_cmd(f *File, cp *Cmd) bool { 280 if cp.re != nil { 281 looper(f, cp, cp.cmdc == 'x') 282 } else { 283 linelooper(f, cp) 284 } 285 return true 286 } 287 288 func X_cmd(f *File, cp *Cmd) bool { 289 filelooper(cp, cp.cmdc == 'X') 290 return true 291 } 292 293 func plan9_cmd(f *File, cp *Cmd) bool { 294 plan9(f, cp.cmdc, cp.ctext, nest > 0) 295 return true 296 } 297 298 func eq_cmd(f *File, cp *Cmd) bool { 299 var charsonly bool 300 switch len(cp.ctext.s) { 301 case 0: 302 charsonly = false 303 case 1: 304 if cp.ctext.s[0] == '#' { 305 charsonly = true 306 break 307 } 308 fallthrough 309 default: 310 error_(Enewline) 311 } 312 printposn(f, charsonly) 313 return true 314 } 315 316 func nl_cmd(f *File, cp *Cmd) bool { 317 if cp.addr == nil { 318 /* First put it on newline boundaries */ 319 addr = lineaddr(Posn(0), f.dot, -1) 320 a := lineaddr(Posn(0), f.dot, 1) 321 addr.r.p2 = a.r.p2 322 if addr.r.p1 == f.dot.r.p1 && addr.r.p2 == f.dot.r.p2 { 323 addr = lineaddr(Posn(1), f.dot, 1) 324 } 325 display(f) 326 } else if downloaded { 327 moveto(f, addr.r) 328 } else { 329 display(f) 330 } 331 return true 332 } 333 334 func cd_cmd(f *File, cp *Cmd) bool { 335 cd(cp.ctext) 336 return true 337 } 338 339 func fappend(f *File, cp *Cmd, p Posn) bool { 340 if len(cp.ctext.s) > 0 && cp.ctext.s[len(cp.ctext.s)-1] == 0 { 341 // TODO(rsc): Where did the NUL come from? 342 cp.ctext.s = cp.ctext.s[:len(cp.ctext.s)-1] 343 } 344 if len(cp.ctext.s) > 0 { 345 loginsert(f, p, cp.ctext.s) 346 } 347 f.ndot.r.p1 = p 348 f.ndot.r.p2 = p + len(cp.ctext.s) 349 return true 350 } 351 352 func display(f *File) bool { 353 p1 := addr.r.p1 354 p2 := addr.r.p2 355 if p2 > f.b.nc { 356 fmt.Fprintf(os.Stderr, "bad display addr p1=%d p2=%d f->b.nc=%d\n", p1, p2, f.b.nc) /*ZZZ should never happen, can remove */ 357 p2 = f.b.nc 358 } 359 for p1 < p2 { 360 np := p2 - p1 361 if np > BLOCKSIZE-1 { 362 np = BLOCKSIZE - 1 363 } 364 text := genbuf[:np] 365 bufread(&f.b, p1, text) 366 if downloaded { 367 termwrite(string(text)) 368 } else { 369 Write(os.Stdout, []byte(string(text))) // TODO(rsc) 370 } 371 // free(c) 372 p1 += np 373 } 374 f.dot = addr 375 return true 376 } 377 378 func looper(f *File, cp *Cmd, xy bool) { 379 r := addr.r 380 op := r.p1 381 if xy { 382 op = -1 383 } 384 nest++ 385 compile(cp.re) 386 for p := r.p1; p <= r.p2; { 387 if !execute(f, p, r.p2) { /* no match, but y should still run */ 388 if xy || op > r.p2 { 389 break 390 } 391 f.dot.r.p1 = op 392 f.dot.r.p2 = r.p2 393 p = r.p2 + 1 /* exit next loop */ 394 } else { 395 if sel.p[0].p1 == sel.p[0].p2 { /* empty match? */ 396 if sel.p[0].p1 == op { 397 p++ 398 continue 399 } 400 p = sel.p[0].p2 + 1 401 } else { 402 p = sel.p[0].p2 403 } 404 if xy { 405 f.dot.r = sel.p[0] 406 } else { 407 f.dot.r.p1 = op 408 f.dot.r.p2 = sel.p[0].p1 409 } 410 } 411 op = sel.p[0].p2 412 cmdexec(f, cp.ccmd) 413 compile(cp.re) 414 } 415 nest-- 416 } 417 418 func linelooper(f *File, cp *Cmd) { 419 nest++ 420 r := addr.r 421 var a3 Address 422 a3.f = f 423 a3.r.p2 = r.p1 424 a3.r.p1 = a3.r.p2 425 for p := r.p1; p < r.p2; p = a3.r.p2 { 426 a3.r.p1 = a3.r.p2 427 var a Address 428 var linesel Range 429 /*pjw if(p!=r.p1 || (linesel = lineaddr((Posn)0, a3, 1)).r.p2==p)*/ 430 if p != r.p1 || func() bool { a = lineaddr(Posn(0), a3, 1); linesel = a.r; return linesel.p2 == p }() { 431 a = lineaddr(Posn(1), a3, 1) 432 linesel = a.r 433 } 434 if linesel.p1 >= r.p2 { 435 break 436 } 437 if linesel.p2 >= r.p2 { 438 linesel.p2 = r.p2 439 } 440 if linesel.p2 > linesel.p1 { 441 if linesel.p1 >= a3.r.p2 && linesel.p2 > a3.r.p2 { 442 f.dot.r = linesel 443 cmdexec(f, cp.ccmd) 444 a3.r = linesel 445 continue 446 } 447 } 448 break 449 } 450 nest-- 451 } 452 453 func filelooper(cp *Cmd, XY bool) { 454 tmp38 := Glooping 455 Glooping++ 456 if tmp38 != 0 { 457 error_(EnestXY) 458 } 459 nest++ 460 settempfile() 461 cur := curfile 462 for _, f := range tempfile { 463 if f == cmd { 464 continue 465 } 466 if cp.re == nil || filematch(f, cp.re) == XY { 467 cmdexec(f, cp.ccmd) 468 } 469 } 470 if cur != nil && whichmenu(cur) >= 0 { /* check that cur is still a file */ 471 current(cur) 472 } 473 Glooping-- 474 nest-- 475 }