9fans.net/go@v0.0.7/cmd/acme/internal/addr/addr.go (about) 1 package addr 2 3 import ( 4 "9fans.net/go/cmd/acme/internal/alog" 5 "9fans.net/go/cmd/acme/internal/regx" 6 "9fans.net/go/cmd/acme/internal/runes" 7 ) 8 9 const ( 10 None = '\x00' 11 Fore = '+' 12 Back = '-' 13 ) 14 15 const ( 16 Char = iota 17 Line 18 ) 19 20 // Advance starts at q0 and advances nl lines, 21 // being careful not to walk past the end of the text, 22 // and then nr chars, being careful not to walk past 23 // the end of the current line. 24 // It returns the final position. 25 func Advance(t runes.Text, q0 int, nl int, nr int) int { 26 for nl > 0 && q0 < t.Len() { 27 tmp1 := q0 28 q0++ 29 if t.RuneAt(tmp1) == '\n' { 30 nl-- 31 } 32 } 33 if nl > 0 { 34 return q0 35 } 36 for nr > 0 && q0 < t.Len() && t.RuneAt(q0) != '\n' { 37 q0++ 38 nr-- 39 } 40 return q0 41 } 42 43 func number(showerr bool, t runes.Text, r runes.Range, line int, dir rune, size int, evalp *bool) runes.Range { 44 q0 := r.Pos 45 q1 := r.End 46 if size == Char { 47 if dir == Fore { 48 line = r.End + line 49 } else if dir == Back { 50 if r.Pos == 0 && line > 0 { 51 r.Pos = t.Len() 52 } 53 line = r.Pos - line 54 } 55 if line < 0 || line > t.Len() { 56 goto Rescue 57 } 58 *evalp = true 59 return runes.Rng(line, line) 60 } 61 switch dir { 62 case None: 63 q0 = 0 64 q1 = 0 65 goto Forward 66 case Fore: 67 if q1 > 0 { 68 for q1 < t.Len() && t.RuneAt(q1-1) != '\n' { 69 q1++ 70 } 71 } 72 q0 = q1 73 goto Forward 74 case Back: 75 if q0 < t.Len() { 76 for q0 > 0 && t.RuneAt(q0-1) != '\n' { 77 q0-- 78 } 79 } 80 q1 = q0 81 for line > 0 && q0 > 0 { 82 if t.RuneAt(q0-1) == '\n' { 83 line-- 84 if line >= 0 { 85 q1 = q0 86 } 87 } 88 q0-- 89 } 90 /* :1-1 is :0 = #0, but :1-2 is an error */ 91 if line > 1 { 92 goto Rescue 93 } 94 for q0 > 0 && t.RuneAt(q0-1) != '\n' { 95 q0-- 96 } 97 } 98 Return: 99 *evalp = true 100 return runes.Rng(q0, q1) 101 102 Forward: 103 for line > 0 && q1 < t.Len() { 104 tmp2 := q1 105 q1++ 106 if t.RuneAt(tmp2) == '\n' || q1 == t.Len() { 107 line-- 108 if line > 0 { 109 q0 = q1 110 } 111 } 112 } 113 if line == 1 && q1 == t.Len() { // 6 goes to end of 5-line file 114 goto Return 115 } 116 if line > 0 { 117 goto Rescue 118 } 119 goto Return 120 121 Rescue: 122 if showerr { 123 alog.Printf("address out of range\n") 124 } 125 *evalp = false 126 return r 127 } 128 129 func regexp(showerr bool, t runes.Text, lim runes.Range, r runes.Range, pat []rune, dir rune, foundp *bool) runes.Range { 130 if pat[0] == '\x00' && regx.Null() { 131 if showerr { 132 alog.Printf("no previous regular expression\n") 133 } 134 *foundp = false 135 return r 136 } 137 if pat[0] != 0 && !regx.Compile(pat) { 138 *foundp = false 139 return r 140 } 141 var found bool 142 var sel regx.Ranges 143 if dir == Back { 144 found = regx.MatchBackward(t, r.Pos, &sel) 145 } else { 146 var q int 147 if lim.Pos < 0 { 148 q = runes.Infinity 149 } else { 150 q = lim.End 151 } 152 found = regx.Match(t, nil, r.End, q, &sel) 153 } 154 if !found && showerr { 155 alog.Printf("no match for regexp\n") 156 } 157 *foundp = found 158 return sel.R[0] 159 } 160 161 func Eval(showerr bool, t runes.Text, lim runes.Range, ar runes.Range, a interface{}, q0 int, q1 int, getc func(interface{}, int) rune, evalp *bool, qp *int) runes.Range { 162 r := ar 163 q := q0 164 dir := None 165 size := Line 166 var c rune 167 for q < q1 { 168 prevc := c 169 c = getc(a, q) 170 q++ 171 var nr runes.Range 172 var pat []rune 173 var n int 174 var nc rune 175 switch c { 176 default: 177 *qp = q - 1 178 return r 179 case ';': 180 ar = r 181 fallthrough 182 /* fall through */ 183 case ',': 184 if prevc == 0 { /* lhs defaults to 0 */ 185 r.Pos = 0 186 } 187 if q >= q1 && t != nil /* && t.file != nil */ { /* rhs defaults to $ */ 188 r.End = t.Len() 189 } else { 190 nr = Eval(showerr, t, lim, ar, a, q, q1, getc, evalp, &q) 191 r.End = nr.End 192 } 193 *qp = q 194 return r 195 case '+', '-': 196 if *evalp && (prevc == '+' || prevc == '-') { 197 nc = getc(a, q) 198 if nc != '#' && nc != '/' && nc != '?' { 199 r = number(showerr, t, r, 1, prevc, Line, evalp) /* do previous one */ 200 } 201 } 202 dir = c 203 case '.', 204 '$': 205 if q != q0+1 { 206 *qp = q - 1 207 return r 208 } 209 if *evalp { 210 if c == '.' { 211 r = ar 212 } else { 213 r = runes.Rng(t.Len(), t.Len()) 214 } 215 } 216 if q < q1 { 217 dir = Fore 218 } else { 219 dir = None 220 } 221 case '#': 222 if q == q1 || func() bool { c = getc(a, q); _r := c < '0'; q++; return _r }() || '9' < c { 223 *qp = q - 1 224 return r 225 } 226 size = Char 227 fallthrough 228 /* fall through */ 229 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': 230 n = int(c - '0') 231 for q < q1 { 232 nc = getc(a, q) 233 q++ 234 if nc < '0' || '9' < nc { 235 q-- 236 break 237 } 238 n = n*10 + int(nc-'0') 239 } 240 if *evalp { 241 r = number(showerr, t, r, n, dir, size, evalp) 242 } 243 dir = None 244 size = Line 245 case '?': 246 dir = Back 247 fallthrough 248 /* fall through */ 249 case '/': 250 pat = nil 251 for q < q1 { 252 c = getc(a, q) 253 q++ 254 switch c { 255 case '\n': 256 q-- 257 goto out 258 case '\\': 259 pat = append(pat, c) 260 if q == q1 { 261 goto out 262 } 263 c = getc(a, q) 264 q++ 265 case '/': 266 goto out 267 } 268 pat = append(pat, c) 269 } 270 out: 271 if *evalp { 272 r = regexp(showerr, t, lim, r, pat, dir, evalp) 273 } 274 dir = None 275 size = Line 276 } 277 } 278 if *evalp && dir != None { 279 r = number(showerr, t, r, 1, dir, Line, evalp) /* do previous one */ 280 } 281 *qp = q 282 return r 283 }