9fans.net/go@v0.0.7/cmd/sam/rasp.go (about)

     1  package main
     2  
     3  /*
     4   * GROWDATASIZE must be big enough that all errors go out as Hgrowdata's,
     5   * so they will be scrolled into visibility in the ~~sam~~ window (yuck!).
     6   */
     7  const GROWDATASIZE = 50 /* if size is <= this, send data with grow */
     8  
     9  var growpos Posn
    10  var grown Posn
    11  var shrinkpos Posn
    12  var shrunk Posn
    13  
    14  /*
    15   * rasp routines inform the terminal of changes to the file.
    16   *
    17   * a rasp is a list of spans within the file, and an indication
    18   * of whether the terminal knows about the span.
    19   *
    20   * optimize by coalescing multiple updates to the same span
    21   * if it is not known by the terminal.
    22   *
    23   * other possible optimizations: flush terminal's rasp by cut everything,
    24   * insert everything if rasp gets too large.
    25   */
    26  
    27  /*
    28   * only called for initial load of file
    29   */
    30  func raspload(f *File) {
    31  	if f.rasp == nil {
    32  		return
    33  	}
    34  	grown = f.b.nc
    35  	growpos = 0
    36  	if f.b.nc != 0 {
    37  		rgrow(f.rasp, 0, f.b.nc)
    38  	}
    39  	raspdone(f, true)
    40  }
    41  
    42  func raspstart(f *File) {
    43  	if f.rasp == nil {
    44  		return
    45  	}
    46  	grown = 0
    47  	shrunk = 0
    48  	outbuffered = true
    49  }
    50  
    51  func raspdone(f *File, toterm bool) {
    52  	if f.dot.r.p1 > f.b.nc {
    53  		f.dot.r.p1 = f.b.nc
    54  	}
    55  	if f.dot.r.p2 > f.b.nc {
    56  		f.dot.r.p2 = f.b.nc
    57  	}
    58  	if f.mark.p1 > f.b.nc {
    59  		f.mark.p1 = f.b.nc
    60  	}
    61  	if f.mark.p2 > f.b.nc {
    62  		f.mark.p2 = f.b.nc
    63  	}
    64  	if f.rasp == nil {
    65  		return
    66  	}
    67  	if grown != 0 {
    68  		outTsll(Hgrow, f.tag, growpos, grown)
    69  	} else if shrunk != 0 {
    70  		outTsll(Hcut, f.tag, shrinkpos, shrunk)
    71  	}
    72  	if toterm {
    73  		outTs(Hcheck0, f.tag)
    74  	}
    75  	outflush()
    76  	outbuffered = false
    77  	if f == cmd {
    78  		cmdpt += cmdptadv
    79  		cmdptadv = 0
    80  	}
    81  }
    82  
    83  func raspflush(f *File) {
    84  	if grown != 0 {
    85  		outTsll(Hgrow, f.tag, growpos, grown)
    86  		grown = 0
    87  	} else if shrunk != 0 {
    88  		outTsll(Hcut, f.tag, shrinkpos, shrunk)
    89  		shrunk = 0
    90  	}
    91  	outflush()
    92  }
    93  
    94  func raspdelete(f *File, p1 int, p2 int, toterm bool) {
    95  	n := p2 - p1
    96  	if n == 0 {
    97  		return
    98  	}
    99  
   100  	if p2 <= f.dot.r.p1 {
   101  		f.dot.r.p1 -= n
   102  		f.dot.r.p2 -= n
   103  	}
   104  	if p2 <= f.mark.p1 {
   105  		f.mark.p1 -= n
   106  		f.mark.p2 -= n
   107  	}
   108  
   109  	if f.rasp == nil {
   110  		return
   111  	}
   112  
   113  	if f == cmd && p1 < cmdpt {
   114  		if p2 <= cmdpt {
   115  			cmdpt -= n
   116  		} else {
   117  			cmdpt = p1
   118  		}
   119  	}
   120  	if toterm {
   121  		if grown != 0 {
   122  			outTsll(Hgrow, f.tag, growpos, grown)
   123  			grown = 0
   124  		} else if shrunk != 0 && shrinkpos != p1 && shrinkpos != p2 {
   125  			outTsll(Hcut, f.tag, shrinkpos, shrunk)
   126  			shrunk = 0
   127  		}
   128  		if shrunk == 0 || shrinkpos == p2 {
   129  			shrinkpos = p1
   130  		}
   131  		shrunk += n
   132  	}
   133  	rcut(f.rasp, p1, p2)
   134  }
   135  
   136  func raspinsert(f *File, p1 int, buf []rune, toterm bool) {
   137  	n := len(buf)
   138  	if n == 0 {
   139  		return
   140  	}
   141  
   142  	if p1 < f.dot.r.p1 {
   143  		f.dot.r.p1 += n
   144  		f.dot.r.p2 += n
   145  	}
   146  	if p1 < f.mark.p1 {
   147  		f.mark.p1 += n
   148  		f.mark.p2 += n
   149  	}
   150  
   151  	if f.rasp == nil {
   152  		return
   153  	}
   154  	if f == cmd && p1 < cmdpt {
   155  		cmdpt += n
   156  	}
   157  	if toterm {
   158  		if shrunk != 0 {
   159  			outTsll(Hcut, f.tag, shrinkpos, shrunk)
   160  			shrunk = 0
   161  		}
   162  		if n > GROWDATASIZE || !rterm(f.rasp, p1) {
   163  			rgrow(f.rasp, p1, n)
   164  			if grown != 0 && growpos+grown != p1 && growpos != p1 {
   165  				outTsll(Hgrow, f.tag, growpos, grown)
   166  				grown = 0
   167  			}
   168  			if grown == 0 {
   169  				growpos = p1
   170  			}
   171  			grown += n
   172  		} else {
   173  			if grown != 0 {
   174  				outTsll(Hgrow, f.tag, growpos, grown)
   175  				grown = 0
   176  			}
   177  			rgrow(f.rasp, p1, n)
   178  			r := rdata(f.rasp, p1, n)
   179  			if r.p1 != p1 || r.p2 != p1+n {
   180  				panic_("rdata in toterminal")
   181  			}
   182  			outTsllS(Hgrowdata, f.tag, p1, n, tmprstr(buf[:n]))
   183  		}
   184  	} else {
   185  		rgrow(f.rasp, p1, n)
   186  		r := rdata(f.rasp, p1, n)
   187  		if r.p1 != p1 || r.p2 != p1+n {
   188  			panic_("rdata in toterminal")
   189  		}
   190  	}
   191  }
   192  
   193  type PosnList []Posn
   194  
   195  const M = 0x80000000
   196  
   197  func (l *PosnList) T(i int) bool { return (*l)[i]&M != 0 }
   198  func (l *PosnList) L(i int) Posn { return (*l)[i] &^ M }
   199  
   200  func (l *PosnList) ins(i int, n Posn) {
   201  	*l = append(*l, Posn(0))
   202  	copy((*l)[i+1:], (*l)[i:])
   203  	(*l)[i] = n
   204  }
   205  
   206  func (l *PosnList) del(i int) {
   207  	copy((*l)[i:], (*l)[i+1:])
   208  	*l = (*l)[:len(*l)-1]
   209  }
   210  
   211  // #define	(*r)[i]	r->posnptr[i]
   212  // #define	T(i)	((*r)[i]&M)	/* in terminal */
   213  // #define	L(i)	((*r)[i]&~M)	/* length of this piece */
   214  
   215  func rcut(r *PosnList, p1 Posn, p2 Posn) {
   216  	if p1 == p2 {
   217  		panic_("rcut 0")
   218  	}
   219  	p := 0
   220  	i := 0
   221  	for i < len(*r) && p+r.L(i) <= p1 {
   222  		p += r.L(i)
   223  		i++
   224  	}
   225  	if i == len(*r) {
   226  		panic_("rcut 1")
   227  	}
   228  	var x Posn
   229  	if p < p1 { /* chop this piece */
   230  		if p+r.L(i) < p2 {
   231  			x = p1 - p
   232  			p += r.L(i)
   233  		} else {
   234  			x = r.L(i) - (p2 - p1)
   235  			p = p2
   236  		}
   237  		if r.T(i) {
   238  			(*r)[i] = x | M
   239  		} else {
   240  			(*r)[i] = x
   241  		}
   242  		i++
   243  	}
   244  	for i < len(*r) && p+r.L(i) <= p2 {
   245  		p += r.L(i)
   246  		r.del(i)
   247  	}
   248  	if p < p2 {
   249  		if i == len(*r) {
   250  			panic_("rcut 2")
   251  		}
   252  		x = r.L(i) - (p2 - p)
   253  		if r.T(i) {
   254  			(*r)[i] = x | M
   255  		} else {
   256  			(*r)[i] = x
   257  		}
   258  	}
   259  	/* can we merge i and i-1 ? */
   260  	if i > 0 && i < len(*r) && r.T(i-1) == r.T(i) {
   261  		x = r.L(i-1) + r.L(i)
   262  		r.del(i)
   263  		i--
   264  		if r.T(i) {
   265  			(*r)[i] = x | M
   266  		} else {
   267  			(*r)[i] = x
   268  		}
   269  	}
   270  }
   271  
   272  func rgrow(r *PosnList, p1 Posn, n Posn) {
   273  	if n == 0 {
   274  		panic_("rgrow 0")
   275  	}
   276  	p := 0
   277  	i := 0
   278  	for ; i < len(*r) && p+r.L(i) <= p1; func() { p += r.L(i); i++ }() {
   279  	}
   280  	if i == len(*r) { /* stick on end of file */
   281  		if p != p1 {
   282  			panic_("rgrow 1")
   283  		}
   284  		if i > 0 && !r.T(i-1) {
   285  			(*r)[i-1] += n
   286  		} else {
   287  			r.ins(i, n)
   288  		}
   289  	} else if !r.T(i) {
   290  		(*r)[i] += n
   291  	} else if p == p1 && i > 0 && !r.T(i-1) { /* special case; simplifies life */
   292  		(*r)[i-1] += n
   293  	} else if p == p1 {
   294  		r.ins(i, n)
   295  	} else { /* must break piece in terminal */
   296  		r.ins(i+1, (r.L(i)-(p1-p))|M)
   297  		r.ins(i+1, n)
   298  		(*r)[i] = (p1 - p) | M
   299  	}
   300  }
   301  
   302  func rterm(r *PosnList, p1 Posn) bool {
   303  	p := 0
   304  	i := 0
   305  	for ; i < len(*r) && p+r.L(i) <= p1; func() { p += r.L(i); i++ }() {
   306  	}
   307  	if i == len(*r) && (i == 0 || !r.T(i-1)) {
   308  		return false
   309  	}
   310  
   311  	// TODO(rsc): Use of uninitialized or stale data?
   312  	// The original C code does return T(i) even when i == r->nused (len(*r)).
   313  	// Most (all?) of the time, the backing store has capacity (i < r->nalloc).
   314  	// If no entries have been deleted from the rasp, then the spare capacity
   315  	// is zeroed and T(i) returns false.
   316  	// But if entries have been deleted, then the spare capacity may hold
   317  	// a stale entry, and the stale entry may have the M bit set, causing
   318  	// T(i) to return true . This does happen in practice.
   319  	// (On my system, B /etc/passwd followed by B /etc/group triggers
   320  	// the stale true in the second B command.)
   321  	// It is difficult to believe that accessing those stale entries is intended,
   322  	// but the C version has been stable for a long time, so assume it is correct.
   323  	if i == len(*r) {
   324  		if i == cap(*r) {
   325  			// Never initialized, assume C version had extra backing store
   326  			// (which would definitely have been zeroed if it existed).
   327  			return false
   328  		}
   329  		// Read stale (deleted) entry.
   330  		rr := (*r)[:i+1]
   331  		return rr.T(i)
   332  	}
   333  
   334  	return r.T(i)
   335  }
   336  
   337  func rdata(r *PosnList, p1 Posn, n Posn) Range {
   338  	if n == 0 {
   339  		panic_("rdata 0")
   340  	}
   341  	p := 0
   342  	i := 0
   343  	for ; i < len(*r) && p+r.L(i) <= p1; func() { p += r.L(i); i++ }() {
   344  	}
   345  	if i == len(*r) {
   346  		panic_("rdata 1")
   347  	}
   348  	var rg Range
   349  	if r.T(i) {
   350  		n -= r.L(i) - (p1 - p)
   351  		if n <= 0 {
   352  			rg.p2 = p1
   353  			rg.p1 = rg.p2
   354  			return rg
   355  		}
   356  		p += r.L(i)
   357  		i++
   358  		p1 = p
   359  	}
   360  	if r.T(i) || i == len(*r) {
   361  		panic_("rdata 2")
   362  	}
   363  	if p+r.L(i) < p1+n {
   364  		n = r.L(i) - (p1 - p)
   365  	}
   366  	rg.p1 = p1
   367  	rg.p2 = p1 + n
   368  	if p != p1 {
   369  		r.ins(i+1, r.L(i)-(p1-p))
   370  		(*r)[i] = p1 - p
   371  		i++
   372  	}
   373  	if r.L(i) != n {
   374  		r.ins(i+1, r.L(i)-n)
   375  		(*r)[i] = n
   376  	}
   377  	(*r)[i] |= M
   378  	/* now i is set; can we merge? */
   379  	if i < len(*r)-1 && r.T(i+1) {
   380  		n += r.L(i + 1)
   381  		(*r)[i] = n | M
   382  		r.del(i + 1)
   383  	}
   384  	if i > 0 && r.T(i-1) {
   385  		(*r)[i] = (n + r.L(i-1)) | M
   386  		r.del(i - 1)
   387  	}
   388  	return rg
   389  }