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 }