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  }