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  }