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 }