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

     1  // #include "sam.h"
     2  
     3  /*
     4   * Structure of Undo list:
     5   * 	The Undo structure follows any associated data, so the list
     6   *	can be read backwards: read the structure, then read whatever
     7   *	data is associated (insert string, file name) and precedes it.
     8   *	The structure includes the previous value of the modify bit
     9   *	and a sequence number; successive Undo structures with the
    10   *	same sequence number represent simultaneous changes.
    11   */
    12  
    13  package main
    14  
    15  import (
    16  	"os"
    17  	"reflect"
    18  	"unsafe"
    19  )
    20  
    21  type Undo struct {
    22  	type_ int
    23  	mod   bool
    24  	seq   int
    25  	p0    int
    26  	n     int
    27  }
    28  
    29  type Merge struct {
    30  	f    *File
    31  	seq  int
    32  	p0   int
    33  	n    int
    34  	nbuf int
    35  	buf  [RBUFSIZE]rune
    36  }
    37  
    38  const (
    39  	Maxmerge = 50
    40  	Undosize = int(unsafe.Sizeof(Undo{}) / unsafe.Sizeof(rune(0)))
    41  )
    42  
    43  func undorunes(u *Undo) []rune {
    44  	var r []rune
    45  	h := (*reflect.SliceHeader)(unsafe.Pointer(&r))
    46  	h.Data = uintptr(unsafe.Pointer(u))
    47  	h.Len = Undosize
    48  	h.Cap = Undosize
    49  	return r
    50  }
    51  
    52  var merge Merge
    53  
    54  func fileopen() *File {
    55  	f := new(File)
    56  	f.dot.f = f
    57  	f.ndot.f = f
    58  	f.seq = 0
    59  	f.mod = false
    60  	f.unread = true
    61  	Strinit0(&f.name)
    62  	return f
    63  }
    64  
    65  func fileisdirty(f *File) bool {
    66  	return f.seq != f.cleanseq
    67  }
    68  
    69  func wrinsert(delta *Buffer, seq int, mod bool, p0 int, s []rune) {
    70  	var u Undo
    71  	u.type_ = Insert
    72  	u.mod = mod
    73  	u.seq = seq
    74  	u.p0 = p0
    75  	u.n = len(s)
    76  	bufinsert(delta, delta.nc, s)
    77  	bufinsert(delta, delta.nc, undorunes(&u))
    78  }
    79  
    80  func wrdelete(delta *Buffer, seq int, mod bool, p0 int, p1 int) {
    81  	var u Undo
    82  	u.type_ = Delete
    83  	u.mod = mod
    84  	u.seq = seq
    85  	u.p0 = p0
    86  	u.n = p1 - p0
    87  	bufinsert(delta, delta.nc, undorunes(&u))
    88  }
    89  
    90  func flushmerge() {
    91  	f := merge.f
    92  	if f == nil {
    93  		return
    94  	}
    95  	if merge.seq != f.seq {
    96  		panic_("flushmerge seq mismatch")
    97  	}
    98  	if merge.n != 0 {
    99  		wrdelete(&f.epsilon, f.seq, true, merge.p0, merge.p0+merge.n)
   100  	}
   101  	if merge.nbuf != 0 {
   102  		wrinsert(&f.epsilon, f.seq, true, merge.p0+merge.n, merge.buf[:merge.nbuf])
   103  	}
   104  	merge.f = nil
   105  	merge.n = 0
   106  	merge.nbuf = 0
   107  }
   108  
   109  func mergeextend(f *File, p0 int) {
   110  	mp0n := merge.p0 + merge.n
   111  	if mp0n != p0 {
   112  		bufread(&f.b, mp0n, merge.buf[merge.nbuf:merge.nbuf+p0-mp0n])
   113  		merge.nbuf += p0 - mp0n
   114  		merge.n = p0 - merge.p0
   115  	}
   116  }
   117  
   118  /*
   119   * like fileundelete, but get the data from arguments
   120   */
   121  func loginsert(f *File, p0 int, s []rune) {
   122  	ns := len(s)
   123  	if f.rescuing != 0 {
   124  		return
   125  	}
   126  	if ns == 0 {
   127  		return
   128  	}
   129  	if ns > STRSIZE {
   130  		panic_("loginsert")
   131  	}
   132  	if f.seq < seq {
   133  		filemark(f)
   134  	}
   135  	if p0 < f.hiposn {
   136  		error_(Esequence)
   137  	}
   138  
   139  	if merge.f != f || p0-(merge.p0+merge.n) > Maxmerge || merge.nbuf+((p0+ns)-(merge.p0+merge.n)) >= RBUFSIZE { /* too far */ /* too long */
   140  		flushmerge()
   141  	}
   142  
   143  	if ns >= RBUFSIZE {
   144  		if !(merge.n == 0 && merge.nbuf == 0) || !(merge.f == nil) {
   145  			panic_("loginsert bad merge state")
   146  		}
   147  		wrinsert(&f.epsilon, f.seq, true, p0, s)
   148  	} else {
   149  		if merge.f != f {
   150  			merge.f = f
   151  			merge.p0 = p0
   152  			merge.seq = f.seq
   153  		}
   154  		mergeextend(f, p0)
   155  
   156  		/* append string to merge */
   157  		copy(merge.buf[merge.nbuf:], s)
   158  		merge.nbuf += ns
   159  	}
   160  
   161  	f.hiposn = p0
   162  	if !f.unread && !f.mod {
   163  		state(f, Dirty)
   164  	}
   165  }
   166  
   167  func logdelete(f *File, p0 int, p1 int) {
   168  	if f.rescuing != 0 {
   169  		return
   170  	}
   171  	if p0 == p1 {
   172  		return
   173  	}
   174  	if f.seq < seq {
   175  		filemark(f)
   176  	}
   177  	if p0 < f.hiposn {
   178  		error_(Esequence)
   179  	}
   180  
   181  	if merge.f != f || p0-(merge.p0+merge.n) > Maxmerge || merge.nbuf+(p0-(merge.p0+merge.n)) >= RBUFSIZE { /* too far */ /* too long */
   182  		flushmerge()
   183  		merge.f = f
   184  		merge.p0 = p0
   185  		merge.seq = f.seq
   186  	}
   187  
   188  	mergeextend(f, p0)
   189  
   190  	/* add to deletion */
   191  	merge.n = p1 - merge.p0
   192  
   193  	f.hiposn = p1
   194  	if !f.unread && !f.mod {
   195  		state(f, Dirty)
   196  	}
   197  }
   198  
   199  /*
   200   * like fileunsetname, but get the data from arguments
   201   */
   202  func logsetname(f *File, s *String) {
   203  	if f.rescuing != 0 {
   204  		return
   205  	}
   206  
   207  	if f.unread { /* This is setting initial file name */
   208  		filesetname(f, s)
   209  		return
   210  	}
   211  
   212  	if f.seq < seq {
   213  		filemark(f)
   214  	}
   215  
   216  	/* undo a file name change by restoring old name */
   217  	delta := &f.epsilon
   218  	var u Undo
   219  	u.type_ = Filename
   220  	u.mod = true
   221  	u.seq = f.seq
   222  	u.p0 = 0 /* unused */
   223  	u.n = len(s.s)
   224  	if len(s.s) != 0 {
   225  		bufinsert(delta, delta.nc, s.s)
   226  	}
   227  	bufinsert(delta, delta.nc, undorunes(&u))
   228  	if !f.unread && !f.mod {
   229  		state(f, Dirty)
   230  	}
   231  }
   232  
   233  func fileuninsert(f *File, delta *Buffer, p0 int, ns int) {
   234  	var u Undo
   235  	/* undo an insertion by deleting */
   236  	u.type_ = Delete
   237  	u.mod = f.mod
   238  	u.seq = f.seq
   239  	u.p0 = p0
   240  	u.n = ns
   241  	bufinsert(delta, delta.nc, undorunes(&u))
   242  }
   243  
   244  func fileundelete(f *File, delta *Buffer, p0 int, p1 int) {
   245  	var u Undo
   246  	/* undo a deletion by inserting */
   247  	u.type_ = Insert
   248  	u.mod = f.mod
   249  	u.seq = f.seq
   250  	u.p0 = p0
   251  	u.n = p1 - p0
   252  	buf := fbufalloc()
   253  	var n int
   254  	for i := p0; i < p1; i += n {
   255  		n = p1 - i
   256  		if n > RBUFSIZE {
   257  			n = RBUFSIZE
   258  		}
   259  		bufread(&f.b, i, buf[:n])
   260  		bufinsert(delta, delta.nc, buf[:n])
   261  	}
   262  	fbuffree(buf)
   263  	bufinsert(delta, delta.nc, undorunes(&u))
   264  
   265  }
   266  
   267  func filereadc(f *File, q int) rune {
   268  	if q < 0 || q >= f.b.nc {
   269  		return -1
   270  	}
   271  	var r [1]rune
   272  	bufread(&f.b, q, r[:])
   273  	return r[0]
   274  }
   275  
   276  func filesetname(f *File, s *String) {
   277  	if !f.unread {
   278  		fileunsetname(f, &f.delta)
   279  	}
   280  	Strduplstr(&f.name, s)
   281  	sortname(f)
   282  	f.unread = true
   283  }
   284  
   285  func fileunsetname(f *File, delta *Buffer) {
   286  	var u Undo
   287  	/* undo a file name change by restoring old name */
   288  	u.type_ = Filename
   289  	u.mod = f.mod
   290  	u.seq = f.seq
   291  	u.p0 = 0 /* unused */
   292  	var s String
   293  	Strinit(&s)
   294  	Strduplstr(&s, &f.name)
   295  	fullname(&s)
   296  	u.n = len(s.s)
   297  	if len(s.s) != 0 {
   298  		bufinsert(delta, delta.nc, s.s)
   299  	}
   300  	bufinsert(delta, delta.nc, undorunes(&u))
   301  	Strclose(&s)
   302  }
   303  
   304  func fileunsetdot(f *File, delta *Buffer, dot Range) {
   305  	var u Undo
   306  	u.type_ = Dot
   307  	u.mod = f.mod
   308  	u.seq = f.seq
   309  	u.p0 = dot.p1
   310  	u.n = dot.p2 - dot.p1
   311  	bufinsert(delta, delta.nc, undorunes(&u))
   312  }
   313  
   314  func fileunsetmark(f *File, delta *Buffer, mark Range) {
   315  	var u Undo
   316  	u.type_ = Mark
   317  	u.mod = f.mod
   318  	u.seq = f.seq
   319  	u.p0 = mark.p1
   320  	u.n = mark.p2 - mark.p1
   321  	bufinsert(delta, delta.nc, undorunes(&u))
   322  }
   323  
   324  func fileload(f *File, p0 int, fd *os.File, nulls *bool) int {
   325  	if f.seq > 0 {
   326  		panic_("undo in file.load unimplemented")
   327  	}
   328  	return bufload(&f.b, p0, fd, nulls)
   329  }
   330  
   331  func fileupdate(f *File, notrans, toterm bool) bool {
   332  	if f.rescuing != 0 {
   333  		return false
   334  	}
   335  
   336  	flushmerge()
   337  
   338  	/*
   339  	 * fix the modification bit
   340  	 * subtle point: don't save it away in the log.
   341  	 *
   342  	 * if another change is made, the correct f->mod
   343  	 * state is saved  in the undo log by filemark
   344  	 * when setting the dot and mark.
   345  	 *
   346  	 * if the change is undone, the correct state is
   347  	 * saved from f in the fileun... routines.
   348  	 */
   349  	mod := f.mod
   350  	f.mod = f.prevmod
   351  	if f == cmd {
   352  		notrans = true
   353  	} else {
   354  		fileunsetdot(f, &f.delta, f.prevdot)
   355  		fileunsetmark(f, &f.delta, f.prevmark)
   356  	}
   357  	f.dot = f.ndot
   358  	var p1 int
   359  	var p2 int
   360  	fileundo(f, false, !notrans, &p1, &p2, toterm)
   361  	f.mod = mod
   362  
   363  	if f.delta.nc == 0 {
   364  		f.seq = 0
   365  	}
   366  
   367  	if f == cmd {
   368  		return false
   369  	}
   370  
   371  	if f.mod {
   372  		f.closeok = false
   373  		quitok = false
   374  	} else {
   375  		f.closeok = true
   376  	}
   377  	return true
   378  }
   379  
   380  func prevseq(b *Buffer) int {
   381  	up := b.nc
   382  	if up == 0 {
   383  		return 0
   384  	}
   385  	up -= Undosize
   386  	var u Undo
   387  	bufread(b, up, undorunes(&u))
   388  	return u.seq
   389  }
   390  
   391  func undoseq(f *File, isundo bool) int {
   392  	if isundo {
   393  		return f.seq
   394  	}
   395  
   396  	return prevseq(&f.epsilon)
   397  }
   398  
   399  func fileundo(f *File, isundo, canredo bool, q0p *int, q1p *int, flag bool) {
   400  	var stop int
   401  	var delta *Buffer
   402  	var epsilon *Buffer
   403  	if isundo {
   404  		/* undo; reverse delta onto epsilon, seq decreases */
   405  		delta = &f.delta
   406  		epsilon = &f.epsilon
   407  		stop = f.seq
   408  	} else {
   409  		/* redo; reverse epsilon onto delta, seq increases */
   410  		delta = &f.epsilon
   411  		epsilon = &f.delta
   412  		stop = 0 /* don't know yet */
   413  	}
   414  
   415  	raspstart(f)
   416  	for delta.nc > 0 {
   417  		/* rasp and buffer are in sync; sync with wire if needed */
   418  		if needoutflush() {
   419  			raspflush(f)
   420  		}
   421  		up := delta.nc - Undosize
   422  		var u Undo
   423  		bufread(delta, up, undorunes(&u))
   424  		if isundo {
   425  			if u.seq < stop {
   426  				f.seq = u.seq
   427  				raspdone(f, flag)
   428  				return
   429  			}
   430  		} else {
   431  			if stop == 0 {
   432  				stop = u.seq
   433  			}
   434  			if u.seq > stop {
   435  				raspdone(f, flag)
   436  				return
   437  			}
   438  		}
   439  		switch u.type_ {
   440  		default:
   441  			panic_("undo unknown u.type")
   442  
   443  		case Delete:
   444  			f.seq = u.seq
   445  			if canredo {
   446  				fileundelete(f, epsilon, u.p0, u.p0+u.n)
   447  			}
   448  			f.mod = u.mod
   449  			bufdelete(&f.b, u.p0, u.p0+u.n)
   450  			raspdelete(f, u.p0, u.p0+u.n, flag)
   451  			*q0p = u.p0
   452  			*q1p = u.p0
   453  
   454  		case Insert:
   455  			f.seq = u.seq
   456  			if canredo {
   457  				fileuninsert(f, epsilon, u.p0, u.n)
   458  			}
   459  			f.mod = u.mod
   460  			up -= u.n
   461  			buf := fbufalloc()
   462  			var n int
   463  			for i := 0; i < u.n; i += n {
   464  				n = u.n - i
   465  				if n > RBUFSIZE {
   466  					n = RBUFSIZE
   467  				}
   468  				bufread(delta, up+i, buf[:n])
   469  				bufinsert(&f.b, u.p0+i, buf[:n])
   470  				raspinsert(f, u.p0+i, buf[:n], flag)
   471  			}
   472  			fbuffree(buf)
   473  			*q0p = u.p0
   474  			*q1p = u.p0 + u.n
   475  
   476  		case Filename:
   477  			f.seq = u.seq
   478  			if canredo {
   479  				fileunsetname(f, epsilon)
   480  			}
   481  			f.mod = u.mod
   482  			up -= u.n
   483  
   484  			Strinsure(&f.name, u.n)
   485  			bufread(delta, up, f.name.s)
   486  			fixname(&f.name)
   487  			sortname(f)
   488  		case Dot:
   489  			f.seq = u.seq
   490  			if canredo {
   491  				fileunsetdot(f, epsilon, f.dot.r)
   492  			}
   493  			f.mod = u.mod
   494  			f.dot.r.p1 = u.p0
   495  			f.dot.r.p2 = u.p0 + u.n
   496  		case Mark:
   497  			f.seq = u.seq
   498  			if canredo {
   499  				fileunsetmark(f, epsilon, f.mark)
   500  			}
   501  			f.mod = u.mod
   502  			f.mark.p1 = u.p0
   503  			f.mark.p2 = u.p0 + u.n
   504  		}
   505  		bufdelete(delta, up, delta.nc)
   506  	}
   507  	if isundo {
   508  		f.seq = 0
   509  	}
   510  	raspdone(f, flag)
   511  }
   512  
   513  func filereset(f *File) {
   514  	bufreset(&f.delta)
   515  	bufreset(&f.epsilon)
   516  	f.seq = 0
   517  }
   518  
   519  func fileclose(f *File) {
   520  	Strclose(&f.name)
   521  	bufclose(&f.b)
   522  	bufclose(&f.delta)
   523  	bufclose(&f.epsilon)
   524  	if f.rasp != nil {
   525  		// listfree(f.rasp)
   526  	}
   527  	// free(f)
   528  }
   529  
   530  func filemark(f *File) {
   531  
   532  	if f.unread {
   533  		return
   534  	}
   535  	if f.epsilon.nc != 0 {
   536  		bufdelete(&f.epsilon, 0, f.epsilon.nc)
   537  	}
   538  
   539  	if f != cmd {
   540  		f.prevdot = f.dot.r
   541  		f.prevmark = f.mark
   542  		f.prevseq = f.seq
   543  		f.prevmod = f.mod
   544  	}
   545  
   546  	f.ndot = f.dot
   547  	f.seq = seq
   548  	f.hiposn = 0
   549  }