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

     1  // #include "sam.h"
     2  // #include "parse.h"
     3  
     4  package main
     5  
     6  import "fmt"
     7  
     8  var addr Address
     9  var lastpat String
    10  var patset bool
    11  var menu *File
    12  
    13  func address(ap *Addr, a Address, sign int) Address {
    14  	f := a.f
    15  	for {
    16  		var a1, a2 Address
    17  		switch ap.type_ {
    18  		case 'l':
    19  			a = lineaddr(ap.num, a, sign)
    20  
    21  		case '#':
    22  			a = charaddr(ap.num, a, sign)
    23  
    24  		case '.':
    25  			a = f.dot
    26  
    27  		case '$':
    28  			a.r.p2 = f.b.nc
    29  			a.r.p1 = a.r.p2
    30  
    31  		case '\'':
    32  			a.r = f.mark
    33  
    34  		case '?':
    35  			sign = -sign
    36  			if sign == 0 {
    37  				sign = -1
    38  			}
    39  			fallthrough
    40  		case '/':
    41  			start := a.r.p2
    42  			if sign < 0 {
    43  				start = a.r.p1
    44  			}
    45  			nextmatch(f, ap.are, start, sign)
    46  			a.r = sel.p[0]
    47  
    48  		case '"':
    49  			a = matchfile(ap.are).dot
    50  			f = a.f
    51  			if f.unread {
    52  				load(f)
    53  			}
    54  
    55  		case '*':
    56  			a.r.p1 = 0
    57  			a.r.p2 = f.b.nc
    58  			return a
    59  
    60  		case ',',
    61  			';':
    62  			if ap.left != nil {
    63  				a1 = address(ap.left, a, 0)
    64  			} else {
    65  				a1.f = a.f
    66  				a1.r.p2 = 0
    67  				a1.r.p1 = a1.r.p2
    68  			}
    69  			if ap.type_ == ';' {
    70  				f = a1.f
    71  				a = a1
    72  				f.dot = a1
    73  			}
    74  			if ap.next != nil {
    75  				a2 = address(ap.next, a, 0)
    76  			} else {
    77  				a2.f = a.f
    78  				a2.r.p2 = f.b.nc
    79  				a2.r.p1 = a2.r.p2
    80  			}
    81  			if a1.f != a2.f {
    82  				error_(Eorder)
    83  			}
    84  			a.f = a1.f
    85  			a.r.p1 = a1.r.p1
    86  			a.r.p2 = a2.r.p2
    87  			if a.r.p2 < a.r.p1 {
    88  				error_(Eorder)
    89  			}
    90  			return a
    91  
    92  		case '+',
    93  			'-':
    94  			sign = 1
    95  			if ap.type_ == '-' {
    96  				sign = -1
    97  			}
    98  			if ap.next == nil || ap.next.type_ == '+' || ap.next.type_ == '-' {
    99  				a = lineaddr(1, a, sign)
   100  			}
   101  		default:
   102  			panic_("address")
   103  			return a
   104  		}
   105  		ap = ap.next
   106  		if ap == nil { /* assign = */
   107  			break
   108  		}
   109  	}
   110  	return a
   111  }
   112  
   113  func nextmatch(f *File, r *String, p Posn, sign int) {
   114  	compile(r)
   115  	if sign >= 0 {
   116  		if !execute(f, p, INFINITY) {
   117  			error_(Esearch)
   118  		}
   119  		if sel.p[0].p1 == sel.p[0].p2 && sel.p[0].p1 == p {
   120  			p++
   121  			if p > f.b.nc {
   122  				p = 0
   123  			}
   124  			if !execute(f, p, INFINITY) {
   125  				panic_("address")
   126  			}
   127  		}
   128  	} else {
   129  		if !bexecute(f, p) {
   130  			error_(Esearch)
   131  		}
   132  		if sel.p[0].p1 == sel.p[0].p2 && sel.p[0].p2 == p {
   133  			p--
   134  			if p < 0 {
   135  				p = f.b.nc
   136  			}
   137  			if !bexecute(f, p) {
   138  				panic_("address")
   139  			}
   140  		}
   141  	}
   142  }
   143  
   144  func matchfile(r *String) *File {
   145  	var match *File
   146  	for _, f := range file {
   147  		if f == cmd {
   148  			continue
   149  		}
   150  		if filematch(f, r) {
   151  			if match != nil {
   152  				error_(Emanyfiles)
   153  			}
   154  			match = f
   155  		}
   156  	}
   157  	if match == nil {
   158  		error_(Efsearch)
   159  	}
   160  	return match
   161  }
   162  
   163  func filematch(f *File, r *String) bool {
   164  	ch := func(s string, b bool) byte {
   165  		if b {
   166  			return s[1]
   167  		}
   168  		return s[0]
   169  	}
   170  	buf := fmt.Sprintf("%c%c%c %s\n", ch(" '", f.mod), ch("-+", f.rasp != nil), ch(" .", f == curfile), f.name)
   171  	t := tmpcstr(buf)
   172  	Strduplstr(&genstr, t)
   173  	freetmpstr(t)
   174  	/* A little dirty... */
   175  	if menu == nil {
   176  		menu = fileopen()
   177  	}
   178  	bufreset(&menu.b)
   179  	bufinsert(&menu.b, 0, genstr.s)
   180  	compile(r)
   181  	return execute(menu, 0, menu.b.nc)
   182  }
   183  
   184  func charaddr(l Posn, addr Address, sign int) Address {
   185  	if sign == 0 {
   186  		addr.r.p2 = l
   187  		addr.r.p1 = addr.r.p2
   188  	} else if sign < 0 {
   189  		addr.r.p1 -= l
   190  		addr.r.p2 = addr.r.p1
   191  	} else if sign > 0 {
   192  		addr.r.p2 += l
   193  		addr.r.p1 = addr.r.p2
   194  	}
   195  	if addr.r.p1 < 0 || addr.r.p2 > addr.f.b.nc {
   196  		error_(Erange)
   197  	}
   198  	return addr
   199  }
   200  
   201  func lineaddr(l Posn, addr Address, sign int) Address {
   202  	debug("lineaddr")
   203  	f := addr.f
   204  	var a Address
   205  	a.f = f
   206  	if sign >= 0 {
   207  		debug("a1")
   208  		var p Posn
   209  		if l == 0 {
   210  			debug("a2")
   211  			if sign == 0 || addr.r.p2 == 0 {
   212  				a.r.p2 = 0
   213  				a.r.p1 = a.r.p2
   214  				return a
   215  			}
   216  			a.r.p1 = addr.r.p2
   217  			p = addr.r.p2 - 1
   218  		} else {
   219  			debug("a3")
   220  			var n int
   221  			if sign == 0 || addr.r.p2 == 0 {
   222  				p = Posn(0)
   223  				n = 1
   224  			} else {
   225  				p = addr.r.p2 - 1
   226  				if filereadc(f, p) == '\n' {
   227  					n = 1
   228  				}
   229  				p++
   230  			}
   231  			for n < l {
   232  				if p >= f.b.nc {
   233  					error_(Erange)
   234  				}
   235  				tmp3 := p
   236  				p++
   237  				if filereadc(f, tmp3) == '\n' {
   238  					n++
   239  				}
   240  			}
   241  			a.r.p1 = p
   242  		}
   243  		for p < f.b.nc {
   244  			c := filereadc(f, p)
   245  			p++
   246  			if c == '\n' {
   247  				break
   248  			}
   249  		}
   250  		a.r.p2 = p
   251  	} else {
   252  		p := addr.r.p1
   253  		if l == 0 {
   254  			a.r.p2 = addr.r.p1
   255  		} else {
   256  			for n := 0; n < l; { /* always runs once */
   257  				if p == 0 {
   258  					n++
   259  					if n != l {
   260  						error_(Erange)
   261  					}
   262  				} else {
   263  					c := filereadc(f, p-1)
   264  					if c != '\n' || func() bool { n++; return n != l }() {
   265  						p--
   266  					}
   267  				}
   268  			}
   269  			a.r.p2 = p
   270  			if p > 0 {
   271  				p--
   272  			}
   273  		}
   274  		for p > 0 && filereadc(f, p-1) != '\n' { /* lines start after a newline */
   275  			p--
   276  		}
   277  		a.r.p1 = p
   278  	}
   279  	return a
   280  }