func (d *Dispenser) Errf(format string, args ...interface{}) error {
	err := fmt.Errorf(format, args...)
	return fmt.Errorf("%s:%d - Error during parsing: %w", d.File(), d.Line(), err)
}
Errf is like Err, but for formatted error messages
package caddyfile
import (
	"errors"
	"fmt"
	"io"
	"log"
	"strings"
)
type Dispenser struct {
	tokens  []Token
	cursor  int
	nesting int
}
func NewDispenser(tokens []Token) *Dispenser {
	return &Dispenser{
		tokens: tokens,
		cursor: -1,
	}
}
func NewTestDispenser(input string) *Dispenser {
	tokens, err := allTokens("Testfile", []byte(input))
	if err != nil && err != io.EOF {
		log.Fatalf("getting all tokens from input: %v", err)
	}
	return NewDispenser(tokens)
}
func (d *Dispenser) Next() bool {
	if d.cursor < len(d.tokens)-1 {
		d.cursor++
		return true
	}
	return false
}
func (d *Dispenser) Prev() bool {
	if d.cursor > -1 {
		d.cursor--
		return d.cursor > -1
	}
	return false
}
func (d *Dispenser) NextArg() bool {
	if !d.nextOnSameLine() {
		return false
	}
	if d.Val() == "{" {
		d.cursor--
		return false
	}
	return true
}
func (d *Dispenser) nextOnSameLine() bool {
	if d.cursor < 0 {
		d.cursor++
		return true
	}
	if d.cursor >= len(d.tokens) {
		return false
	}
	if d.cursor < len(d.tokens)-1 &&
		d.tokens[d.cursor].File == d.tokens[d.cursor+1].File &&
		d.tokens[d.cursor].Line+d.numLineBreaks(d.cursor) == d.tokens[d.cursor+1].Line {
		d.cursor++
		return true
	}
	return false
}
func (d *Dispenser) NextLine() bool {
	if d.cursor < 0 {
		d.cursor++
		return true
	}
	if d.cursor >= len(d.tokens) {
		return false
	}
	if d.cursor < len(d.tokens)-1 &&
		(d.tokens[d.cursor].File != d.tokens[d.cursor+1].File ||
			d.tokens[d.cursor].Line+d.numLineBreaks(d.cursor) < d.tokens[d.cursor+1].Line) {
		d.cursor++
		return true
	}
	return false
}
func (d *Dispenser) NextBlock(initialNestingLevel int) bool {
	if d.nesting > initialNestingLevel {
		if !d.Next() {
			return false  
		}
		if d.Val() == "}" && !d.nextOnSameLine() {
			d.nesting--
		} else if d.Val() == "{" && !d.nextOnSameLine() {
			d.nesting++
		}
		return d.nesting > initialNestingLevel
	}
	if !d.nextOnSameLine() {  
		return false
	}
	if d.Val() != "{" {
		d.cursor--  
		return false
	}
	d.Next()  
	if d.Val() == "}" {
		return false  
	}
	d.nesting++
	return true
}
func (d *Dispenser) Nesting() int {
	return d.nesting
}
func (d *Dispenser) Val() string {
	if d.cursor < 0 || d.cursor >= len(d.tokens) {
		return ""
	}
	return d.tokens[d.cursor].Text
}
func (d *Dispenser) Line() int {
	if d.cursor < 0 || d.cursor >= len(d.tokens) {
		return 0
	}
	return d.tokens[d.cursor].Line
}
func (d *Dispenser) File() string {
	if d.cursor < 0 || d.cursor >= len(d.tokens) {
		return ""
	}
	return d.tokens[d.cursor].File
}
func (d *Dispenser) Args(targets ...*string) bool {
	for i := 0; i < len(targets); i++ {
		if !d.NextArg() {
			return false
		}
		*targets[i] = d.Val()
	}
	return true
}
func (d *Dispenser) AllArgs(targets ...*string) bool {
	if !d.Args(targets...) {
		return false
	}
	if d.NextArg() {
		d.Prev()
		return false
	}
	return true
}
func (d *Dispenser) RemainingArgs() []string {
	var args []string
	for d.NextArg() {
		args = append(args, d.Val())
	}
	return args
}
func (d *Dispenser) NewFromNextSegment() *Dispenser {
	return NewDispenser(d.NextSegment())
}
func (d *Dispenser) NextSegment() Segment {
	tkns := Segment{d.Token()}
	for d.NextArg() {
		tkns = append(tkns, d.Token())
	}
	var openedBlock bool
	for nesting := d.Nesting(); d.NextBlock(nesting); {
		if !openedBlock {
			d.Prev()
			tkns = append(tkns, d.Token())
			d.Next()
			openedBlock = true
		}
		tkns = append(tkns, d.Token())
	}
	if openedBlock {
		tkns = append(tkns, d.Token())
	}
	return tkns
}
func (d *Dispenser) Token() Token {
	if d.cursor < 0 || d.cursor >= len(d.tokens) {
		return Token{}
	}
	return d.tokens[d.cursor]
}
func (d *Dispenser) Reset() {
	d.cursor = -1
	d.nesting = 0
}
func (d *Dispenser) ArgErr() error {
	if d.Val() == "{" {
		return d.Err("Unexpected token '{', expecting argument")
	}
	return d.Errf("Wrong argument count or unexpected line ending after '%s'", d.Val())
}
func (d *Dispenser) SyntaxErr(expected string) error {
	msg := fmt.Sprintf("%s:%d - Syntax error: Unexpected token '%s', expecting '%s'", d.File(), d.Line(), d.Val(), expected)
	return errors.New(msg)
}
func (d *Dispenser) EOFErr() error {
	return d.Errf("Unexpected EOF")
}
func (d *Dispenser) Err(msg string) error {
	return d.Errf(msg)
}