pkgsrc-Changes archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

CVS commit: pkgsrc/pkgtools/pkglint



Module Name:    pkgsrc
Committed By:   rillig
Date:           Thu Aug 16 20:41:42 UTC 2018

Modified Files:
        pkgsrc/pkgtools/pkglint: Makefile
        pkgsrc/pkgtools/pkglint/files: alternatives.go alternatives_test.go
            autofix_test.go buildlink3_test.go category.go check_test.go
            distinfo.go distinfo_test.go files.go files_test.go
            licenses_test.go logging.go mkline.go mkline_test.go
            mklinechecker.go mklinechecker_test.go mklines.go mklines_test.go
            mkparser.go mkparser_test.go options.go options_test.go package.go
            package_test.go parser_test.go patches_test.go pkglint.go
            pkglint_test.go pkgsrc.go pkgsrc_test.go plist.go plist_test.go
            shell_test.go shtypes_test.go substcontext.go substcontext_test.go
            tools.go tools_test.go toplevel.go util.go util_test.go vardefs.go
            vardefs_test.go vartype.go vartypecheck.go vartypecheck_test.go
        pkgsrc/pkgtools/pkglint/files/regex: regex.go

Log Message:
pkgtools/pkglint: update to 5.6.1

Changes since 5.6.0:

* Fix output of relative paths in the diagnostics (thanks @wiz)
* Fix parsing of ${VAR:ts---}; it is now a syntax error
* Load more type definitions from mk/* instead of hard-coding them
* Lots of refactoring to improve test coverage, fixing several
  small bugs as they were found


To generate a diff of this commit:
cvs rdiff -u -r1.546 -r1.547 pkgsrc/pkgtools/pkglint/Makefile
cvs rdiff -u -r1.3 -r1.4 pkgsrc/pkgtools/pkglint/files/alternatives.go \
    pkgsrc/pkgtools/pkglint/files/shtypes_test.go
cvs rdiff -u -r1.2 -r1.3 pkgsrc/pkgtools/pkglint/files/alternatives_test.go \
    pkgsrc/pkgtools/pkglint/files/options.go \
    pkgsrc/pkgtools/pkglint/files/options_test.go \
    pkgsrc/pkgtools/pkglint/files/tools.go \
    pkgsrc/pkgtools/pkglint/files/tools_test.go
cvs rdiff -u -r1.8 -r1.9 pkgsrc/pkgtools/pkglint/files/autofix_test.go
cvs rdiff -u -r1.15 -r1.16 pkgsrc/pkgtools/pkglint/files/buildlink3_test.go \
    pkgsrc/pkgtools/pkglint/files/distinfo_test.go \
    pkgsrc/pkgtools/pkglint/files/files_test.go
cvs rdiff -u -r1.13 -r1.14 pkgsrc/pkgtools/pkglint/files/category.go \
    pkgsrc/pkgtools/pkglint/files/licenses_test.go
cvs rdiff -u -r1.23 -r1.24 pkgsrc/pkgtools/pkglint/files/check_test.go \
    pkgsrc/pkgtools/pkglint/files/plist_test.go
cvs rdiff -u -r1.21 -r1.22 pkgsrc/pkgtools/pkglint/files/distinfo.go
cvs rdiff -u -r1.17 -r1.18 pkgsrc/pkgtools/pkglint/files/files.go
cvs rdiff -u -r1.12 -r1.13 pkgsrc/pkgtools/pkglint/files/logging.go \
    pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go \
    pkgsrc/pkgtools/pkglint/files/mkparser_test.go \
    pkgsrc/pkgtools/pkglint/files/substcontext_test.go \
    pkgsrc/pkgtools/pkglint/files/toplevel.go
cvs rdiff -u -r1.35 -r1.36 pkgsrc/pkgtools/pkglint/files/mkline.go \
    pkgsrc/pkgtools/pkglint/files/pkglint.go
cvs rdiff -u -r1.39 -r1.40 pkgsrc/pkgtools/pkglint/files/mkline_test.go
cvs rdiff -u -r1.16 -r1.17 pkgsrc/pkgtools/pkglint/files/mklinechecker.go
cvs rdiff -u -r1.29 -r1.30 pkgsrc/pkgtools/pkglint/files/mklines.go \
    pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go
cvs rdiff -u -r1.25 -r1.26 pkgsrc/pkgtools/pkglint/files/mklines_test.go
cvs rdiff -u -r1.14 -r1.15 pkgsrc/pkgtools/pkglint/files/mkparser.go \
    pkgsrc/pkgtools/pkglint/files/vartype.go
cvs rdiff -u -r1.33 -r1.34 pkgsrc/pkgtools/pkglint/files/package.go
cvs rdiff -u -r1.27 -r1.28 pkgsrc/pkgtools/pkglint/files/package_test.go
cvs rdiff -u -r1.7 -r1.8 pkgsrc/pkgtools/pkglint/files/parser_test.go \
    pkgsrc/pkgtools/pkglint/files/pkgsrc.go
cvs rdiff -u -r1.18 -r1.19 pkgsrc/pkgtools/pkglint/files/patches_test.go
cvs rdiff -u -r1.22 -r1.23 pkgsrc/pkgtools/pkglint/files/pkglint_test.go
cvs rdiff -u -r1.5 -r1.6 pkgsrc/pkgtools/pkglint/files/pkgsrc_test.go
cvs rdiff -u -r1.26 -r1.27 pkgsrc/pkgtools/pkglint/files/plist.go \
    pkgsrc/pkgtools/pkglint/files/util.go
cvs rdiff -u -r1.28 -r1.29 pkgsrc/pkgtools/pkglint/files/shell_test.go
cvs rdiff -u -r1.11 -r1.12 pkgsrc/pkgtools/pkglint/files/substcontext.go \
    pkgsrc/pkgtools/pkglint/files/util_test.go
cvs rdiff -u -r1.43 -r1.44 pkgsrc/pkgtools/pkglint/files/vardefs.go
cvs rdiff -u -r1.1 -r1.2 pkgsrc/pkgtools/pkglint/files/vardefs_test.go
cvs rdiff -u -r1.37 -r1.38 pkgsrc/pkgtools/pkglint/files/vartypecheck.go
cvs rdiff -u -r1.2 -r1.3 pkgsrc/pkgtools/pkglint/files/regex/regex.go

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: pkgsrc/pkgtools/pkglint/Makefile
diff -u pkgsrc/pkgtools/pkglint/Makefile:1.546 pkgsrc/pkgtools/pkglint/Makefile:1.547
--- pkgsrc/pkgtools/pkglint/Makefile:1.546      Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/Makefile    Thu Aug 16 20:41:42 2018
@@ -1,6 +1,6 @@
-# $NetBSD: Makefile,v 1.546 2018/08/12 16:31:56 rillig Exp $
+# $NetBSD: Makefile,v 1.547 2018/08/16 20:41:42 rillig Exp $
 
-PKGNAME=       pkglint-5.6.0
+PKGNAME=       pkglint-5.6.1
 DISTFILES=     # none
 CATEGORIES=    pkgtools
 

Index: pkgsrc/pkgtools/pkglint/files/alternatives.go
diff -u pkgsrc/pkgtools/pkglint/files/alternatives.go:1.3 pkgsrc/pkgtools/pkglint/files/alternatives.go:1.4
--- pkgsrc/pkgtools/pkglint/files/alternatives.go:1.3   Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/alternatives.go       Thu Aug 16 20:41:42 2018
@@ -6,8 +6,8 @@ import (
 )
 
 func CheckfileAlternatives(filename string, plistFiles map[string]bool) {
-       lines, err := readLines(filename, false)
-       if err != nil {
+       lines := Load(filename, NotEmpty|LogErrors)
+       if lines == nil {
                return
        }
 
Index: pkgsrc/pkgtools/pkglint/files/shtypes_test.go
diff -u pkgsrc/pkgtools/pkglint/files/shtypes_test.go:1.3 pkgsrc/pkgtools/pkglint/files/shtypes_test.go:1.4
--- pkgsrc/pkgtools/pkglint/files/shtypes_test.go:1.3   Sat Apr 28 23:32:52 2018
+++ pkgsrc/pkgtools/pkglint/files/shtypes_test.go       Thu Aug 16 20:41:42 2018
@@ -32,3 +32,10 @@ func (s *Suite) Test_ShAtom_String(c *ch
 func (s *Suite) Test_ShQuoting_String(c *check.C) {
        c.Check(shqDquotBacktSquot.String(), equals, "dbs")
 }
+
+func (s *Suite) Test_ShToken_String(c *check.C) {
+       tokenizer := NewShTokenizer(dummyLine, "${ECHO} \"hello, world\"", false)
+
+       c.Check(tokenizer.ShToken().String(), equals, "ShToken([varuse(\"ECHO\")])")
+       c.Check(tokenizer.ShToken().String(), equals, "ShToken([ShAtom(word, \"\\\"\", d) ShAtom(word, \"hello, world\", d) \"\\\"\"])")
+}

Index: pkgsrc/pkgtools/pkglint/files/alternatives_test.go
diff -u pkgsrc/pkgtools/pkglint/files/alternatives_test.go:1.2 pkgsrc/pkgtools/pkglint/files/alternatives_test.go:1.3
--- pkgsrc/pkgtools/pkglint/files/alternatives_test.go:1.2      Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/alternatives_test.go  Thu Aug 16 20:41:42 2018
@@ -5,23 +5,24 @@ import "gopkg.in/check.v1"
 func (s *Suite) Test_Alternatives_PLIST(c *check.C) {
        t := s.Init(c)
 
+       t.Chdir("category/package")
        t.SetupFileLines("ALTERNATIVES",
                "sbin/sendmail @PREFIX@/sbin/sendmail.postfix@POSTFIXVER@",
                "sbin/sendmail @PREFIX@/sbin/sendmail.exim@EXIMVER@",
                "bin/echo bin/gnu-echo",
                "bin/editor bin/vim -e")
 
-       G.Pkg = NewPackage("")
+       G.Pkg = NewPackage(".")
        G.Pkg.PlistFiles["bin/echo"] = true
        G.Pkg.PlistFiles["bin/vim"] = true
        G.Pkg.PlistFiles["sbin/sendmail.exim${EXIMVER}"] = true
 
-       CheckfileAlternatives(t.File("ALTERNATIVES"), G.Pkg.PlistFiles)
+       CheckfileAlternatives("ALTERNATIVES", G.Pkg.PlistFiles)
 
        t.CheckOutputLines(
-               "ERROR: ~/ALTERNATIVES:1: Alternative implementation \"@PREFIX@/sbin/sendmail.postfix@POSTFIXVER@\" must appear in the PLIST as \"sbin/sendmail.postfix${POSTFIXVER}\".",
-               "NOTE: ~/ALTERNATIVES:1: @PREFIX@/ can be omitted from the file name.",
-               "NOTE: ~/ALTERNATIVES:2: @PREFIX@/ can be omitted from the file name.",
-               "ERROR: ~/ALTERNATIVES:3: Alternative wrapper \"bin/echo\" must not appear in the PLIST.",
-               "ERROR: ~/ALTERNATIVES:3: Alternative implementation \"bin/gnu-echo\" must appear in the PLIST.")
+               "ERROR: ALTERNATIVES:1: Alternative implementation \"@PREFIX@/sbin/sendmail.postfix@POSTFIXVER@\" must appear in the PLIST as \"sbin/sendmail.postfix${POSTFIXVER}\".",
+               "NOTE: ALTERNATIVES:1: @PREFIX@/ can be omitted from the file name.",
+               "NOTE: ALTERNATIVES:2: @PREFIX@/ can be omitted from the file name.",
+               "ERROR: ALTERNATIVES:3: Alternative wrapper \"bin/echo\" must not appear in the PLIST.",
+               "ERROR: ALTERNATIVES:3: Alternative implementation \"bin/gnu-echo\" must appear in the PLIST.")
 }
Index: pkgsrc/pkgtools/pkglint/files/options.go
diff -u pkgsrc/pkgtools/pkglint/files/options.go:1.2 pkgsrc/pkgtools/pkglint/files/options.go:1.3
--- pkgsrc/pkgtools/pkglint/files/options.go:1.2        Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/options.go    Thu Aug 16 20:41:42 2018
@@ -45,7 +45,7 @@ loop:
                                }
                        }
 
-               case mkline.IsCond():
+               case mkline.IsDirective():
                        // The conditionals are typically for OPSYS and MACHINE_ARCH.
 
                case mkline.IsInclude():
@@ -74,7 +74,7 @@ loop:
 
        for ; !exp.EOF(); exp.Advance() {
                mkline := exp.CurrentMkLine()
-               if mkline.IsCond() && (mkline.Directive() == "if" || mkline.Directive() == "elif") {
+               if mkline.IsDirective() && (mkline.Directive() == "if" || mkline.Directive() == "elif") {
                        cond := NewMkParser(mkline.Line, mkline.Args(), false).MkCond()
                        if cond == nil {
                                continue
Index: pkgsrc/pkgtools/pkglint/files/options_test.go
diff -u pkgsrc/pkgtools/pkglint/files/options_test.go:1.2 pkgsrc/pkgtools/pkglint/files/options_test.go:1.3
--- pkgsrc/pkgtools/pkglint/files/options_test.go:1.2   Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/options_test.go       Thu Aug 16 20:41:42 2018
@@ -87,7 +87,7 @@ func (s *Suite) Test_ChecklinesOptionsMk
                "WARN: ~/category/package/options.mk:7: Expected inclusion of \"../../mk/bsd.options.mk\".")
 }
 
-func (s *Suite) Test_ChecklinesOptionsMk__malformed_conditional(c *check.C) {
+func (s *Suite) Test_ChecklinesOptionsMk__malformed_condition(c *check.C) {
        t := s.Init(c)
 
        t.SetupCommandLine("-Wno-space")
@@ -115,5 +115,5 @@ func (s *Suite) Test_ChecklinesOptionsMk
        ChecklinesOptionsMk(mklines)
 
        t.CheckOutputLines(
-               "WARN: ~/category/package/options.mk:9: Invalid conditional \"${OPSYS} == 'Darwin'\".")
+               "WARN: ~/category/package/options.mk:9: Invalid condition, unrecognized part: \"${OPSYS} == 'Darwin'\".")
 }
Index: pkgsrc/pkgtools/pkglint/files/tools.go
diff -u pkgsrc/pkgtools/pkglint/files/tools.go:1.2 pkgsrc/pkgtools/pkglint/files/tools.go:1.3
--- pkgsrc/pkgtools/pkglint/files/tools.go:1.2  Sat Apr 28 23:32:52 2018
+++ pkgsrc/pkgtools/pkglint/files/tools.go      Thu Aug 16 20:41:42 2018
@@ -6,13 +6,17 @@ import (
        "strings"
 )
 
+// Tool is one of the many standard shell utilities that are typically
+// provided by the operating system, or, if missing, are installed via
+// pkgsrc.
+//
 // See `mk/tools/`.
 type Tool struct {
        Name             string // e.g. "sed", "gzip"
        Varname          string // e.g. "SED", "GZIP_CMD"
        MustUseVarForm   bool   // True for `echo`, because of many differing implementations.
        Predefined       bool   // This tool is used by the pkgsrc infrastructure, therefore the package does not need to add it to `USE_TOOLS` explicitly.
-       UsableAtLoadtime bool   // May be used after including `bsd.prefs.mk`.
+       UsableAtLoadTime bool   // May be used after including `bsd.prefs.mk`.
 }
 
 type ToolRegistry struct {
@@ -28,9 +32,9 @@ func NewToolRegistry() ToolRegistry {
 // The tool may then be used by this name (e.g. "awk"),
 // but not by a corresponding variable (e.g. ${AWK}).
 // The toolname may include the scope (:pkgsrc, :run, etc.).
-func (tr *ToolRegistry) Register(toolname string, line Line) *Tool {
+func (tr *ToolRegistry) Register(toolname string, mkline MkLine) *Tool {
        name := strings.SplitN(toolname, ":", 2)[0]
-       tr.validateToolName(name, line)
+       tr.validateToolName(name, mkline)
 
        tool := tr.byName[name]
        if tool == nil {
@@ -40,15 +44,15 @@ func (tr *ToolRegistry) Register(toolnam
        return tool
 }
 
-func (tr *ToolRegistry) RegisterVarname(toolname, varname string, line Line) *Tool {
-       tool := tr.Register(toolname, line)
+func (tr *ToolRegistry) RegisterVarname(toolname, varname string, mkline MkLine) *Tool {
+       tool := tr.Register(toolname, mkline)
        tool.Varname = varname
        tr.byVarname[varname] = tool
        return tool
 }
 
-func (tr *ToolRegistry) RegisterTool(tool *Tool, line Line) {
-       tr.validateToolName(tool.Name, line)
+func (tr *ToolRegistry) RegisterTool(tool *Tool, mkline MkLine) {
+       tr.validateToolName(tool.Name, mkline)
 
        if tool.Name != "" && tr.byName[tool.Name] == nil {
                tr.byName[tool.Name] = tool
@@ -90,24 +94,23 @@ func (tr *ToolRegistry) Trace() {
 
 // ParseToolLine parses a tool definition from the pkgsrc infrastructure,
 // e.g. in mk/tools/replace.mk.
-func (tr *ToolRegistry) ParseToolLine(line Line) {
-       if m, commented, varname, _, _, _, value, _, _ := MatchVarassign(line.Text); m {
-               if commented {
-                       return
-               }
+func (tr *ToolRegistry) ParseToolLine(mkline MkLine) {
+       if mkline.IsVarassign() {
+               varname := mkline.Varname()
+               value := mkline.Value()
                if varname == "TOOLS_CREATE" && (value == "[" || matches(value, `^?[-\w.]+$`)) {
-                       tr.Register(value, line)
+                       tr.Register(value, mkline)
 
                } else if m, toolname := match1(varname, `^_TOOLS_VARNAME\.([-\w.]+|\[)$`); m {
-                       tr.RegisterVarname(toolname, value, line)
+                       tr.RegisterVarname(toolname, value, mkline)
 
-               } else if m, toolname := match1(varname, `^(?:TOOLS_PATH|_TOOLS_DEPMETHOD)\.([-\w.]+|\[)$`); m {
-                       tr.Register(toolname, line)
+               } else if m, toolname = match1(varname, `^(?:TOOLS_PATH|_TOOLS_DEPMETHOD)\.([-\w.]+|\[)$`); m {
+                       tr.Register(toolname, mkline)
 
-               } else if m, toolname := match1(varname, `^_TOOLS\.(.*)`); m {
-                       tr.Register(toolname, line)
+               } else if m, toolname = match1(varname, `^_TOOLS\.(.*)`); m {
+                       tr.Register(toolname, mkline)
                        for _, tool := range splitOnSpace(value) {
-                               tr.Register(tool, line)
+                               tr.Register(tool, mkline)
                        }
                }
        }
@@ -127,8 +130,8 @@ func (tr *ToolRegistry) ForEach(action f
        }
 }
 
-func (tr *ToolRegistry) validateToolName(toolName string, line Line) {
+func (tr *ToolRegistry) validateToolName(toolName string, mkline MkLine) {
        if toolName != "echo -n" && !matches(toolName, `^([-a-z0-9.]+|\[)$`) {
-               line.Errorf("Invalid tool name %q", toolName)
+               mkline.Errorf("Invalid tool name %q.", toolName)
        }
 }
Index: pkgsrc/pkgtools/pkglint/files/tools_test.go
diff -u pkgsrc/pkgtools/pkglint/files/tools_test.go:1.2 pkgsrc/pkgtools/pkglint/files/tools_test.go:1.3
--- pkgsrc/pkgtools/pkglint/files/tools_test.go:1.2     Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/tools_test.go Thu Aug 16 20:41:42 2018
@@ -17,3 +17,16 @@ func (s *Suite) Test_ToolRegistry_ParseT
        // No error about "Unknown tool \"NetBSD\"."
        t.CheckOutputEmpty()
 }
+
+func (s *Suite) Test_ToolRegistry_validateToolName__invalid(c *check.C) {
+       t := s.Init(c)
+
+       reg := NewToolRegistry()
+
+       reg.Register("tool_name", dummyMkLine)
+
+       // Currently, the underscore is not used in any tool name.
+       // If there should ever be such a case, just use a different character.
+       t.CheckOutputLines(
+               "ERROR: Invalid tool name \"tool_name\".")
+}

Index: pkgsrc/pkgtools/pkglint/files/autofix_test.go
diff -u pkgsrc/pkgtools/pkglint/files/autofix_test.go:1.8 pkgsrc/pkgtools/pkglint/files/autofix_test.go:1.9
--- pkgsrc/pkgtools/pkglint/files/autofix_test.go:1.8   Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/autofix_test.go       Thu Aug 16 20:41:42 2018
@@ -117,7 +117,7 @@ func (s *Suite) Test_autofix_MkLines(c *
                "line1 := value1",
                "line2 := value2",
                "line3 := value3")
-       pkg := NewPackage("category/basename")
+       pkg := NewPackage(t.File("category/basename"))
        G.Pkg = pkg
        mklines := pkg.loadPackageMakefile()
        G.Pkg = nil
@@ -259,7 +259,7 @@ func (s *Suite) Test_Autofix_show_source
        t.SetupCommandLine("--show-autofix", "--source")
        mklines := t.SetupFileMkLines("Makefile",
                MkRcsID,
-               "before \\",
+               "# before \\",
                "The old song \\",
                "after")
        line := mklines.lines[1]
@@ -274,7 +274,7 @@ func (s *Suite) Test_Autofix_show_source
        t.CheckOutputLines(
                "WARN: ~/Makefile:2--4: Using \"old\" is deprecated.",
                "AUTOFIX: ~/Makefile:3: Replacing \"old\" with \"new\".",
-               ">\tbefore \\",
+               ">\t# before \\",
                "-\tThe old song \\",
                "+\tThe new song \\",
                ">\tafter")

Index: pkgsrc/pkgtools/pkglint/files/buildlink3_test.go
diff -u pkgsrc/pkgtools/pkglint/files/buildlink3_test.go:1.15 pkgsrc/pkgtools/pkglint/files/buildlink3_test.go:1.16
--- pkgsrc/pkgtools/pkglint/files/buildlink3_test.go:1.15       Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/buildlink3_test.go    Thu Aug 16 20:41:42 2018
@@ -41,7 +41,7 @@ func (s *Suite) Test_ChecklinesBuildlink
        t := s.Init(c)
 
        t.SetupVartypes()
-       G.Pkg = NewPackage("x11/hs-X11")
+       G.Pkg = NewPackage(t.File("x11/hs-X11"))
        G.Pkg.EffectivePkgbase = "X11"
        G.Pkg.EffectivePkgnameLine = t.NewMkLine("Makefile", 3, "DISTNAME=\tX11-1.0")
        mklines := t.NewMkLines("buildlink3.mk",
Index: pkgsrc/pkgtools/pkglint/files/distinfo_test.go
diff -u pkgsrc/pkgtools/pkglint/files/distinfo_test.go:1.15 pkgsrc/pkgtools/pkglint/files/distinfo_test.go:1.16
--- pkgsrc/pkgtools/pkglint/files/distinfo_test.go:1.15 Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/distinfo_test.go      Thu Aug 16 20:41:42 2018
@@ -5,28 +5,33 @@ import "gopkg.in/check.v1"
 func (s *Suite) Test_ChecklinesDistinfo(c *check.C) {
        t := s.Init(c)
 
-       t.SetupFileLines("category/package/patches/patch-aa",
-               "$"+"NetBSD$ line is ignored",
+       t.Chdir("category/package")
+       t.SetupFileLines("patches/patch-aa",
+               RcsID+" line is ignored for computing the SHA1 hash",
                "patch contents")
-       t.SetupFileLines("category/package/patches/patch-ab",
+       t.SetupFileLines("patches/patch-ab",
                "patch contents")
-       lines := t.SetupFileLines("category/package/distinfo",
+       lines := t.SetupFileLines("distinfo",
                "should be the RCS ID",
                "should be empty",
                "MD5 (distfile.tar.gz) = 12345678901234567890123456789012",
                "SHA1 (distfile.tar.gz) = 1234567890123456789012345678901234567890",
                "SHA1 (patch-aa) = 6b98dd609f85a9eb9c4c1e4e7055a6aaa62b7cc7",
+               "Size (patch-aa) = 104",
                "SHA1 (patch-ab) = 6b98dd609f85a9eb9c4c1e4e7055a6aaa62b7cc7",
+               "Another invalid line",
                "SHA1 (patch-nonexistent) = 1234")
-       G.Pkg = NewPackage("category/package")
+       G.Pkg = NewPackage(".")
 
        ChecklinesDistinfo(lines)
 
        t.CheckOutputLines(
-               "ERROR: ~/category/package/distinfo:1: Expected \"$"+"NetBSD$\".",
-               "NOTE: ~/category/package/distinfo:2: Empty line expected.",
-               "ERROR: ~/category/package/distinfo:5: Expected SHA1, RMD160, SHA512, Size checksums for \"distfile.tar.gz\", got MD5, SHA1.",
-               "WARN: ~/category/package/distinfo:7: Patch file \"patch-nonexistent\" does not exist in directory \"patches\".")
+               "ERROR: distinfo:1: Expected \"$"+"NetBSD$\".",
+               "NOTE: distinfo:2: Empty line expected.",
+               "ERROR: distinfo:5: Expected SHA1, RMD160, SHA512, Size checksums for \"distfile.tar.gz\", got MD5, SHA1.",
+               "ERROR: distinfo:7: Expected SHA1 hash for patch-aa, got SHA1, Size.",
+               "ERROR: distinfo:8: Invalid line.",
+               "WARN: distinfo:9: Patch file \"patch-nonexistent\" does not exist in directory \"patches\".")
 }
 
 func (s *Suite) Test_ChecklinesDistinfo_global_hash_mismatch(c *check.C) {
@@ -49,7 +54,8 @@ func (s *Suite) Test_ChecklinesDistinfo_
 func (s *Suite) Test_ChecklinesDistinfo_uncommitted_patch(c *check.C) {
        t := s.Init(c)
 
-       t.SetupFileLines("category/package/patches/patch-aa",
+       t.Chdir("category/package")
+       t.SetupFileLines("patches/patch-aa",
                RcsID,
                "",
                "--- oldfile",
@@ -57,45 +63,47 @@ func (s *Suite) Test_ChecklinesDistinfo_
                "@@ -1,1 +1,1 @@",
                "-old",
                "+new")
-       t.SetupFileLines("category/package/CVS/Entries",
+       t.SetupFileLines("CVS/Entries",
                "/distinfo/...")
-       lines := t.SetupFileLines("category/package/distinfo",
+       lines := t.SetupFileLines("distinfo",
                RcsID,
                "",
                "SHA1 (patch-aa) = 5ad1fb9b3c328fff5caa1a23e8f330e707dd50c0")
-       G.Pkg = NewPackage("category/package")
+       G.Pkg = NewPackage(".")
 
        ChecklinesDistinfo(lines)
 
        t.CheckOutputLines(
-               "WARN: ~/category/package/distinfo:3: patches/patch-aa is registered in distinfo but not added to CVS.")
+               "WARN: distinfo:3: patches/patch-aa is registered in distinfo but not added to CVS.")
 }
 
 func (s *Suite) Test_ChecklinesDistinfo_unrecorded_patches(c *check.C) {
        t := s.Init(c)
 
-       t.SetupFileLines("category/package/patches/CVS/Entries")
-       t.SetupFileLines("category/package/patches/patch-aa")
-       t.SetupFileLines("category/package/patches/patch-src-Makefile")
-       lines := t.SetupFileLines("category/package/distinfo",
+       t.Chdir("category/package")
+       t.SetupFileLines("patches/CVS/Entries")
+       t.SetupFileLines("patches/patch-aa")
+       t.SetupFileLines("patches/patch-src-Makefile")
+       lines := t.SetupFileLines("distinfo",
                RcsID,
                "",
                "SHA1 (distfile.tar.gz) = ...",
                "RMD160 (distfile.tar.gz) = ...",
                "SHA512 (distfile.tar.gz) = ...",
                "Size (distfile.tar.gz) = 1024 bytes")
-       G.Pkg = NewPackage("category/package")
+       G.Pkg = NewPackage(".")
 
        ChecklinesDistinfo(lines)
 
        t.CheckOutputLines(
-               "ERROR: ~/category/package/distinfo: patch \"patches/patch-aa\" is not recorded. Run \""+confMake+" makepatchsum\".",
-               "ERROR: ~/category/package/distinfo: patch \"patches/patch-src-Makefile\" is not recorded. Run \""+confMake+" makepatchsum\".")
+               "ERROR: distinfo: patch \"patches/patch-aa\" is not recorded. Run \""+confMake+" makepatchsum\".",
+               "ERROR: distinfo: patch \"patches/patch-src-Makefile\" is not recorded. Run \""+confMake+" makepatchsum\".")
 }
 
 func (s *Suite) Test_ChecklinesDistinfo_manual_patches(c *check.C) {
        t := s.Init(c)
 
+       t.Chdir("category/package")
        t.CreateFileLines("patches/manual-libtool.m4")
        lines := t.SetupFileLines("distinfo",
                RcsID,
@@ -115,7 +123,7 @@ func (s *Suite) Test_ChecklinesDistinfo_
        // When a distinfo file is checked in the context of a package,
        // the PATCHDIR is known, therefore the checks are active.
        t.CheckOutputLines(
-               "WARN: ~/distinfo:3: Patch file \"patch-aa\" does not exist in directory \"patches\".")
+               "WARN: distinfo:3: Patch file \"patch-aa\" does not exist in directory \"patches\".")
 }
 
 // PHP modules that are not PECL use the distinfo file from lang/php* but
Index: pkgsrc/pkgtools/pkglint/files/files_test.go
diff -u pkgsrc/pkgtools/pkglint/files/files_test.go:1.15 pkgsrc/pkgtools/pkglint/files/files_test.go:1.16
--- pkgsrc/pkgtools/pkglint/files/files_test.go:1.15    Thu Aug  9 20:08:12 2018
+++ pkgsrc/pkgtools/pkglint/files/files_test.go Thu Aug 16 20:41:42 2018
@@ -150,3 +150,23 @@ func (s *Suite) Test_splitRawLine(c *che
        c.Check(trailingWhitespace, equals, "   ")
        c.Check(continuation, equals, "\\")
 }
+
+func (s *Suite) Test_Load(c *check.C) {
+       t := s.Init(c)
+
+       t.CreateFileLines("empty")
+
+       func() {
+               defer t.ExpectFatalError()
+               Load(t.File("does-not-exist"), MustSucceed)
+       }()
+
+       func() {
+               defer t.ExpectFatalError()
+               Load(t.File("empty"), MustSucceed|NotEmpty)
+       }()
+
+       t.CheckOutputLines(
+               "FATAL: ~/does-not-exist: Cannot be read.",
+               "FATAL: ~/empty: Must not be empty.")
+}

Index: pkgsrc/pkgtools/pkglint/files/category.go
diff -u pkgsrc/pkgtools/pkglint/files/category.go:1.13 pkgsrc/pkgtools/pkglint/files/category.go:1.14
--- pkgsrc/pkgtools/pkglint/files/category.go:1.13      Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/category.go   Thu Aug 16 20:41:42 2018
@@ -10,12 +10,11 @@ func CheckdirCategory(dir string) {
                defer trace.Call1(dir)()
        }
 
-       lines := LoadNonemptyLines(dir+"/Makefile", true)
-       if lines == nil {
+       mklines := LoadMk(dir+"/Makefile", NotEmpty|LogErrors)
+       if mklines == nil {
                return
        }
 
-       mklines := NewMkLines(lines)
        mklines.Check()
 
        exp := NewMkExpecter(mklines)
@@ -164,7 +163,7 @@ func CheckdirCategory(dir string) {
                exp.CurrentLine().Errorf("The file should end here.")
        }
 
-       SaveAutofixChanges(lines)
+       mklines.SaveAutofixChanges()
 
        if G.opts.Recursive {
                G.Todo = append(append([]string(nil), subdirs...), G.Todo...)
Index: pkgsrc/pkgtools/pkglint/files/licenses_test.go
diff -u pkgsrc/pkgtools/pkglint/files/licenses_test.go:1.13 pkgsrc/pkgtools/pkglint/files/licenses_test.go:1.14
--- pkgsrc/pkgtools/pkglint/files/licenses_test.go:1.13 Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/licenses_test.go      Thu Aug 16 20:41:42 2018
@@ -47,16 +47,7 @@ func (s *Suite) Test_checklineLicense(c 
 func (s *Suite) Test_checkToplevelUnusedLicenses(c *check.C) {
        t := s.Init(c)
 
-       t.SetupFileLines("mk/bsd.pkg.mk", "# dummy")
-       t.SetupFileLines("mk/fetch/sites.mk", "# dummy")
-       t.SetupFileLines("mk/defaults/options.description", "option\tdescription")
-       t.SetupFileLines("doc/TODO")
-       t.SetupFileLines("mk/defaults/mk.conf")
-       t.SetupFileLines("mk/tools/bsd.tools.mk",
-               ".include \"actual-tools.mk\"")
-       t.SetupFileLines("mk/tools/actual-tools.mk")
-       t.SetupFileLines("mk/tools/defaults.mk")
-       t.SetupFileLines("mk/bsd.prefs.mk")
+       t.SetupPkgsrc()
        t.SetupFileLines("mk/misc/category.mk")
        t.SetupFileLines("licenses/2-clause-bsd")
        t.SetupFileLines("licenses/gnu-gpl-v3")
@@ -90,3 +81,36 @@ func (s *Suite) Test_checkToplevelUnused
                "WARN: ~/licenses/gnu-gpl-v3: This license seems to be unused.",
                "0 errors and 1 warning found.")
 }
+
+func (s *Suite) Test_LicenseChecker_checkLicenseName__LICENSE_FILE(c *check.C) {
+       t := s.Init(c)
+
+       t.SetupPkgsrc()
+       t.SetupCommandLine("-Wno-space")
+       t.SetupFileLines("category/package/DESCR",
+               "Package description")
+       t.SetupFileMkLines("category/package/Makefile",
+               MkRcsID,
+               "",
+               "CATEGORIES=     chinese",
+               "",
+               "COMMENT=        Useful tools",
+               "LICENSE=        my-license",
+               "",
+               "LICENSE_FILE=   my-license",
+               "NO_CHECKSUM=    yes",
+               "",
+               ".include \"../../mk/bsd.pkg.mk\"")
+       t.SetupFileLines("category/package/PLIST",
+               PlistRcsID,
+               "bin/program")
+       t.SetupFileLines("category/package/my-license",
+               "An individual license file.")
+
+       G.Main("pkglint", t.File("category/package"))
+
+       // FIXME: It should be allowed to place a license file directly into
+       // the package directory.
+       t.CheckOutputLines(
+               "WARN: ~/category/package/my-license: Unexpected file found.", "0 errors and 1 warning found.")
+}

Index: pkgsrc/pkgtools/pkglint/files/check_test.go
diff -u pkgsrc/pkgtools/pkglint/files/check_test.go:1.23 pkgsrc/pkgtools/pkglint/files/check_test.go:1.24
--- pkgsrc/pkgtools/pkglint/files/check_test.go:1.23    Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/check_test.go Thu Aug 16 20:41:42 2018
@@ -58,12 +58,23 @@ func (s *Suite) SetUpTest(c *check.C) {
        t.checkC = nil
 
        G.opts.LogVerbose = true // To detect duplicate work being done
+       t.EnableSilentTracing()
+
+       prevdir, err := os.Getwd()
+       if err != nil {
+               c.Fatalf("Cannot get current working directory: %s", err)
+       }
+       t.prevdir = prevdir
 }
 
 func (s *Suite) TearDownTest(c *check.C) {
        t := s.Tester
        t.checkC = nil // No longer usable; see https://github.com/go-check/check/issues/22
 
+       if err := os.Chdir(t.prevdir); err != nil {
+               fmt.Fprintf(os.Stderr, "Cannot chdir back to previous dir: %s", err)
+       }
+
        G = Pkglint{} // unusable because of missing logOut and logErr
        textproc.Testing = false
        if out := t.Output(); out != "" {
@@ -71,6 +82,7 @@ func (s *Suite) TearDownTest(c *check.C)
                        c.TestName(), strings.Split(out, "\n"))
        }
        t.tmpdir = ""
+       t.DisableTracing()
 }
 
 var _ = check.Suite(new(Suite))
@@ -82,10 +94,12 @@ func Test(t *testing.T) { check.TestingT
 // all the test methods, which makes it difficult to find
 // a method by auto-completion.
 type Tester struct {
-       stdout bytes.Buffer
-       stderr bytes.Buffer
-       tmpdir string
-       checkC *check.C
+       stdout  bytes.Buffer
+       stderr  bytes.Buffer
+       tmpdir  string
+       checkC  *check.C // Only usable during the test method itself
+       prevdir string   // The current working directory before the test started
+       relcwd  string
 }
 
 func (t *Tester) c() *check.C {
@@ -98,6 +112,11 @@ func (t *Tester) c() *check.C {
 // SetupCommandLine simulates a command line for the remainder of the test.
 // See Pkglint.ParseCommandLine.
 func (t *Tester) SetupCommandLine(args ...string) {
+
+       // Prevent tracing from being disabled; see EnableSilentTracing.
+       prevTracing := trace.Tracing
+       defer func() { trace.Tracing = prevTracing }()
+
        exitcode := G.ParseCommandLine(append([]string{"pkglint"}, args...))
        if exitcode != nil && *exitcode != 0 {
                t.CheckOutputEmpty()
@@ -149,15 +168,14 @@ func (t *Tester) SetupTool(tool *Tool) {
 // The file is then read in, without considering line continuations.
 func (t *Tester) SetupFileLines(relativeFilename string, lines ...string) []Line {
        filename := t.CreateFileLines(relativeFilename, lines...)
-       return LoadExistingLines(filename, false)
+       return Load(filename, MustSucceed)
 }
 
 // SetupFileLines creates a temporary file and writes the given lines to it.
 // The file is then read in, handling line continuations for Makefiles.
 func (t *Tester) SetupFileMkLines(relativeFilename string, lines ...string) *MkLines {
        filename := t.CreateFileLines(relativeFilename, lines...)
-       plainLines := LoadExistingLines(filename, true)
-       return NewMkLines(plainLines)
+       return LoadMk(filename, MustSucceed)
 }
 
 // SetupPkgsrc sets up a minimal but complete pkgsrc installation in the
@@ -222,21 +240,62 @@ func (t *Tester) CreateFileLines(relativ
 
 // File returns the absolute path to the given file in the
 // temporary directory. It doesn't check whether that file exists.
+// Calls to Tester.Chdir change the base directory for the relative file name.
 func (t *Tester) File(relativeFilename string) string {
        if t.tmpdir == "" {
                t.tmpdir = filepath.ToSlash(t.c().MkDir())
        }
-       return t.tmpdir + "/" + relativeFilename
+       if t.relcwd != "" {
+               return cleanpath(relativeFilename)
+       }
+       return cleanpath(t.tmpdir + "/" + relativeFilename)
 }
 
-// ExpectFatalError, when run in a defer statement, runs the action
-// if the current function panics with a pkglintFatal
-// (typically from line.Fatalf).
-func (t *Tester) ExpectFatalError(action func()) {
+// Chdir changes the current working directory to the given subdirectory
+// of the temporary directory, creating it if necessary.
+//
+// After this call, all files loaded from the temporary directory via
+// SetupFileLines or CreateFileLines or similar methods will use path names
+// relative to this directory.
+//
+// After the test, the previous working directory is restored, so that
+// the other tests are unaffected.
+//
+// As long as this method is not called in a test, the current working
+// directory is indeterminate.
+func (t *Tester) Chdir(relativeFilename string) {
+       if t.relcwd != "" {
+               // When multiple calls of Chdir are mixed with calls to CreateFileLines,
+               // the resulting []Line and MkLines variables will use relative file names,
+               // and these will point to different areas in the file system. This is
+               // usually not indented and therefore prevented.
+               t.checkC.Fatalf("Chdir must only be called once per test; already in %q.", t.relcwd)
+       }
+
+       _ = os.MkdirAll(t.File(relativeFilename), 0700)
+       if err := os.Chdir(t.File(relativeFilename)); err != nil {
+               t.checkC.Fatalf("Cannot chdir: %s", err)
+       }
+       t.relcwd = relativeFilename
+}
+
+// ExpectFatalError promises that in the remainder of the current function
+// call, a panic with a pkglintFatal will occur (typically from Line.Fatalf).
+//
+// Usage:
+//     func() {
+//      defer t.ExpectFatalError()
+//
+//      // The code that causes the fatal error.
+//      Load(t.File("nonexistent"), MustSucceed)
+//  }()
+//  t.CheckOutputLines(
+//      "FATAL: ~/nonexistent: Does not exist.")
+func (t *Tester) ExpectFatalError() {
        r := recover()
-       if _, ok := r.(pkglintFatal); ok {
-               action()
-       } else {
+       if r == nil {
+               panic("Expected a pkglint fatal error, but didn't get one.")
+       } else if _, ok := r.(pkglintFatal); !ok {
                panic(r)
        }
 }
@@ -344,12 +403,28 @@ func (t *Tester) EnableTracing() {
        trace.Tracing = true
 }
 
+// EnableTracingToLog enables the tracing and writes the tracing output
+// to the test log that can be examined with Tester.Output.
+func (t *Tester) EnableTracingToLog() {
+       G.logOut = NewSeparatorWriter(io.MultiWriter(os.Stdout, &t.stdout))
+       trace.Out = &t.stdout
+       trace.Tracing = true
+}
+
+// EnableSilentTracing enables tracing mode, but discards any tracing output.
+// This can be used to improve code coverage without any side-effects,
+// since tracing output is quite large.
+func (t *Tester) EnableSilentTracing() {
+       trace.Out = ioutil.Discard
+       trace.Tracing = true
+}
+
 // DisableTracing logs the output to the buffers again, ready to be
 // checked with CheckOutputLines.
 func (t *Tester) DisableTracing() {
        G.logOut = NewSeparatorWriter(&t.stdout)
-       trace.Out = &t.stdout
        trace.Tracing = false
+       trace.Out = nil
 }
 
 // CheckFileLines loads the lines from the temporary file and checks that
@@ -368,10 +443,7 @@ func (t *Tester) CheckFileLines(relative
 // for indentation, while the lines in the code use spaces exclusively,
 // in order to make the depth of the indentation clearly visible.
 func (t *Tester) CheckFileLinesDetab(relativeFileName string, lines ...string) {
-       actualLines, err := readLines(t.File(relativeFileName), false)
-       if !t.c().Check(err, check.IsNil) {
-               return
-       }
+       actualLines := Load(t.File(relativeFileName), MustSucceed)
 
        var detabbed []string
        for _, line := range actualLines {
Index: pkgsrc/pkgtools/pkglint/files/plist_test.go
diff -u pkgsrc/pkgtools/pkglint/files/plist_test.go:1.23 pkgsrc/pkgtools/pkglint/files/plist_test.go:1.24
--- pkgsrc/pkgtools/pkglint/files/plist_test.go:1.23    Sat Mar 24 14:32:49 2018
+++ pkgsrc/pkgtools/pkglint/files/plist_test.go Thu Aug 16 20:41:42 2018
@@ -6,7 +6,7 @@ func (s *Suite) Test_ChecklinesPlist(c *
        t := s.Init(c)
 
        t.SetupCommandLine("-Wall")
-       G.Pkg = NewPackage("category/pkgbase")
+       G.Pkg = NewPackage(t.File("category/pkgbase"))
        lines := t.NewLines("PLIST",
                "bin/i386/6c",
                "bin/program",
@@ -76,10 +76,10 @@ func (s *Suite) Test_ChecklinesPlist__co
        t.CheckOutputEmpty()
 }
 
-func (s *Suite) Test_ChecklinesPlist__conditional(c *check.C) {
+func (s *Suite) Test_ChecklinesPlist__condition(c *check.C) {
        t := s.Init(c)
 
-       G.Pkg = NewPackage("category/pkgbase")
+       G.Pkg = NewPackage(t.File("category/pkgbase"))
        G.Pkg.plistSubstCond["PLIST.bincmds"] = true
        lines := t.NewLines("PLIST",
                PlistRcsID,
@@ -101,7 +101,7 @@ func (s *Suite) Test_ChecklinesPlist__so
                "sbin/i386/6c",
                "sbin/program",
                "bin/otherprogram",
-               "${PLIST.conditional}bin/cat")
+               "${PLIST.condition}bin/cat")
 
        ChecklinesPlist(lines)
 
@@ -129,7 +129,7 @@ func (s *Suite) Test_PlistLineSorter_Sor
                "man/man1/program.1",
                "${PLIST.two}bin/program2",
                "lib/before.la",
-               "${PLIST.linux}${PLIST.x86_64}lib/lib-linux-x86_64.so", // Double conditional, see graphics/graphviz
+               "${PLIST.linux}${PLIST.x86_64}lib/lib-linux-x86_64.so", // Double condition, see graphics/graphviz
                "lib/after.la",
                "@exec echo \"after lib/after.la\"")
        ck := &PlistChecker{nil, nil, "", Once{}}
@@ -155,7 +155,7 @@ func (s *Suite) Test_PlistLineSorter_Sor
                "C",
                "CCC",
                "b",
-               "${PLIST.one}bin/program", // Conditionals are ignored while sorting
+               "${PLIST.one}bin/program", // Conditional lines are ignored during sorting
                "${PLIST.two}bin/program2",
                "ddd",
                "lib/after.la",
@@ -169,7 +169,7 @@ func (s *Suite) Test_PlistLineSorter_Sor
 func (s *Suite) Test_PlistChecker_checkpathMan_gz(c *check.C) {
        t := s.Init(c)
 
-       G.Pkg = NewPackage("category/pkgbase")
+       G.Pkg = NewPackage(t.File("category/pkgbase"))
        lines := t.NewLines("PLIST",
                PlistRcsID,
                "man/man3/strerror.3.gz")
@@ -211,7 +211,7 @@ func (s *Suite) Test_PlistChecker__autof
 
        t.SetupCommandLine("-Wall")
 
-       fname := t.CreateFileLines("PLIST",
+       lines := t.SetupFileLines("PLIST",
                PlistRcsID,
                "lib/libvirt/connection-driver/libvirt_driver_storage.la",
                "${PLIST.hal}lib/libvirt/connection-driver/libvirt_driver_nodedev.la",
@@ -232,7 +232,7 @@ func (s *Suite) Test_PlistChecker__autof
                "@pkgdir        etc/libvirt/qemu/networks/autostart",
                "@pkgdir        etc/logrotate.d",
                "@pkgdir        etc/sasl2")
-       lines := LoadExistingLines(fname, false)
+
        ChecklinesPlist(lines)
 
        t.CheckOutputLines(
@@ -245,12 +245,9 @@ func (s *Suite) Test_PlistChecker__autof
        t.SetupCommandLine("-Wall", "--autofix")
        ChecklinesPlist(lines)
 
-       fixedLines := LoadExistingLines(fname, false)
-
        t.CheckOutputLines(
                "AUTOFIX: ~/PLIST:6: Replacing \"${PKGMANDIR}/\" with \"man/\".",
                "AUTOFIX: ~/PLIST:2: Sorting the whole file.")
-       c.Check(len(lines), equals, len(fixedLines))
        t.CheckFileLines("PLIST",
                PlistRcsID,
                "${PLIST.xen}lib/libvirt/connection-driver/libvirt_driver_libxl.la",
@@ -274,9 +271,9 @@ func (s *Suite) Test_PlistChecker__autof
                "@pkgdir        etc/sasl2")
 }
 
-// When the same entry appears both with and without a conditional,
-// the one with the conditional can be removed.
-// When the same entry appears with several different conditionals,
+// When the same entry appears both with and without a condition,
+// the one with the condition can be removed.
+// When the same entry appears with several different conditions,
 // all of them must stay.
 func (s *Suite) Test_PlistChecker__remove_same_entries(c *check.C) {
        t := s.Init(c)

Index: pkgsrc/pkgtools/pkglint/files/distinfo.go
diff -u pkgsrc/pkgtools/pkglint/files/distinfo.go:1.21 pkgsrc/pkgtools/pkglint/files/distinfo.go:1.22
--- pkgsrc/pkgtools/pkglint/files/distinfo.go:1.21      Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/distinfo.go   Thu Aug 16 20:41:42 2018
@@ -68,7 +68,7 @@ func (ck *distinfoLinesChecker) checkLin
                ck.algorithms = append(ck.algorithms, alg)
 
                ck.checkGlobalMismatch(line, filename, alg, hash)
-               ck.checkUncommittedPatch(line, filename, hash)
+               ck.checkUncommittedPatch(line, filename, alg, hash)
        }
        ck.onFilenameChange(NewLineEOF(ck.distinfoFilename), "")
 }
@@ -149,13 +149,15 @@ func (ck *distinfoLinesChecker) checkGlo
        }
 }
 
-func (ck *distinfoLinesChecker) checkUncommittedPatch(line Line, patchName, sha1Hash string) {
+func (ck *distinfoLinesChecker) checkUncommittedPatch(line Line, patchName, alg, hash string) {
        if ck.isPatch == yes {
                patchFname := ck.patchdir + "/" + patchName
                if ck.distinfoIsCommitted && !isCommitted(G.Pkg.File(patchFname)) {
                        line.Warnf("%s is registered in distinfo but not added to CVS.", patchFname)
                }
-               ck.checkPatchSha1(line, patchFname, sha1Hash)
+               if alg == "SHA1" {
+                       ck.checkPatchSha1(line, patchFname, hash)
+               }
                ck.patches[patchName] = true
        }
 }
@@ -194,7 +196,7 @@ func computePatchSha1Hex(patchFilename s
 
 func AutofixDistinfo(oldSha1, newSha1 string) {
        distinfoFilename := G.Pkg.File(G.Pkg.DistinfoFile)
-       if lines, err := readLines(distinfoFilename, false); err == nil {
+       if lines := Load(distinfoFilename, NotEmpty|LogErrors); lines != nil {
                for _, line := range lines {
                        fix := line.Autofix()
                        fix.Warnf("Silent-Magic-Diagnostic")

Index: pkgsrc/pkgtools/pkglint/files/files.go
diff -u pkgsrc/pkgtools/pkglint/files/files.go:1.17 pkgsrc/pkgtools/pkglint/files/files.go:1.18
--- pkgsrc/pkgtools/pkglint/files/files.go:1.17 Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/files.go      Thu Aug 16 20:41:42 2018
@@ -6,29 +6,51 @@ import (
        "strings"
 )
 
-// LoadNonemptyLines loads the given file.
-// If the file doesn't exist or is empty, an error is logged.
-//
-// See [LoadExistingLines].
-func LoadNonemptyLines(fname string, joinBackslashLines bool) []Line {
-       lines, err := readLines(fname, joinBackslashLines)
+type LoadOptions uint8
+
+const (
+       MustSucceed LoadOptions = 1 << iota // It's a fatal error if loading fails.
+       NotEmpty                            // It is an error if the file is empty.
+       Makefile                            // Lines ending in a backslash are continued in the next line.
+       LogErrors                           //
+)
+
+func Load(fileName string, options LoadOptions) []Line {
+       rawBytes, err := ioutil.ReadFile(fileName)
        if err != nil {
-               NewLineWhole(fname).Errorf("Cannot be read.")
+               switch {
+               case options&MustSucceed != 0:
+                       NewLineWhole(fileName).Fatalf("Cannot be read.")
+               case options&LogErrors != 0:
+                       NewLineWhole(fileName).Errorf("Cannot be read.")
+               }
                return nil
        }
-       if len(lines) == 0 {
-               NewLineWhole(fname).Errorf("Must not be empty.")
+
+       rawText := string(rawBytes)
+       if rawText == "" && options&NotEmpty != 0 {
+               switch {
+               case options&MustSucceed != 0:
+                       NewLineWhole(fileName).Fatalf("Must not be empty.")
+               case options&LogErrors != 0:
+                       NewLineWhole(fileName).Errorf("Must not be empty.")
+               }
                return nil
        }
-       return lines
+
+       if G.opts.Profiling {
+               G.loaded.Add(path.Clean(fileName), 1)
+       }
+
+       return convertToLogicalLines(fileName, rawText, options&Makefile != 0)
 }
 
-func LoadExistingLines(fname string, joinBackslashLines bool) []Line {
-       lines, err := readLines(fname, joinBackslashLines)
-       if err != nil {
-               NewLineWhole(fname).Fatalf("Cannot be read.")
+func LoadMk(fileName string, options LoadOptions) *MkLines {
+       lines := Load(fileName, options|Makefile)
+       if lines == nil {
+               return nil
        }
-       return lines
+       return NewMkLines(lines)
 }
 
 func nextLogicalLine(fname string, rawLines []*RawLine, pindex *int) Line {
@@ -106,18 +128,6 @@ func splitRawLine(textnl string) (leadin
        return
 }
 
-func readLines(fname string, joinBackslashLines bool) ([]Line, error) {
-       rawText, err := ioutil.ReadFile(fname)
-       if err != nil {
-               return nil, err
-       }
-
-       if G.opts.Profiling {
-               G.loaded.Add(path.Clean(fname), 1)
-       }
-       return convertToLogicalLines(fname, string(rawText), joinBackslashLines), nil
-}
-
 func convertToLogicalLines(fname string, rawText string, joinBackslashLines bool) []Line {
        var rawLines []*RawLine
        for lineno, rawLine := range strings.SplitAfter(rawText, "\n") {

Index: pkgsrc/pkgtools/pkglint/files/logging.go
diff -u pkgsrc/pkgtools/pkglint/files/logging.go:1.12 pkgsrc/pkgtools/pkglint/files/logging.go:1.13
--- pkgsrc/pkgtools/pkglint/files/logging.go:1.12       Thu Jul 12 16:23:36 2018
+++ pkgsrc/pkgtools/pkglint/files/logging.go    Thu Aug 16 20:41:42 2018
@@ -21,6 +21,7 @@ var (
 )
 
 var dummyLine = NewLine("", 0, "", nil)
+var dummyMkLine = NewMkLine(dummyLine)
 
 func shallBeLogged(msg string) bool {
        if len(G.opts.LogOnly) > 0 {
@@ -57,7 +58,7 @@ func logs(level *LogLevel, fname, lineno
                fname = cleanpath(fname)
        }
        if G.Testing && format != "Magic-Autofix-Format" && !hasSuffix(format, ".") && !hasSuffix(format, ": %s") && !hasSuffix(format, ". %s") {
-               panic(fmt.Sprintf("Format %q must end in a period.", format))
+               panic(fmt.Sprintf("Diagnostic format %q must end in a period.", format))
        }
 
        if !G.opts.LogVerbose && loggedAlready(fname, lineno, msg) {
Index: pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go:1.12 pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go:1.13
--- pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go:1.12    Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go Thu Aug 16 20:41:42 2018
@@ -42,7 +42,7 @@ func (s *Suite) Test_MkLineChecker_Check
 func (s *Suite) Test_MkLineChecker_checkVarassign__URL_with_shell_special_characters(c *check.C) {
        t := s.Init(c)
 
-       G.Pkg = NewPackage("graphics/gimp-fix-ca")
+       G.Pkg = NewPackage(t.File("graphics/gimp-fix-ca"))
        t.SetupVartypes()
        mkline := t.NewMkLine("fname", 10, "MASTER_SITES=http://registry.gimp.org/file/fix-ca.c?action=download&id=9884&file=";)
 
@@ -57,37 +57,37 @@ func (s *Suite) Test_MkLineChecker_Check
        t.SetupCommandLine("-Wtypes")
        t.SetupVartypes()
 
-       MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(PKGSRC_COMPILER:Mmycc)")}.CheckCond()
+       MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(PKGSRC_COMPILER:Mmycc)")}.checkDirectiveCond()
 
        t.CheckOutputLines(
                "WARN: fname:1: The pattern \"mycc\" cannot match any of " +
                        "{ ccache ccc clang distcc f2c gcc hp icc ido " +
                        "mipspro mipspro-ucode pcc sunpro xlc } for PKGSRC_COMPILER.")
 
-       MkLineChecker{t.NewMkLine("fname", 1, ".elif ${A} != ${B}")}.CheckCond()
+       MkLineChecker{t.NewMkLine("fname", 1, ".elif ${A} != ${B}")}.checkDirectiveCond()
 
        t.CheckOutputEmpty()
 
-       MkLineChecker{t.NewMkLine("fname", 1, ".if ${HOMEPAGE} == \"mailto:someone%example.org@localhost\"";)}.CheckCond()
+       MkLineChecker{t.NewMkLine("fname", 1, ".if ${HOMEPAGE} == \"mailto:someone%example.org@localhost\"";)}.checkDirectiveCond()
 
        t.CheckOutputLines(
                "WARN: fname:1: \"mailto:someone%example.org@localhost\"; is not a valid URL.")
 
-       MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(PKGSRC_RUN_TEST:M[Y][eE][sS])")}.CheckCond()
+       MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(PKGSRC_RUN_TEST:M[Y][eE][sS])")}.checkDirectiveCond()
 
        t.CheckOutputLines(
                "WARN: fname:1: PKGSRC_RUN_TEST should be matched against \"[yY][eE][sS]\" or \"[nN][oO]\", not \"[Y][eE][sS]\".")
 
-       MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(IS_BUILTIN.Xfixes:M[yY][eE][sS])")}.CheckCond()
+       MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(IS_BUILTIN.Xfixes:M[yY][eE][sS])")}.checkDirectiveCond()
 
        t.CheckOutputEmpty()
 
-       MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(${IS_BUILTIN.Xfixes:M[yY][eE][sS]})")}.CheckCond()
+       MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(${IS_BUILTIN.Xfixes:M[yY][eE][sS]})")}.checkDirectiveCond()
 
        t.CheckOutputLines(
                "WARN: fname:1: The empty() function takes a variable name as parameter, not a variable expression.")
 
-       MkLineChecker{t.NewMkLine("fname", 1, ".if ${EMUL_PLATFORM} == \"linux-x386\"")}.CheckCond()
+       MkLineChecker{t.NewMkLine("fname", 1, ".if ${EMUL_PLATFORM} == \"linux-x386\"")}.checkDirectiveCond()
 
        t.CheckOutputLines(
                "WARN: fname:1: " +
@@ -100,7 +100,7 @@ func (s *Suite) Test_MkLineChecker_Check
                        "mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 " +
                        "} instead.")
 
-       MkLineChecker{t.NewMkLine("fname", 1, ".if ${EMUL_PLATFORM:Mlinux-x386}")}.CheckCond()
+       MkLineChecker{t.NewMkLine("fname", 1, ".if ${EMUL_PLATFORM:Mlinux-x386}")}.checkDirectiveCond()
 
        t.CheckOutputLines(
                "WARN: fname:1: "+
@@ -113,7 +113,7 @@ func (s *Suite) Test_MkLineChecker_Check
                        "for the hardware architecture part of EMUL_PLATFORM.",
                "NOTE: fname:1: EMUL_PLATFORM should be compared using == instead of the :M or :N modifier without wildcards.")
 
-       MkLineChecker{t.NewMkLine("fname", 98, ".if ${MACHINE_PLATFORM:MUnknownOS-*-*} || ${MACHINE_ARCH:Mx86}")}.CheckCond()
+       MkLineChecker{t.NewMkLine("fname", 98, ".if ${MACHINE_PLATFORM:MUnknownOS-*-*} || ${MACHINE_ARCH:Mx86}")}.checkDirectiveCond()
 
        t.CheckOutputLines(
                "WARN: fname:98: "+
Index: pkgsrc/pkgtools/pkglint/files/mkparser_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mkparser_test.go:1.12 pkgsrc/pkgtools/pkglint/files/mkparser_test.go:1.13
--- pkgsrc/pkgtools/pkglint/files/mkparser_test.go:1.12 Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/mkparser_test.go      Thu Aug 16 20:41:42 2018
@@ -110,6 +110,10 @@ func (s *Suite) Test_MkParser_MkTokens(c
        check("${VAR:ts\\000012}", varuse("VAR", "ts\\000012")) // The separator character can be a long octal number.
        check("${VAR:ts\\124}", varuse("VAR", "ts\\124"))       // Or even decimal.
 
+       checkRest("${VAR:ts---}", nil, "${VAR:ts---}") // The :ts modifier only takes single-character separators.
+
+       check("$<", varuseText("$<", "<")) // Same as ${.IMPSRC}
+
        check("$(GNUSTEP_USER_ROOT)", varuseText("$(GNUSTEP_USER_ROOT)", "GNUSTEP_USER_ROOT"))
        t.CheckOutputLines(
                "WARN: Test_MkParser_MkTokens.mk:1: Please use curly braces {} instead of round parentheses () for GNUSTEP_USER_ROOT.")
@@ -222,6 +226,15 @@ func (s *Suite) Test_MkParser_MkCond(c *
        checkRest("!empty(PKG_OPTIONS:Msndfile) || defined(PKG_OPTIONS:Msamplerate)",
                &mkCond{Not: &mkCond{Empty: varuse("PKG_OPTIONS", "Msndfile")}},
                " || defined(PKG_OPTIONS:Msamplerate)")
+       checkRest("${LEFT} &&",
+               &mkCond{Not: &mkCond{Empty: varuse("LEFT")}},
+               " &&")
+       checkRest("\"unfinished string literal",
+               nil,
+               "\"unfinished string literal")
+       checkRest("${VAR} == \"unfinished string literal",
+               nil, // Not even the ${VAR} gets through here, although that can be expected.
+               "${VAR} == \"unfinished string literal")
 }
 
 func (s *Suite) Test_MkParser__varuse_parentheses_autofix(c *check.C) {
Index: pkgsrc/pkgtools/pkglint/files/substcontext_test.go
diff -u pkgsrc/pkgtools/pkglint/files/substcontext_test.go:1.12 pkgsrc/pkgtools/pkglint/files/substcontext_test.go:1.13
--- pkgsrc/pkgtools/pkglint/files/substcontext_test.go:1.12     Thu Jul 12 16:23:36 2018
+++ pkgsrc/pkgtools/pkglint/files/substcontext_test.go  Thu Aug 16 20:41:42 2018
@@ -90,7 +90,7 @@ func (s *Suite) Test_SubstContext__no_cl
                "WARN: Makefile:13: Incomplete SUBST block: SUBST_STAGE.repl missing.")
 }
 
-func (s *Suite) Test_SubstContext__conditionals(c *check.C) {
+func (s *Suite) Test_SubstContext__directives(c *check.C) {
        t := s.Init(c)
 
        t.SetupCommandLine("-Wextra")
@@ -119,7 +119,7 @@ func (s *Suite) Test_SubstContext__condi
                "WARN: Makefile:18: All but the first \"SUBST_SED.os\" lines should use the \"+=\" operator.")
 }
 
-func (s *Suite) Test_SubstContext__one_conditional_missing_transformation(c *check.C) {
+func (s *Suite) Test_SubstContext__missing_transformation_in_one_branch(c *check.C) {
        t := s.Init(c)
 
        t.SetupCommandLine("-Wextra")
@@ -254,7 +254,7 @@ func simulateSubstLines(t *Tester, texts
                case text == "":
                        ctx.Finish(line)
                case hasPrefix(text, "."):
-                       ctx.Conditional(line)
+                       ctx.Directive(line)
                default:
                        ctx.Varassign(line)
                }
Index: pkgsrc/pkgtools/pkglint/files/toplevel.go
diff -u pkgsrc/pkgtools/pkglint/files/toplevel.go:1.12 pkgsrc/pkgtools/pkglint/files/toplevel.go:1.13
--- pkgsrc/pkgtools/pkglint/files/toplevel.go:1.12      Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/toplevel.go   Thu Aug 16 20:41:42 2018
@@ -18,18 +18,18 @@ func CheckdirToplevel(dir string) {
        ctx := &Toplevel{dir, "", nil}
        fname := dir + "/Makefile"
 
-       lines := LoadNonemptyLines(fname, true)
-       if lines == nil {
+       mklines := LoadMk(fname, NotEmpty|LogErrors)
+       if mklines == nil {
                return
        }
 
-       for _, line := range lines {
-               if m, commentedOut, indentation, subdir, comment := match4(line.Text, `^(#?)SUBDIR\s*\+=(\s*)(\S+)\s*(?:#\s*(.*?)\s*|)$`); m {
-                       ctx.checkSubdir(line, commentedOut == "#", indentation, subdir, comment)
+       for _, mkline := range mklines.mklines {
+               if (mkline.IsVarassign() || mkline.IsCommentedVarassign()) && mkline.Varname() == "SUBDIR" {
+                       ctx.checkSubdir(mkline)
                }
        }
 
-       NewMkLines(lines).Check()
+       mklines.Check()
 
        if G.opts.Recursive {
                if G.opts.CheckGlobal {
@@ -40,13 +40,15 @@ func CheckdirToplevel(dir string) {
        }
 }
 
-func (ctx *Toplevel) checkSubdir(line Line, commentedOut bool, indentation, subdir, comment string) {
-       if commentedOut && comment == "" {
-               line.Warnf("%q commented out without giving a reason.", subdir)
+func (ctx *Toplevel) checkSubdir(mkline MkLine) {
+       subdir := mkline.Value()
+
+       if mkline.IsCommentedVarassign() && (mkline.VarassignComment() == "#" || mkline.VarassignComment() == "") {
+               mkline.Warnf("%q commented out without giving a reason.", subdir)
        }
 
-       if indentation != "\t" {
-               line.Warnf("Indentation should be a single tab character.")
+       if !hasSuffix(mkline.ValueAlign(), "=\t") {
+               mkline.Warnf("Indentation should be a single tab character.")
        }
 
        if contains(subdir, "$") || !fileExists(ctx.dir+"/"+subdir+"/Makefile") {
@@ -58,15 +60,15 @@ func (ctx *Toplevel) checkSubdir(line Li
        case subdir > prev:
                // Correctly ordered
        case subdir == prev:
-               line.Errorf("Each subdir must only appear once.")
+               mkline.Errorf("Each subdir must only appear once.")
        case subdir == "archivers" && prev == "x11":
                // This exception is documented in the top-level Makefile.
        default:
-               line.Warnf("%s should come before %s.", subdir, prev)
+               mkline.Warnf("%s should come before %s.", subdir, prev)
        }
        ctx.previousSubdir = subdir
 
-       if !commentedOut {
+       if !mkline.IsCommentedVarassign() {
                ctx.subdirs = append(ctx.subdirs, ctx.dir+"/"+subdir)
        }
 }

Index: pkgsrc/pkgtools/pkglint/files/mkline.go
diff -u pkgsrc/pkgtools/pkglint/files/mkline.go:1.35 pkgsrc/pkgtools/pkglint/files/mkline.go:1.36
--- pkgsrc/pkgtools/pkglint/files/mkline.go:1.35        Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/mkline.go     Thu Aug 16 20:41:42 2018
@@ -35,7 +35,7 @@ type mkLineShell struct {
 }
 type mkLineComment struct{}
 type mkLineEmpty struct{}
-type mkLineConditional struct {
+type mkLineDirective struct {
        indent    string
        directive string
        args      string
@@ -43,11 +43,11 @@ type mkLineConditional struct {
        elseLine  MkLine // (filled in later)
 }
 type mkLineInclude struct {
-       mustExist     bool
-       sys           bool
-       indent        string
-       includeFile   string
-       conditionVars string // (filled in later)
+       mustExist       bool
+       sys             bool
+       indent          string
+       includeFile     string
+       conditionalVars string // (filled in later)
 }
 type mkLineDependency struct {
        targets string
@@ -115,8 +115,8 @@ func NewMkLine(line Line) *MkLineImpl {
                return &MkLineImpl{line, mkLineEmpty{}}
        }
 
-       if m, indent, directive, args, comment := matchMkCond(text); m {
-               return &MkLineImpl{line, mkLineConditional{indent, directive, args, comment, nil}}
+       if m, indent, directive, args, comment := matchMkDirective(text); m {
+               return &MkLineImpl{line, mkLineDirective{indent, directive, args, comment, nil}}
        }
 
        if m, indent, directive, includefile := MatchMkInclude(text); m {
@@ -179,9 +179,9 @@ func (mkline *MkLineImpl) IsEmpty() bool
        return ok
 }
 
-// IsCond checks whether the line is a conditional (.if/.ifelse/.else/.if) or a loop (.for/.endfor).
-func (mkline *MkLineImpl) IsCond() bool {
-       _, ok := mkline.data.(mkLineConditional)
+// IsDirective checks whether the line is a conditional (.if/.elif/.else/.if) or a loop (.for/.endfor).
+func (mkline *MkLineImpl) IsDirective() bool {
+       _, ok := mkline.data.(mkLineDirective)
        return ok
 }
 
@@ -233,8 +233,8 @@ func (mkline *MkLineImpl) Value() string
 func (mkline *MkLineImpl) VarassignComment() string { return mkline.data.(mkLineAssign).comment }
 func (mkline *MkLineImpl) ShellCommand() string     { return mkline.data.(mkLineShell).command }
 func (mkline *MkLineImpl) Indent() string {
-       if mkline.IsCond() {
-               return mkline.data.(mkLineConditional).indent
+       if mkline.IsDirective() {
+               return mkline.data.(mkLineDirective).indent
        } else {
                return mkline.data.(mkLineInclude).indent
        }
@@ -242,15 +242,17 @@ func (mkline *MkLineImpl) Indent() strin
 
 // Directive returns one of "if", "ifdef", "ifndef", "else", "elif", "endif", "for", "endfor", "undef".
 //
-// See matchMkCond.
-func (mkline *MkLineImpl) Directive() string { return mkline.data.(mkLineConditional).directive }
-func (mkline *MkLineImpl) Args() string      { return mkline.data.(mkLineConditional).args }
-
-// CondComment is the trailing end-of-line comment, typically at a deeply nested .endif or .endfor.
-func (mkline *MkLineImpl) CondComment() string { return mkline.data.(mkLineConditional).comment }
-func (mkline *MkLineImpl) HasElseBranch() bool { return mkline.data.(mkLineConditional).elseLine != nil }
+// See matchMkDirective.
+func (mkline *MkLineImpl) Directive() string { return mkline.data.(mkLineDirective).directive }
+
+// Args returns the arguments from an .if, .ifdef, .ifndef, .elif, .for, .undef.
+func (mkline *MkLineImpl) Args() string { return mkline.data.(mkLineDirective).args }
+
+// DirectiveComment is the trailing end-of-line comment, typically at a deeply nested .endif or .endfor.
+func (mkline *MkLineImpl) DirectiveComment() string { return mkline.data.(mkLineDirective).comment }
+func (mkline *MkLineImpl) HasElseBranch() bool      { return mkline.data.(mkLineDirective).elseLine != nil }
 func (mkline *MkLineImpl) SetHasElseBranch(elseLine MkLine) {
-       data := mkline.data.(mkLineConditional)
+       data := mkline.data.(mkLineDirective)
        data.elseLine = elseLine
        mkline.data = data
 }
@@ -261,13 +263,13 @@ func (mkline *MkLineImpl) IncludeFile() 
 func (mkline *MkLineImpl) Targets() string { return mkline.data.(mkLineDependency).targets }
 func (mkline *MkLineImpl) Sources() string { return mkline.data.(mkLineDependency).sources }
 
-// ConditionVars is a space-separated list of those variable names
+// ConditionalVars is a space-separated list of those variable names
 // on which the inclusion depends. It is initialized later,
 // step by step, when parsing other lines
-func (mkline *MkLineImpl) ConditionVars() string { return mkline.data.(mkLineInclude).conditionVars }
-func (mkline *MkLineImpl) SetConditionVars(varnames string) {
+func (mkline *MkLineImpl) ConditionalVars() string { return mkline.data.(mkLineInclude).conditionalVars }
+func (mkline *MkLineImpl) SetConditionalVars(varnames string) {
        include := mkline.data.(mkLineInclude)
-       include.conditionVars = varnames
+       include.conditionalVars = varnames
        mkline.data = include
 }
 
@@ -406,7 +408,7 @@ func (mkline *MkLineImpl) ExplainRelativ
                "main pkgsrc repository.")
 }
 
-func matchMkCond(text string) (m bool, indent, directive, args, comment string) {
+func matchMkDirective(text string) (m bool, indent, directive, args, comment string) {
        i, n := 0, len(text)
        if i < n && text[i] == '.' {
                i++
@@ -552,13 +554,6 @@ func (mkline *MkLineImpl) VariableNeedsQ
                return nqNo
        }
 
-       // Assigning lists to lists does not require any quoting, though
-       // there may be cases like "CONFIGURE_ARGS+= -libs ${LDFLAGS:Q}"
-       // where quoting is necessary.
-       if wantList && haveList && !vuc.IsWordPart {
-               return nqDoesntMatter
-       }
-
        if wantList != haveList {
                if vuc.vartype != nil && vartype != nil {
                        if vuc.vartype.basicType == BtFetchURL && vartype.basicType == BtHomepage {
@@ -602,7 +597,7 @@ func (mkline *MkLineImpl) VariableType(v
                if trace.Tracing {
                        trace.Stepf("Use of tool %+v", tool)
                }
-               if tool.UsableAtLoadtime {
+               if tool.UsableAtLoadTime {
                        if G.Pkg == nil || G.Pkg.SeenBsdPrefsMk || G.Pkg.loadTimeTools[tool.Name] {
                                perms |= aclpUseLoadtime
                        }
@@ -650,8 +645,6 @@ func (mkline *MkLineImpl) VariableType(v
                gtype = &Vartype{lkShell, BtLdFlag, allowRuntime, true}
        case hasSuffix(varbase, "_MK"):
                gtype = &Vartype{lkNone, BtUnknown, allowAll, true}
-       case hasPrefix(varbase, "PLIST."):
-               gtype = &Vartype{lkNone, BtYes, allowAll, true}
        }
 
        if trace.Tracing {
@@ -753,8 +746,8 @@ type vucTime uint8
 const (
        vucTimeUnknown vucTime = iota
 
-       // When Makefiles are loaded, the operators := and != are evaluated,
-       // as well as the conditionals .if, .elif and .for.
+       // When Makefiles are loaded, the operators := and != evaluate their
+       // right-hand side, as well as the directives .if, .elif and .for.
        // During loading, not all variables are available yet.
        // Variable values are still subject to change, especially lists.
        vucTimeParse
@@ -815,18 +808,18 @@ func (ind *Indentation) String() string 
        s := ""
        for _, level := range ind.levels[1:] {
                s += fmt.Sprintf(" %d", level.depth)
-               if len(level.conditionVars) != 0 {
-                       s += " (" + strings.Join(level.conditionVars, " ") + ")"
+               if len(level.conditionalVars) != 0 {
+                       s += " (" + strings.Join(level.conditionalVars, " ") + ")"
                }
        }
        return "[" + strings.TrimSpace(s) + "]"
 }
 
 type indentationLevel struct {
-       mkline        MkLine   // The line in which the indentation started; the .if/.for
-       depth         int      // Number of space characters; always a multiple of 2
-       condition     string   // The corresponding condition from the .if or .elif
-       conditionVars []string // Variables on which the current path depends
+       mkline          MkLine   // The line in which the indentation started; the .if/.for
+       depth           int      // Number of space characters; always a multiple of 2
+       condition       string   // The corresponding condition from the .if or latest .elif
+       conditionalVars []string // Variables on which the current path depends
 
        // Files whose existence has been checked in a related path.
        // The check counts for both the "if" and the "else" branch,
@@ -861,7 +854,7 @@ func (ind *Indentation) Push(mkline MkLi
 }
 
 func (ind *Indentation) AddVar(varname string) {
-       vars := &ind.top().conditionVars
+       vars := &ind.top().conditionalVars
        for _, existingVarname := range *vars {
                if varname == existingVarname {
                        return
@@ -873,7 +866,7 @@ func (ind *Indentation) AddVar(varname s
 
 func (ind *Indentation) DependsOn(varname string) bool {
        for _, level := range ind.levels {
-               for _, levelVarname := range level.conditionVars {
+               for _, levelVarname := range level.conditionalVars {
                        if varname == levelVarname {
                                return true
                        }
@@ -882,9 +875,11 @@ func (ind *Indentation) DependsOn(varnam
        return false
 }
 
+// IsConditional returns whether the current line depends on evaluating
+// any variable in an .if or .elif expression or from a .for loop.
 func (ind *Indentation) IsConditional() bool {
        for _, level := range ind.levels {
-               for _, varname := range level.conditionVars {
+               for _, varname := range level.conditionalVars {
                        if !hasSuffix(varname, "_MK") {
                                return true
                        }
@@ -900,7 +895,7 @@ func (ind *Indentation) Varnames() strin
        sep := ""
        varnames := ""
        for _, level := range ind.levels {
-               for _, levelVarname := range level.conditionVars {
+               for _, levelVarname := range level.conditionalVars {
                        if !hasSuffix(levelVarname, "_MK") {
                                varnames += sep + levelVarname
                                sep = ", "
@@ -910,7 +905,7 @@ func (ind *Indentation) Varnames() strin
        return varnames
 }
 
-// Condition returns the condition for the innermost .if, .elif or .for.
+// Condition returns the condition of the innermost .if, .elif or .for.
 func (ind *Indentation) Condition() string {
        return ind.top().condition
 }
@@ -932,7 +927,7 @@ func (ind *Indentation) IsCheckedFile(fi
 }
 
 func (ind *Indentation) TrackBefore(mkline MkLine) {
-       if !mkline.IsCond() {
+       if !mkline.IsDirective() {
                return
        }
        if trace.Tracing {
@@ -949,7 +944,7 @@ func (ind *Indentation) TrackBefore(mkli
 }
 
 func (ind *Indentation) TrackAfter(mkline MkLine) {
-       if !mkline.IsCond() {
+       if !mkline.IsDirective() {
                return
        }
 
@@ -966,7 +961,7 @@ func (ind *Indentation) TrackAfter(mklin
                }
 
                // Note: adding the used variables for arbitrary conditions
-               // happens in MkLineChecker.CheckCond for performance reasons.
+               // happens in MkLineChecker.checkDirectiveCond for performance reasons.
 
                if contains(args, "exists") {
                        cond := NewMkParser(mkline.Line, args, false).MkCond()
@@ -984,7 +979,7 @@ func (ind *Indentation) TrackAfter(mklin
                ind.top().depth += 2
 
        case "elif":
-               // Handled here instead of TrackAfter to allow the action to access the previous condition.
+               // Handled here instead of TrackBefore to allow the action to access the previous condition.
                ind.top().condition = args
 
        case "else":
Index: pkgsrc/pkgtools/pkglint/files/pkglint.go
diff -u pkgsrc/pkgtools/pkglint/files/pkglint.go:1.35 pkgsrc/pkgtools/pkglint/files/pkglint.go:1.36
--- pkgsrc/pkgtools/pkglint/files/pkglint.go:1.35       Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/pkglint.go    Thu Aug 16 20:41:42 2018
@@ -138,7 +138,10 @@ func (pkglint *Pkglint) Main(argv ...str
                        dummyLine.Fatalf("Cannot create profiling file: %s", err)
                }
                pprof.StartCPUProfile(f)
-               defer pprof.StopCPUProfile()
+               defer func() {
+                       pprof.StopCPUProfile()
+                       f.Close()
+               }()
 
                regex.Profiling = true
                pkglint.loghisto = histogram.New()
@@ -146,7 +149,7 @@ func (pkglint *Pkglint) Main(argv ...str
                defer func() {
                        pkglint.logOut.Write("")
                        pkglint.loghisto.PrintStats("loghisto", pkglint.logOut.out, -1)
-                       regex.PrintStats()
+                       regex.PrintStats(pkglint.logOut.out)
                        pkglint.loaded.PrintStats("loaded", pkglint.logOut.out, 50)
                }()
        }
@@ -168,7 +171,7 @@ func (pkglint *Pkglint) Main(argv ...str
        }
 
        pkglint.Pkgsrc = NewPkgsrc(firstArg + "/" + relTopdir)
-       pkglint.Pkgsrc.Load()
+       pkglint.Pkgsrc.LoadInfrastructure()
 
        currentUser, err := user.Current()
        if err == nil {
@@ -296,13 +299,13 @@ func (pkglint *Pkglint) CheckDirent(fnam
        isDir := st.Mode().IsDir()
        isReg := st.Mode().IsRegular()
 
-       currentDir := ifelseStr(isReg, path.Dir(fname), fname)
-       absCurrentDir := abspath(currentDir)
+       dir := ifelseStr(isReg, path.Dir(fname), fname)
+       absCurrentDir := abspath(dir)
        pkglint.Wip = !pkglint.opts.Import && matches(absCurrentDir, `/wip/|/wip$`)
        pkglint.Infrastructure = matches(absCurrentDir, `/mk/|/mk$`)
-       pkgsrcdir := findPkgsrcTopdir(currentDir)
+       pkgsrcdir := findPkgsrcTopdir(dir)
        if pkgsrcdir == "" {
-               NewLineWhole(fname).Errorf("Cannot determine the pkgsrc root directory for %q.", cleanpath(currentDir))
+               NewLineWhole(fname).Errorf("Cannot determine the pkgsrc root directory for %q.", cleanpath(dir))
                return
        }
 
@@ -316,11 +319,11 @@ func (pkglint *Pkglint) CheckDirent(fnam
 
        switch pkgsrcdir {
        case "../..":
-               pkglint.checkdirPackage(pkglint.Pkgsrc.ToRel(currentDir))
+               pkglint.checkdirPackage(dir)
        case "..":
-               CheckdirCategory(currentDir)
+               CheckdirCategory(dir)
        case ".":
-               CheckdirToplevel(currentDir)
+               CheckdirToplevel(dir)
        default:
                NewLineWhole(fname).Errorf("Cannot check directories outside a pkgsrc tree.")
        }
@@ -374,7 +377,7 @@ func CheckfileExtra(fname string) {
                defer trace.Call1(fname)()
        }
 
-       if lines := LoadNonemptyLines(fname, false); lines != nil {
+       if lines := Load(fname, NotEmpty|LogErrors); lines != nil {
                ChecklinesTrailingEmptyLines(lines)
        }
 }
@@ -458,13 +461,13 @@ func CheckfileMk(fname string) {
                defer trace.Call1(fname)()
        }
 
-       lines := LoadNonemptyLines(fname, true)
-       if lines == nil {
+       mklines := LoadMk(fname, NotEmpty|LogErrors)
+       if mklines == nil {
                return
        }
 
-       NewMkLines(lines).Check()
-       SaveAutofixChanges(lines)
+       mklines.Check()
+       mklines.SaveAutofixChanges()
 }
 
 func (pkglint *Pkglint) Checkfile(fname string) {
@@ -514,21 +517,21 @@ func (pkglint *Pkglint) Checkfile(fname 
 
        case basename == "buildlink3.mk":
                if pkglint.opts.CheckBuildlink3 {
-                       if lines := LoadNonemptyLines(fname, true); lines != nil {
-                               ChecklinesBuildlink3Mk(NewMkLines(lines))
+                       if mklines := LoadMk(fname, NotEmpty|LogErrors); mklines != nil {
+                               ChecklinesBuildlink3Mk(mklines)
                        }
                }
 
        case hasPrefix(basename, "DESCR"):
                if pkglint.opts.CheckDescr {
-                       if lines := LoadNonemptyLines(fname, false); lines != nil {
+                       if lines := Load(fname, NotEmpty|LogErrors); lines != nil {
                                ChecklinesDescr(lines)
                        }
                }
 
        case basename == "distinfo":
                if pkglint.opts.CheckDistinfo {
-                       if lines := LoadNonemptyLines(fname, false); lines != nil {
+                       if lines := Load(fname, NotEmpty|LogErrors); lines != nil {
                                ChecklinesDistinfo(lines)
                        }
                }
@@ -540,21 +543,21 @@ func (pkglint *Pkglint) Checkfile(fname 
 
        case hasPrefix(basename, "MESSAGE"):
                if pkglint.opts.CheckMessage {
-                       if lines := LoadNonemptyLines(fname, false); lines != nil {
+                       if lines := Load(fname, NotEmpty|LogErrors); lines != nil {
                                ChecklinesMessage(lines)
                        }
                }
 
        case basename == "options.mk":
                if pkglint.opts.CheckOptions {
-                       if lines := LoadNonemptyLines(fname, true); lines != nil {
-                               ChecklinesOptionsMk(NewMkLines(lines))
+                       if mklines := LoadMk(fname, NotEmpty|LogErrors); mklines != nil {
+                               ChecklinesOptionsMk(mklines)
                        }
                }
 
        case matches(basename, `^patch-[-A-Za-z0-9_.~+]*[A-Za-z0-9_]$`):
                if pkglint.opts.CheckPatches {
-                       if lines := LoadNonemptyLines(fname, false); lines != nil {
+                       if lines := Load(fname, NotEmpty|LogErrors); lines != nil {
                                ChecklinesPatch(lines)
                        }
                }
@@ -574,7 +577,7 @@ func (pkglint *Pkglint) Checkfile(fname 
 
        case hasPrefix(basename, "PLIST"):
                if pkglint.opts.CheckPlist {
-                       if lines := LoadNonemptyLines(fname, false); lines != nil {
+                       if lines := Load(fname, NotEmpty|LogErrors); lines != nil {
                                ChecklinesPlist(lines)
                        }
                }

Index: pkgsrc/pkgtools/pkglint/files/mkline_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mkline_test.go:1.39 pkgsrc/pkgtools/pkglint/files/mkline_test.go:1.40
--- pkgsrc/pkgtools/pkglint/files/mkline_test.go:1.39   Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/mkline_test.go        Thu Aug 16 20:41:42 2018
@@ -123,12 +123,13 @@ func (s *Suite) Test_NewMkLine(c *check.
                "\tshell command # shell comment",
                "# whole line comment",
                "",
-               ".  if !empty(PKGNAME:M*-*) && ${RUBY_RAILS_SUPPORTED:[\\#]} == 1 # cond comment",
+               ".  if !empty(PKGNAME:M*-*) && ${RUBY_RAILS_SUPPORTED:[\\#]} == 1 # directive comment",
                ".    include \"../../mk/bsd.prefs.mk\" # include comment",
                ".    include <subdir.mk> # sysinclude comment",
                "target1 target2: source1 source2",
                "target : source",
-               "VARNAME+=value")
+               "VARNAME+=value",
+               "<<<<<<<<<<<<<<<<<")
        ln := mklines.mklines
 
        c.Check(ln[0].IsVarassign(), equals, true)
@@ -146,11 +147,11 @@ func (s *Suite) Test_NewMkLine(c *check.
 
        c.Check(ln[3].IsEmpty(), equals, true)
 
-       c.Check(ln[4].IsCond(), equals, true)
+       c.Check(ln[4].IsDirective(), equals, true)
        c.Check(ln[4].Indent(), equals, "  ")
        c.Check(ln[4].Directive(), equals, "if")
        c.Check(ln[4].Args(), equals, "!empty(PKGNAME:M*-*) && ${RUBY_RAILS_SUPPORTED:[#]} == 1")
-       c.Check(ln[4].CondComment(), equals, "cond comment")
+       c.Check(ln[4].DirectiveComment(), equals, "directive comment")
 
        c.Check(ln[5].IsInclude(), equals, true)
        c.Check(ln[5].Indent(), equals, "    ")
@@ -171,6 +172,16 @@ func (s *Suite) Test_NewMkLine(c *check.
        c.Check(ln[9].Varcanon(), equals, "VARNAME")
        c.Check(ln[9].Varparam(), equals, "")
 
+       // Merge conflicts are of neither type.
+       c.Check(ln[10].IsVarassign(), equals, false)
+       c.Check(ln[10].IsDirective(), equals, false)
+       c.Check(ln[10].IsInclude(), equals, false)
+       c.Check(ln[10].IsEmpty(), equals, false)
+       c.Check(ln[10].IsComment(), equals, false)
+       c.Check(ln[10].IsDependency(), equals, false)
+       c.Check(ln[10].IsShellCommand(), equals, false)
+       c.Check(ln[10].IsSysinclude(), equals, false)
+
        t.CheckOutputLines(
                "WARN: test.mk:9: Space before colon in dependency line.")
 }
@@ -207,6 +218,7 @@ func (s *Suite) Test_NewMkLine__autofix_
                "pkgbase := pkglint")
 }
 
+// Guessing the variable type works for both plain and parameterized variable names.
 func (s *Suite) Test_MkLine_VariableType_varparam(c *check.C) {
        t := s.Init(c)
 
@@ -216,12 +228,12 @@ func (s *Suite) Test_MkLine_VariableType
        t1 := mkline.VariableType("FONT_DIRS")
 
        c.Assert(t1, check.NotNil)
-       c.Check(t1.String(), equals, "ShellList of Pathmask")
+       c.Check(t1.String(), equals, "ShellList of Pathmask (guessed)")
 
        t2 := mkline.VariableType("FONT_DIRS.ttf")
 
        c.Assert(t2, check.NotNil)
-       c.Check(t2.String(), equals, "ShellList of Pathmask")
+       c.Check(t2.String(), equals, "ShellList of Pathmask (guessed)")
 }
 
 func (s *Suite) Test_VarUseContext_String(c *check.C) {
@@ -277,7 +289,7 @@ func (s *Suite) Test_MkLines_Check__extr
 
        t.SetupCommandLine("-Wextra")
        t.SetupVartypes()
-       G.Pkg = NewPackage("category/pkgbase")
+       G.Pkg = NewPackage(t.File("category/pkgbase"))
        G.Mk = t.NewMkLines("options.mk",
                MkRcsID,
                ".for word in ${PKG_FAIL_REASON}",
@@ -379,7 +391,7 @@ func (s *Suite) Test_MkLine_variableNeed
        t.SetupVartypes()
        t.SetupTool(&Tool{Name: "find", Varname: "FIND", Predefined: true})
        t.SetupTool(&Tool{Name: "sort", Varname: "SORT", Predefined: true})
-       G.Pkg = NewPackage("category/pkgbase")
+       G.Pkg = NewPackage(t.File("category/pkgbase"))
        G.Mk = t.NewMkLines("Makefile",
                MkRcsID,
                "GENERATE_PLIST= cd ${DESTDIR}${PREFIX}; ${FIND} * \\( -type f -or -type l \\) | ${SORT};")
@@ -629,7 +641,7 @@ func (s *Suite) Test_MkLine_variableNeed
 
        t.SetupCommandLine("-Wall")
        t.SetupVartypes()
-       G.Pkgsrc.Tools.RegisterVarname("tar", "TAR", dummyLine)
+       G.Pkgsrc.Tools.RegisterVarname("tar", "TAR", dummyMkLine)
        mklines := t.NewMkLines("Makefile",
                MkRcsID,
                "",
@@ -650,7 +662,7 @@ func (s *Suite) Test_MkLine_variableNeed
 
        t.SetupCommandLine("-Wall")
        t.SetupVartypes()
-       G.Pkgsrc.Tools.RegisterVarname("cat", "CAT", dummyLine)
+       G.Pkgsrc.Tools.RegisterVarname("cat", "CAT", dummyMkLine)
        mklines := t.NewMkLines("Makefile",
                MkRcsID,
                "",
@@ -698,6 +710,69 @@ func (s *Suite) Test_MkLine_variableNeed
                "\t${ECHO} ${FOODIR:Q}")
 }
 
+// TODO: COMPILER_RPATH_FLAG and LINKER_RPATH_FLAG have different types
+// defined in vardefs.go; examine why.
+func (s *Suite) Test_MkLine_variableNeedsQuoting__shellword_part(c *check.C) {
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall,no-space")
+       t.SetupVartypes()
+
+       mklines := t.SetupFileMkLines("Makefile",
+               MkRcsID,
+               "",
+               "SUBST_CLASSES+=    class",
+               "SUBST_STAGE.class= pre-configure",
+               "SUBST_FILES.class= files",
+               "SUBST_SED.class=-e s:@LINKER_RPATH_FLAG@:${LINKER_RPATH_FLAG}:g")
+
+       mklines.Check()
+
+       t.CheckOutputEmpty()
+}
+
+// Tools, when used in a shell command, must not be quoted.
+func (s *Suite) Test_MkLine_variableNeedsQuoting__tool_in_shell_command(c *check.C) {
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall,no-space")
+       t.SetupVartypes()
+       t.SetupTool(&Tool{Varname: "BASH"})
+
+       mklines := t.SetupFileMkLines("Makefile",
+               MkRcsID,
+               "",
+               "CONFIG_SHELL= ${BASH}")
+
+       mklines.Check()
+
+       t.CheckOutputEmpty()
+}
+
+// These examples from real pkgsrc end up in the final nqDontKnow case.
+func (s *Suite) Test_MkLine_variableNeedsQuoting__uncovered_cases(c *check.C) {
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall,no-space")
+       t.SetupVartypes()
+
+       mklines := t.SetupFileMkLines("Makefile",
+               MkRcsID,
+               "",
+               "GO_SRCPATH=             ${HOMEPAGE:S,https://,,}";,
+               "LINKER_RPATH_FLAG:=     ${LINKER_RPATH_FLAG:S/-rpath/& /}",
+               "HOMEPAGE=               http://godoc.org/${GO_SRCPATH}";,
+               "PATH:=                  ${PREFIX}/cross/bin:${PATH}",
+               "NO_SRC_ON_FTP=          ${RESTRICTED}")
+
+       mklines.Check()
+
+       t.CheckOutputLines(
+               "WARN: ~/Makefile:4: The variable LINKER_RPATH_FLAG may not be set by any package.",
+               "WARN: ~/Makefile:4: Please use ${LINKER_RPATH_FLAG:S/-rpath/& /:Q} instead of ${LINKER_RPATH_FLAG:S/-rpath/& /}.",
+               "WARN: ~/Makefile:4: LINKER_RPATH_FLAG should not be evaluated at load time.")
+}
+
 func (s *Suite) Test_MkLine_Pkgmandir(c *check.C) {
        t := s.Init(c)
 
@@ -767,11 +842,31 @@ func (s *Suite) Test_MkLine_shell_varuse
 
 // See PR 46570, Ctrl+F "3. In lang/perl5".
 func (s *Suite) Test_MkLine_VariableType(c *check.C) {
-       mkline := NewMkLine(dummyLine)
+       t := s.Init(c)
+
+       t.SetupVartypes()
+
+       checkType := func(varname string, vartype string) {
+               actualType := dummyMkLine.VariableType(varname)
+               if vartype == "" {
+                       c.Check(actualType, check.IsNil)
+               } else {
+                       if c.Check(actualType, check.NotNil) {
+                               c.Check(actualType.String(), equals, vartype)
+                       }
+               }
+       }
 
-       c.Check(mkline.VariableType("_PERL5_PACKLIST_AWK_STRIP_DESTDIR"), check.IsNil)
-       c.Check(mkline.VariableType("SOME_DIR").guessed, equals, true)
-       c.Check(mkline.VariableType("SOMEDIR").guessed, equals, true)
+       checkType("_PERL5_PACKLIST_AWK_STRIP_DESTDIR", "")
+       checkType("SOME_DIR", "Pathname (guessed)")
+       checkType("SOMEDIR", "Pathname (guessed)")
+       checkType("SEARCHPATHS", "ShellList of Pathname (guessed)")
+       checkType("APACHE_USER", "UserGroupName (guessed)")
+       checkType("APACHE_GROUP", "UserGroupName (guessed)")
+       checkType("MY_CMD_ENV", "ShellList of ShellWord (guessed)")
+       checkType("MY_CMD_ARGS", "ShellList of ShellWord (guessed)")
+       checkType("MY_CMD_CFLAGS", "ShellList of CFlag (guessed)")
+       checkType("PLIST.abcde", "Yes")
 }
 
 // PR 51696, security/py-pbkdf2/Makefile, r1.2
@@ -789,16 +884,16 @@ func (s *Suite) Test_MkLine__comment_in_
                "WARN: Makefile:2: The # character starts a comment.")
 }
 
-func (s *Suite) Test_MkLine_ConditionVars(c *check.C) {
+func (s *Suite) Test_MkLine_ConditionalVars(c *check.C) {
        t := s.Init(c)
 
        mkline := t.NewMkLine("Makefile", 45, ".include \"../../category/package/buildlink3.mk\"")
 
-       c.Check(mkline.ConditionVars(), equals, "")
+       c.Check(mkline.ConditionalVars(), equals, "")
 
-       mkline.SetConditionVars("OPSYS")
+       mkline.SetConditionalVars("OPSYS")
 
-       c.Check(mkline.ConditionVars(), equals, "OPSYS")
+       c.Check(mkline.ConditionalVars(), equals, "OPSYS")
 }
 
 func (s *Suite) Test_MkLine_ValueSplit(c *check.C) {
@@ -830,6 +925,33 @@ func (s *Suite) Test_MkLine_ValueSplit(c
                "${DESTDIR:S,/,\\:,:S,:,:,}/sbin")
 }
 
+func (s *Suite) Test_MkLine_ResolveVarsInRelativePath(c *check.C) {
+       t := s.Init(c)
+
+       checkResolve := func(before string, after string) {
+               c.Check(dummyMkLine.ResolveVarsInRelativePath(before, false), equals, after)
+       }
+
+       t.CreateFileLines("lang/lua53/Makefile")
+       t.CreateFileLines("lang/php72/Makefile")
+       t.CreateFileLines("emulators/suse100_base/Makefile")
+       t.CreateFileLines("lang/python36/Makefile")
+
+       checkResolve("", "")
+       checkResolve("${LUA_PKGSRCDIR}", "../../lang/lua53")
+       checkResolve("${PHPPKGSRCDIR}", "../../lang/php72")
+       checkResolve("${SUSE_DIR_PREFIX}", "suse100")
+       checkResolve("${PYPKGSRCDIR}", "../../lang/python36")
+       checkResolve("${PYPACKAGE}", "python36")
+       checkResolve("${FILESDIR}", "${FILESDIR}")
+       checkResolve("${PKGDIR}", "${PKGDIR}")
+
+       G.Pkg = NewPackage(t.File("category/package"))
+
+       checkResolve("${FILESDIR}", "files")
+       checkResolve("${PKGDIR}", ".")
+}
+
 func (s *Suite) Test_MatchVarassign(c *check.C) {
        s.Init(c)
 
@@ -918,3 +1040,31 @@ func (s *Suite) Test_Indentation(c *chec
        c.Check(ind.IsConditional(), equals, false)
        c.Check(ind.String(), equals, "[]")
 }
+
+func (s *Suite) Test_Indentation_RememberUsedVariables(c *check.C) {
+       t := s.Init(c)
+
+       mkline := t.NewMkLine("Makefile", 123, ".if ${PKGREVISION} > 0")
+       ind := NewIndentation()
+       cond := NewMkParser(mkline.Line, mkline.Args(), false)
+
+       ind.RememberUsedVariables(cond.MkCond())
+
+       t.CheckOutputEmpty()
+       c.Check(ind.Varnames(), equals, "PKGREVISION")
+}
+
+func (s *Suite) Test_MkLine_ExtractUsedVariables(c *check.C) {
+       t := s.Init(c)
+
+       mkline := t.NewMkLine("Makefile", 123, "")
+
+       nestedVarnames := mkline.ExtractUsedVariables("${VAR.${param}}")
+
+       // ExtractUsedVariables is very old code, should be more advanced.
+       c.Check(nestedVarnames, check.IsNil)
+
+       plainVarnames := mkline.ExtractUsedVariables("${VAR}and${VAR2}")
+
+       c.Check(plainVarnames, deepEquals, []string{"VAR", "VAR2"})
+}

Index: pkgsrc/pkgtools/pkglint/files/mklinechecker.go
diff -u pkgsrc/pkgtools/pkglint/files/mklinechecker.go:1.16 pkgsrc/pkgtools/pkglint/files/mklinechecker.go:1.17
--- pkgsrc/pkgtools/pkglint/files/mklinechecker.go:1.16 Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/mklinechecker.go      Thu Aug 16 20:41:42 2018
@@ -105,32 +105,17 @@ func (ck MkLineChecker) checkInclude() {
        }
 }
 
-func (ck MkLineChecker) checkCond(forVars map[string]bool, indentation *Indentation) {
+func (ck MkLineChecker) checkDirective(forVars map[string]bool, ind *Indentation) {
        mkline := ck.MkLine
 
        directive := mkline.Directive()
        args := mkline.Args()
-       comment := mkline.CondComment()
 
-       expectedDepth := indentation.Depth(directive)
+       expectedDepth := ind.Depth(directive)
        ck.checkDirectiveIndentation(expectedDepth)
 
        if directive == "endfor" || directive == "endif" {
-               if directive == "endif" && comment != "" {
-                       if condition := indentation.Condition(); !contains(condition, comment) {
-                               mkline.Warnf("Comment %q does not match condition %q.", comment, condition)
-                       }
-               }
-
-               if directive == "endfor" && comment != "" {
-                       if condition := indentation.Condition(); !contains(condition, comment) {
-                               mkline.Warnf("Comment %q does not match loop %q.", comment, condition)
-                       }
-               }
-
-               if indentation.Len() <= 1 {
-                       mkline.Errorf("Unmatched .%s.", directive)
-               }
+               ck.checkDirectiveEnd(ind)
        }
 
        needsArgument := false
@@ -150,55 +135,82 @@ func (ck MkLineChecker) checkCond(forVar
                }
 
        } else if directive == "if" || directive == "elif" {
-               ck.CheckCond()
+               ck.checkDirectiveCond()
 
        } else if directive == "ifdef" || directive == "ifndef" {
                mkline.Warnf("The \".%s\" directive is deprecated. Please use \".if %sdefined(%s)\" instead.",
                        directive, ifelseStr(directive == "ifdef", "", "!"), args)
 
        } else if directive == "for" {
-               if m, vars, values := match2(args, `^(\S+(?:\s*\S+)*?)\s+in\s+(.*)$`); m {
-                       for _, forvar := range splitOnSpace(vars) {
-                               indentation.AddVar(forvar)
-                               if !G.Infrastructure && hasPrefix(forvar, "_") {
-                                       mkline.Warnf("Variable names starting with an underscore (%s) are reserved for internal pkgsrc use.", forvar)
-                               }
-
-                               if matches(forvar, `^[_a-z][_a-z0-9]*$`) {
-                                       // Fine.
-                               } else if matches(forvar, `[A-Z]`) {
-                                       mkline.Warnf(".for variable names should not contain uppercase letters.")
-                               } else {
-                                       mkline.Errorf("Invalid variable name %q.", forvar)
-                               }
+               ck.checkDirectiveFor(forVars, ind)
 
-                               forVars[forvar] = true
+       } else if directive == "undef" && args != "" {
+               for _, varname := range splitOnSpace(args) {
+                       if forVars[varname] {
+                               mkline.Notef("Using \".undef\" after a \".for\" loop is unnecessary.")
                        }
+               }
+       }
+}
 
-                       // Check if any of the value's types is not guessed.
-                       guessed := true
-                       for _, value := range splitOnSpace(values) {
-                               if m, vname := match1(value, `^\$\{(.*)\}`); m {
-                                       vartype := mkline.VariableType(vname)
-                                       if vartype != nil && !vartype.guessed {
-                                               guessed = false
-                                       }
-                               }
+func (ck MkLineChecker) checkDirectiveEnd(ind *Indentation) {
+       mkline := ck.MkLine
+       directive := mkline.Directive()
+       comment := mkline.DirectiveComment()
+
+       if directive == "endif" && comment != "" {
+               if condition := ind.Condition(); !contains(condition, comment) {
+                       mkline.Warnf("Comment %q does not match condition %q.", comment, condition)
+               }
+       }
+       if directive == "endfor" && comment != "" {
+               if condition := ind.Condition(); !contains(condition, comment) {
+                       mkline.Warnf("Comment %q does not match loop %q.", comment, condition)
+               }
+       }
+       if ind.Len() <= 1 {
+               mkline.Errorf("Unmatched .%s.", directive)
+       }
+}
+
+func (ck MkLineChecker) checkDirectiveFor(forVars map[string]bool, indentation *Indentation) {
+       mkline := ck.MkLine
+       args := mkline.Args()
+
+       if m, vars, values := match2(args, `^(\S+(?:\s*\S+)*?)\s+in\s+(.*)$`); m {
+               for _, forvar := range splitOnSpace(vars) {
+                       indentation.AddVar(forvar)
+                       if !G.Infrastructure && hasPrefix(forvar, "_") {
+                               mkline.Warnf("Variable names starting with an underscore (%s) are reserved for internal pkgsrc use.", forvar)
                        }
 
-                       forLoopType := &Vartype{lkSpace, BtUnknown, []ACLEntry{{"*", aclpAllRead}}, guessed}
-                       forLoopContext := &VarUseContext{forLoopType, vucTimeParse, vucQuotFor, false}
-                       for _, forLoopVar := range mkline.ExtractUsedVariables(values) {
-                               ck.CheckVaruse(&MkVarUse{forLoopVar, nil}, forLoopContext)
+                       if matches(forvar, `^[_a-z][_a-z0-9]*$`) {
+                               // Fine.
+                       } else if matches(forvar, `[A-Z]`) {
+                               mkline.Warnf(".for variable names should not contain uppercase letters.")
+                       } else {
+                               mkline.Errorf("Invalid variable name %q.", forvar)
                        }
+
+                       forVars[forvar] = true
                }
 
-       } else if directive == "undef" && args != "" {
-               for _, uvar := range splitOnSpace(args) {
-                       if forVars[uvar] {
-                               mkline.Notef("Using \".undef\" after a \".for\" loop is unnecessary.")
+               // Check if any of the value's types is not guessed.
+               guessed := true
+               for _, value := range splitOnSpace(values) {
+                       if m, vname := match1(value, `^\$\{(.*)\}`); m {
+                               vartype := mkline.VariableType(vname)
+                               if vartype != nil && !vartype.guessed {
+                                       guessed = false
+                               }
                        }
                }
+
+               forLoopType := &Vartype{lkSpace, BtUnknown, []ACLEntry{{"*", aclpAllRead}}, guessed}
+               forLoopContext := &VarUseContext{forLoopType, vucTimeParse, vucQuotFor, false}
+               for _, forLoopVar := range mkline.ExtractUsedVariables(values) {
+                       ck.CheckVaruse(&MkVarUse{forLoopVar, nil}, forLoopContext)
+               }
        }
 }
 
@@ -330,11 +342,14 @@ func (ck MkLineChecker) CheckVaruse(varu
 
        varname := varuse.varname
        vartype := mkline.VariableType(varname)
-       if G.opts.WarnExtra &&
-               (vartype == nil || vartype.guessed) &&
-               !varIsUsed(varname) &&
-               !(G.Mk != nil && G.Mk.forVars[varname]) &&
-               !containsVarRef(varname) {
+       switch {
+       case !G.opts.WarnExtra:
+       case vartype != nil && !vartype.guessed:
+               // Well-known variables are probably defined by the infrastructure.
+       case varIsUsed(varname):
+       case G.Mk != nil && G.Mk.forVars[varname]:
+       case containsVarRef(varname):
+       default:
                mkline.Warnf("%s is used but not defined.", varname)
        }
 
@@ -886,7 +901,7 @@ func (ck MkLineChecker) checkVarassignPl
                contains(value, "@comment") && !matches(value, `="@comment "`) {
                ck.MkLine.Warnf("Please don't use @comment in %s.", varname)
                Explain(
-                       "If you are defining a PLIST conditional here, use one of the",
+                       "If you are defining a PLIST condition here, use one of the",
                        "following patterns instead:",
                        "",
                        "1. The direct way, without intermediate variable",
@@ -941,18 +956,6 @@ func (ck MkLineChecker) CheckVartype(var
        case vartype.kindOfList == lkNone:
                ck.CheckVartypePrimitive(varname, vartype.basicType, op, value, comment, vartype.guessed)
 
-               if op == opUseMatch && matches(value, `^[\w-/]+$`) && !vartype.IsConsideredList() {
-                       mkline.Notef("%s should be compared using == instead of the :M or :N modifier without wildcards.", varname)
-                       Explain(
-                               "This variable has a single value, not a list of values.  Therefore",
-                               "it feels strange to apply list operators like :M and :N onto it.",
-                               "A more direct approach is to use the == and != operators.",
-                               "",
-                               "An entirely different case is when the pattern contains wildcards",
-                               "like ^, *, $.  In such a case, using the :M or :N modifiers is",
-                               "useful and preferred.")
-               }
-
        case value == "":
                break
 
@@ -1030,7 +1033,7 @@ func (ck MkLineChecker) checkText(text s
        }
 }
 
-func (ck MkLineChecker) CheckCond() {
+func (ck MkLineChecker) checkDirectiveCond() {
        mkline := ck.MkLine
        if trace.Tracing {
                defer trace.Call1(mkline.Args())()
@@ -1039,7 +1042,7 @@ func (ck MkLineChecker) CheckCond() {
        p := NewMkParser(mkline.Line, mkline.Args(), false)
        cond := p.MkCond()
        if !p.EOF() {
-               mkline.Warnf("Invalid conditional %q.", mkline.Args())
+               mkline.Warnf("Invalid condition, unrecognized part: %q.", p.Rest())
                return
        }
 
@@ -1060,9 +1063,25 @@ func (ck MkLineChecker) CheckCond() {
                                "\t!empty(VARNAME:Mpattern)",
                                "\t${VARNAME:Mpattern}")
                }
-               for _, modifier := range varuse.modifiers {
-                       if modifier[0] == 'M' || modifier[0] == 'N' {
+
+               modifiers := varuse.modifiers
+               for _, modifier := range modifiers {
+                       if modifier[0] == 'M' || (modifier[0] == 'N' && len(modifiers) == 1) {
                                ck.CheckVartype(varname, opUseMatch, modifier[1:], "")
+
+                               value := modifier[1:]
+                               vartype := mkline.VariableType(varname)
+                               if matches(value, `^[\w-/]+$`) && vartype != nil && !vartype.IsConsideredList() {
+                                       mkline.Notef("%s should be compared using == instead of the :M or :N modifier without wildcards.", varname)
+                                       Explain(
+                                               "This variable has a single value, not a list of values.  Therefore",
+                                               "it feels strange to apply list operators like :M and :N onto it.",
+                                               "A more direct approach is to use the == and != operators.",
+                                               "",
+                                               "An entirely different case is when the pattern contains wildcards",
+                                               "like ^, *, $.  In such a case, using the :M or :N modifiers is",
+                                               "useful and preferred.")
+                               }
                        }
                }
        }

Index: pkgsrc/pkgtools/pkglint/files/mklines.go
diff -u pkgsrc/pkgtools/pkglint/files/mklines.go:1.29 pkgsrc/pkgtools/pkglint/files/mklines.go:1.30
--- pkgsrc/pkgtools/pkglint/files/mklines.go:1.29       Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/mklines.go    Thu Aug 16 20:41:42 2018
@@ -140,9 +140,9 @@ func (mklines *MkLines) Check() {
                                G.Pkg.CheckInclude(mkline, mklines.indentation)
                        }
 
-               case mkline.IsCond():
-                       ck.checkCond(mklines.forVars, mklines.indentation)
-                       substcontext.Conditional(mkline)
+               case mkline.IsDirective():
+                       ck.checkDirective(mklines.forVars, mklines.indentation)
+                       substcontext.Directive(mkline)
 
                case mkline.IsDependency():
                        ck.checkDependencyRule(allowedTargets)
@@ -173,7 +173,7 @@ func (mklines *MkLines) Check() {
 }
 
 // ForEach calls the action for each line, until the action returns false.
-// It keeps track of the indentation and all conditionals.
+// It keeps track of the indentation and all conditional variables.
 func (mklines *MkLines) ForEach(action func(mkline MkLine) bool, atEnd func(mkline MkLine)) {
        mklines.indentation = NewIndentation()
 
@@ -256,7 +256,7 @@ func (mklines *MkLines) DetermineDefined
                        }
                }
 
-               mklines.toolRegistry.ParseToolLine(mkline.Line)
+               mklines.toolRegistry.ParseToolLine(mkline)
        }
 }
 
@@ -396,6 +396,10 @@ func (mklines *MkLines) CheckRedundantVa
                func(mkline MkLine) {})
 }
 
+func (mklines *MkLines) SaveAutofixChanges() {
+       SaveAutofixChanges(mklines.lines)
+}
+
 // VaralignBlock checks that all variable assignments from a paragraph
 // use the same indentation depth for their values.
 // It also checks that the indentation uses tabs instead of spaces.
@@ -433,7 +437,7 @@ func (va *VaralignBlock) Check(mkline Mk
        case mkline.IsComment():
                return
 
-       case mkline.IsCond():
+       case mkline.IsDirective():
                return
 
        case !mkline.IsVarassign():
@@ -613,7 +617,7 @@ func (va *VaralignBlock) realign(mkline 
                        "alignment at all.",
                        "",
                        "When the block contains something else than variable definitions",
-                       "and conditionals, it is not checked at all.")
+                       "and directives like .if or .for, it is not checked at all.")
        }
        fix.ReplaceAfter(varnameOp, oldSpace, newSpace)
        fix.Apply()
Index: pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go
diff -u pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go:1.29 pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go:1.30
--- pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go:1.29     Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go  Thu Aug 16 20:41:42 2018
@@ -78,7 +78,7 @@ func (s *Suite) Test_VartypeCheck_CFlag(
 func (s *Suite) Test_VartypeCheck_Comment(c *check.C) {
        t := s.Init(c)
 
-       G.Pkg = NewPackage("category/converter")
+       G.Pkg = NewPackage(t.File("category/converter"))
        G.Pkg.EffectivePkgbase = "converter"
 
        runVartypeChecks(t, "COMMENT", opAssign, (*VartypeCheck).Comment,
@@ -168,13 +168,13 @@ func (s *Suite) Test_VartypeCheck_Depend
 
        t.CreateFileLines("x11/alacarte/Makefile")
        t.CreateFileLines("category/package/Makefile")
-       G.Pkg = NewPackage("category/package")
+       G.Pkg = NewPackage(t.File("category/package"))
 
        // Since this test involves relative paths, the filename of the line must be realistic.
        // Therefore this custom implementation of runVartypeChecks.
        runChecks := func(values ...string) {
                for i, value := range values {
-                       mkline := t.NewMkLine(t.File("category/package/fname.mk"), i+1, "DEPENDS+=\t"+value)
+                       mkline := t.NewMkLine(G.Pkg.File("fname.mk"), i+1, "DEPENDS+=\t"+value)
                        mkline.Tokenize(mkline.Value())
                        valueNovar := mkline.WithoutMakeVariables(mkline.Value())
                        vc := &VartypeCheck{mkline, mkline.Line, mkline.Varname(), mkline.Op(), mkline.Value(), valueNovar, "", false}
@@ -272,6 +272,8 @@ func (s *Suite) Test_VartypeCheck_Enum__
                ".if !empty(MACHINE_ARCH:Mi386) || ${MACHINE_ARCH} == i386",
                ".endif",
                ".if !empty(PKGSRC_COMPILER:Mclang) || ${PKGSRC_COMPILER} == clang",
+               ".endif",
+               ".if ${MACHINE_ARCH:Ni386:Nx86_64:Nsparc64}",
                ".endif")
 
        mklines.Check()
@@ -661,9 +663,9 @@ func (s *Suite) Test_VartypeCheck_Yes(c 
                "${YESVAR}")
 
        t.CheckOutputLines(
-               "WARN: fname:1: PKG_DEVELOPER should only be used in a \".if defined(...)\" conditional.",
-               "WARN: fname:2: PKG_DEVELOPER should only be used in a \".if defined(...)\" conditional.",
-               "WARN: fname:3: PKG_DEVELOPER should only be used in a \".if defined(...)\" conditional.")
+               "WARN: fname:1: PKG_DEVELOPER should only be used in a \".if defined(...)\" condition.",
+               "WARN: fname:2: PKG_DEVELOPER should only be used in a \".if defined(...)\" condition.",
+               "WARN: fname:3: PKG_DEVELOPER should only be used in a \".if defined(...)\" condition.")
 }
 
 func (s *Suite) Test_VartypeCheck_YesNo(c *check.C) {

Index: pkgsrc/pkgtools/pkglint/files/mklines_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mklines_test.go:1.25 pkgsrc/pkgtools/pkglint/files/mklines_test.go:1.26
--- pkgsrc/pkgtools/pkglint/files/mklines_test.go:1.25  Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/mklines_test.go       Thu Aug 16 20:41:42 2018
@@ -6,7 +6,7 @@ import (
        "sort"
 )
 
-func (s *Suite) Test_MkLines_Check__autofix_conditional_indentation(c *check.C) {
+func (s *Suite) Test_MkLines_Check__autofix_directive_indentation(c *check.C) {
        t := s.Init(c)
 
        t.SetupCommandLine("--autofix", "-Wspace")
@@ -69,7 +69,7 @@ func (s *Suite) Test_MkLines_quoting_LDF
 
        t.SetupCommandLine("-Wall")
        t.SetupVartypes()
-       G.Pkg = NewPackage("category/pkgbase")
+       G.Pkg = NewPackage(t.File("category/pkgbase"))
        mklines := t.NewMkLines("Makefile",
                MkRcsID,
                "GNU_CONFIGURE=\tyes",
@@ -443,7 +443,7 @@ func (s *Suite) Test_MkLines_Check__endi
                ".elif ${OPSYS} == FreeBSD",
                ".endif # NetBSD") // Wrong, should be FreeBSD from the .elif.
 
-       // See MkLineChecker.checkCond
+       // See MkLineChecker.checkDirective
        mklines.Check()
 
        t.CheckOutputLines(""+

Index: pkgsrc/pkgtools/pkglint/files/mkparser.go
diff -u pkgsrc/pkgtools/pkglint/files/mkparser.go:1.14 pkgsrc/pkgtools/pkglint/files/mkparser.go:1.15
--- pkgsrc/pkgtools/pkglint/files/mkparser.go:1.14      Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/mkparser.go   Thu Aug 16 20:41:42 2018
@@ -108,6 +108,7 @@ func (p *MkParser) VarUseModifiers(varna
 
        var modifiers []string
        mayOmitColon := false
+loop:
        for repl.AdvanceStr(":") || mayOmitColon {
                mayOmitColon = false
                modifierMark := repl.Mark()
@@ -125,7 +126,7 @@ func (p *MkParser) VarUseModifiers(varna
                                } else if len(rest) >= 1 && (rest[0] == closing[0] || rest[0] == ':') {
                                } else if repl.AdvanceRegexp(`^\\\d+`) {
                                } else {
-                                       break
+                                       break loop
                                }
                                modifiers = append(modifiers, repl.Since(modifierMark))
                                continue
Index: pkgsrc/pkgtools/pkglint/files/vartype.go
diff -u pkgsrc/pkgtools/pkglint/files/vartype.go:1.14 pkgsrc/pkgtools/pkglint/files/vartype.go:1.15
--- pkgsrc/pkgtools/pkglint/files/vartype.go:1.14       Sat Apr 28 23:32:52 2018
+++ pkgsrc/pkgtools/pkglint/files/vartype.go    Thu Aug 16 20:41:42 2018
@@ -122,16 +122,21 @@ func (vt *Vartype) MayBeAppendedTo() boo
 }
 
 func (vt *Vartype) String() string {
+       listPrefix := ""
        switch vt.kindOfList {
        case lkNone:
-               return vt.basicType.name
+               listPrefix = ""
        case lkSpace:
-               return "SpaceList of " + vt.basicType.name
+               listPrefix = "SpaceList of "
        case lkShell:
-               return "ShellList of " + vt.basicType.name
+               listPrefix = "ShellList of "
        default:
                panic("Unknown list type")
        }
+
+       guessedSuffix := ifelseStr(vt.guessed, " (guessed)", "")
+
+       return listPrefix + vt.basicType.name + guessedSuffix
 }
 
 func (vt *Vartype) IsShell() bool {

Index: pkgsrc/pkgtools/pkglint/files/package.go
diff -u pkgsrc/pkgtools/pkglint/files/package.go:1.33 pkgsrc/pkgtools/pkglint/files/package.go:1.34
--- pkgsrc/pkgtools/pkglint/files/package.go:1.33       Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/package.go    Thu Aug 16 20:41:42 2018
@@ -15,6 +15,7 @@ const rePkgname = `^([\w\-.+]+)-(\d[.0-9
 
 // Package contains data for the pkgsrc package that is currently checked.
 type Package struct {
+       dir                  string          // The directory of the package, for resolving files
        Pkgpath              string          // e.g. "category/pkgdir"
        Pkgdir               string          // PKGDIR from the package Makefile
        Filesdir             string          // FILESDIR from the package Makefile
@@ -30,7 +31,7 @@ type Package struct {
 
        vars                  Scope
        bl3                   map[string]Line // buildlink3.mk name => line; contains only buildlink3.mk files that are directly included.
-       plistSubstCond        map[string]bool // varname => true; list of all variables that are used as conditionals (@comment or nothing) in PLISTs.
+       plistSubstCond        map[string]bool // varname => true; all variables that are used as conditions (@comment or nothing) in PLISTs.
        included              map[string]Line // fname => line
        seenMakefileCommon    bool            // Does the package have any .includes?
        loadTimeTools         map[string]bool // true=ok, false=not ok, absent=not mentioned in USE_TOOLS.
@@ -40,12 +41,19 @@ type Package struct {
        IgnoreMissingPatches  bool // In distinfo, don't warn about patches that cannot be found.
 }
 
-func NewPackage(pkgpath string) *Package {
+func NewPackage(dir string) *Package {
+       pkgpath := G.Pkgsrc.ToRel(dir)
+       if strings.Count(pkgpath, "/") != 1 {
+               NewLineWhole(dir).Errorf("Package directory %q must be two subdirectories below the pkgsrc root %q.", dir, G.Pkgsrc.File("."))
+       }
+
        pkg := &Package{
+               dir:                   dir,
                Pkgpath:               pkgpath,
                Pkgdir:                ".",
                Filesdir:              "files",
                Patchdir:              "patches",
+               DistinfoFile:          "distinfo",
                PlistDirs:             make(map[string]bool),
                PlistFiles:            make(map[string]bool),
                vars:                  NewScope(),
@@ -65,7 +73,7 @@ func NewPackage(pkgpath string) *Package
 // File returns the (possibly absolute) path to relativeFilename,
 // as resolved from the package's directory.
 func (pkg *Package) File(relativeFilename string) string {
-       return G.Pkgsrc.File(pkg.Pkgpath + "/" + relativeFilename)
+       return cleanpath(pkg.dir + "/" + relativeFilename)
 }
 
 func (pkg *Package) varValue(varname string) (string, bool) {
@@ -151,21 +159,14 @@ func (pkg *Package) checklinesBuildlink3
        }
 }
 
-// Given the package path relative to the pkgsrc top directory,
-// checks a complete pkgsrc package.
-//
-// Example:
-//  checkdirPackage("category/pkgbase")
-func (pkglint *Pkglint) checkdirPackage(pkgpath string) {
+// checkdirPackage checks a complete pkgsrc package, including each
+// of the files individually, and also when seen in combination.
+func (pkglint *Pkglint) checkdirPackage(dir string) {
        if trace.Tracing {
-               defer trace.Call1(pkgpath)()
+               defer trace.Call1(dir)()
        }
 
-       if strings.Count(pkgpath, "/") != 1 {
-               dummyLine.Fatalf("Internal pkglint error: Wrong pkgpath %q.", pkgpath)
-       }
-
-       G.Pkg = NewPackage(pkgpath)
+       G.Pkg = NewPackage(dir)
        defer func() { G.Pkg = nil }()
        pkg := G.Pkg
 
@@ -195,8 +196,8 @@ func (pkglint *Pkglint) checkdirPackage(
                        !matches(fname, `patch-`) &&
                        !contains(fname, pkg.Pkgdir+"/") &&
                        !contains(fname, pkg.Filesdir+"/") {
-                       if lines, err := readLines(fname, true); err == nil && lines != nil {
-                               NewMkLines(lines).DetermineUsedVariables()
+                       if mklines := LoadMk(fname, MustSucceed); mklines != nil {
+                               mklines.DetermineUsedVariables()
                        }
                }
                if hasPrefix(path.Base(fname), "PLIST") {
@@ -301,11 +302,10 @@ func (pkg *Package) readMakefile(fname s
                defer trace.Call1(fname)()
        }
 
-       fileLines := LoadNonemptyLines(fname, true)
-       if fileLines == nil {
+       fileMklines := LoadMk(fname, NotEmpty|LogErrors)
+       if fileMklines == nil {
                return false
        }
-       fileMklines := NewMkLines(fileLines)
 
        isMainMakefile := len(mainLines.mklines) == 0
 
@@ -916,10 +916,10 @@ func (pkg *Package) checkLocallyModified
 }
 
 func (pkg *Package) CheckInclude(mkline MkLine, indentation *Indentation) {
-       conditionVars := mkline.ConditionVars()
-       if conditionVars == "" {
-               conditionVars = indentation.Varnames()
-               mkline.SetConditionVars(conditionVars)
+       conditionalVars := mkline.ConditionalVars()
+       if conditionalVars == "" {
+               conditionalVars = indentation.Varnames()
+               mkline.SetConditionalVars(conditionalVars)
        }
 
        if path.Dir(abspath(mkline.Filename)) == abspath(pkg.File(".")) {
@@ -929,27 +929,23 @@ func (pkg *Package) CheckInclude(mkline 
                        pkg.conditionalIncludes[includefile] = mkline
                        if other := pkg.unconditionalIncludes[includefile]; other != nil {
                                mkline.Warnf("%q is included conditionally here (depending on %s) and unconditionally in %s.",
-                                       cleanpath(includefile), mkline.ConditionVars(), other.ReferenceFrom(mkline.Line))
+                                       cleanpath(includefile), mkline.ConditionalVars(), other.ReferenceFrom(mkline.Line))
                        }
                } else {
                        pkg.unconditionalIncludes[includefile] = mkline
                        if other := pkg.conditionalIncludes[includefile]; other != nil {
                                mkline.Warnf("%q is included unconditionally here and conditionally in %s (depending on %s).",
-                                       cleanpath(includefile), other.ReferenceFrom(mkline.Line), other.ConditionVars())
+                                       cleanpath(includefile), other.ReferenceFrom(mkline.Line), other.ConditionalVars())
                        }
                }
        }
 }
 
 func (pkg *Package) loadPlistDirs(plistFilename string) {
-       lines, err := readLines(plistFilename, false)
-       if err != nil {
-               return
-       }
-
+       lines := Load(plistFilename, MustSucceed)
        for _, line := range lines {
                text := line.Text
-               pkg.PlistFiles[text] = true // XXX: ignores PLIST conditionals for now
+               pkg.PlistFiles[text] = true // XXX: ignores PLIST conditions for now
                // Keep in sync with PlistChecker.collectFilesAndDirs
                if !contains(text, "$") && !contains(text, "@") {
                        for dir := path.Dir(text); dir != "."; dir = path.Dir(dir) {

Index: pkgsrc/pkgtools/pkglint/files/package_test.go
diff -u pkgsrc/pkgtools/pkglint/files/package_test.go:1.27 pkgsrc/pkgtools/pkglint/files/package_test.go:1.28
--- pkgsrc/pkgtools/pkglint/files/package_test.go:1.27  Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/package_test.go       Thu Aug 16 20:41:42 2018
@@ -5,7 +5,7 @@ import "gopkg.in/check.v1"
 func (s *Suite) Test_Package_pkgnameFromDistname(c *check.C) {
        t := s.Init(c)
 
-       pkg := NewPackage("dummy")
+       pkg := NewPackage(t.File("category/package"))
        pkg.vars.Define("PKGNAME", t.NewMkLine("Makefile", 5, "PKGNAME=dummy"))
 
        c.Check(pkg.pkgnameFromDistname("pkgname-1.0", "whatever"), equals, "pkgname-1.0")
@@ -25,7 +25,7 @@ func (s *Suite) Test_Package_CheckVarord
        t := s.Init(c)
 
        t.SetupCommandLine("-Worder")
-       pkg := NewPackage("x11/9term")
+       pkg := NewPackage(t.File("x11/9term"))
 
        pkg.CheckVarorder(t.NewMkLines("Makefile",
                MkRcsID,
@@ -56,7 +56,7 @@ func (s *Suite) Test_Package_CheckVarord
        t := s.Init(c)
 
        t.SetupCommandLine("-Worder")
-       pkg := NewPackage("x11/9term")
+       pkg := NewPackage(t.File("x11/9term"))
 
        pkg.CheckVarorder(t.NewMkLines("Makefile",
                MkRcsID,
@@ -79,7 +79,7 @@ func (s *Suite) Test_Package_CheckVarord
 
        t.SetupCommandLine("-Worder")
 
-       pkg := NewPackage("x11/9term")
+       pkg := NewPackage(t.File("x11/9term"))
 
        pkg.CheckVarorder(t.NewMkLines("Makefile",
                MkRcsID,
@@ -95,12 +95,12 @@ func (s *Suite) Test_Package_CheckVarord
        t.CheckOutputEmpty()
 }
 
-func (s *Suite) Test_Package_CheckVarorder__conditionals_skip(c *check.C) {
+func (s *Suite) Test_Package_CheckVarorder__skip_if_there_are_directives(c *check.C) {
        t := s.Init(c)
 
        t.SetupCommandLine("-Worder")
 
-       pkg := NewPackage("x11/9term")
+       pkg := NewPackage(t.File("category/package"))
 
        pkg.CheckVarorder(t.NewMkLines("Makefile",
                MkRcsID,
@@ -113,8 +113,8 @@ func (s *Suite) Test_Package_CheckVarord
                ".endif",
                "LICENSE=\tgnu-gpl-v2"))
 
-       // No warning about the missing COMMENT since the conditional
-       // skips the whole check.
+       // No warning about the missing COMMENT since the directive
+       // causes the whole check to be skipped.
        t.CheckOutputEmpty()
 }
 
@@ -122,7 +122,7 @@ func (s *Suite) Test_Package_CheckVarord
        t := s.Init(c)
 
        t.SetupCommandLine("-Worder")
-       pkg := NewPackage("x11/9term")
+       pkg := NewPackage(t.File("x11/9term"))
 
        pkg.CheckVarorder(t.NewMkLines("Makefile",
                MkRcsID,
@@ -172,7 +172,7 @@ func (s *Suite) Test_Package_CheckVarord
        t := s.Init(c)
 
        t.SetupCommandLine("-Worder")
-       pkg := NewPackage("category/package")
+       pkg := NewPackage(t.File("category/package"))
 
        pkg.CheckVarorder(t.NewMkLines("Makefile",
                MkRcsID,
@@ -196,7 +196,7 @@ func (s *Suite) Test_Package_CheckVarord
 
        t.SetupCommandLine("-Worder")
        t.SetupVartypes()
-       pkg := NewPackage("category/package")
+       pkg := NewPackage(t.File("category/package"))
 
        pkg.CheckVarorder(t.NewMkLines("Makefile",
                MkRcsID,
@@ -246,7 +246,7 @@ func (s *Suite) Test_Package_CheckVarord
 func (s *Suite) Test_Package_getNbpart(c *check.C) {
        t := s.Init(c)
 
-       pkg := NewPackage("category/pkgbase")
+       pkg := NewPackage(t.File("category/pkgbase"))
        pkg.vars.Define("PKGREVISION", t.NewMkLine("Makefile", 1, "PKGREVISION=14"))
 
        c.Check(pkg.getNbpart(), equals, "nb14")
@@ -260,7 +260,7 @@ func (s *Suite) Test_Package_getNbpart(c
 func (s *Suite) Test_Package_determineEffectivePkgVars__precedence(c *check.C) {
        t := s.Init(c)
 
-       pkg := NewPackage("category/pkgbase")
+       pkg := NewPackage(t.File("category/pkgbase"))
        pkgnameLine := t.NewMkLine("Makefile", 3, "PKGNAME=pkgname-1.0")
        distnameLine := t.NewMkLine("Makefile", 4, "DISTNAME=distname-1.0")
        pkgrevisionLine := t.NewMkLine("Makefile", 5, "PKGREVISION=13")
@@ -279,21 +279,19 @@ func (s *Suite) Test_Package_determineEf
 func (s *Suite) Test_Package_checkPossibleDowngrade(c *check.C) {
        t := s.Init(c)
 
-       G.Pkg = NewPackage("category/pkgbase")
+       t.CreateFileLines("doc/CHANGES-2018",
+               "\tUpdated category/pkgbase to 1.8 [committer 2018-01-05]")
+       G.Pkgsrc.loadDocChanges()
+
+       t.Chdir("category/pkgbase")
+       G.Pkg = NewPackage(".")
        G.Pkg.EffectivePkgname = "package-1.0nb15"
-       G.Pkg.EffectivePkgnameLine = t.NewMkLine("category/pkgbase/Makefile", 5, "PKGNAME=dummy")
-       G.Pkgsrc.LastChange = map[string]*Change{
-               "category/pkgbase": {
-                       Action:  "Updated",
-                       Version: "1.8",
-                       Line:    t.NewLine("doc/CHANGES", 116, "dummy"),
-               },
-       }
+       G.Pkg.EffectivePkgnameLine = t.NewMkLine("Makefile", 5, "PKGNAME=dummy")
 
        G.Pkg.checkPossibleDowngrade()
 
        t.CheckOutputLines(
-               "WARN: category/pkgbase/Makefile:5: The package is being downgraded from 1.8 (see ../../doc/CHANGES:116) to 1.0nb15.")
+               "WARN: Makefile:5: The package is being downgraded from 1.8 (see ../../doc/CHANGES-2018:1) to 1.0nb15.")
 
        G.Pkgsrc.LastChange["category/pkgbase"].Version = "1.0nb22"
 
@@ -305,31 +303,33 @@ func (s *Suite) Test_Package_checkPossib
 func (s *Suite) Test_checkdirPackage(c *check.C) {
        t := s.Init(c)
 
-       t.SetupFileLines("category/package/Makefile",
+       t.Chdir("category/package")
+       t.SetupFileLines("Makefile",
                MkRcsID)
 
-       G.checkdirPackage("category/package")
+       G.checkdirPackage(".")
 
        t.CheckOutputLines(
-               "WARN: ~/category/package/Makefile: Neither PLIST nor PLIST.common exist, and PLIST_SRC is unset.",
-               "WARN: ~/category/package/distinfo: File not found. Please run \""+confMake+" makesum\" or define NO_CHECKSUM=yes in the package Makefile.",
-               "ERROR: ~/category/package/Makefile: Each package must define its LICENSE.",
-               "WARN: ~/category/package/Makefile: No COMMENT given.")
+               "WARN: Makefile: Neither PLIST nor PLIST.common exist, and PLIST_SRC is unset.",
+               "WARN: distinfo: File not found. Please run \""+confMake+" makesum\" or define NO_CHECKSUM=yes in the package Makefile.",
+               "ERROR: Makefile: Each package must define its LICENSE.",
+               "WARN: Makefile: No COMMENT given.")
 }
 
 func (s *Suite) Test_Pkglint_checkdirPackage__meta_package_without_license(c *check.C) {
        t := s.Init(c)
 
-       t.CreateFileLines("category/package/Makefile",
+       t.Chdir("category/package")
+       t.CreateFileLines("Makefile",
                MkRcsID,
                "",
                "META_PACKAGE=\tyes")
        t.SetupVartypes()
 
-       G.checkdirPackage("category/package")
+       G.checkdirPackage(".")
 
        t.CheckOutputLines(
-               "WARN: ~/category/package/Makefile: No COMMENT given.") // No error about missing LICENSE.
+               "WARN: Makefile: No COMMENT given.") // No error about missing LICENSE.
 }
 
 func (s *Suite) Test_Package__varuse_at_load_time(c *check.C) {
@@ -391,10 +391,9 @@ func (s *Suite) Test_Package_loadPackage
                "PKGNAME=pkgname-1.67",
                "DISTNAME=distfile_1_67",
                ".include \"../../category/package/Makefile\"")
-       pkg := NewPackage("category/package")
-       G.Pkg = pkg
+       G.Pkg = NewPackage(t.File("category/package"))
 
-       pkg.loadPackageMakefile()
+       G.Pkg.loadPackageMakefile()
 
        // Including a package Makefile directly is an error (in the last line),
        // but that is checked later.
@@ -409,7 +408,13 @@ func (s *Suite) Test_Package_conditional
        t := s.Init(c)
 
        t.SetupVartypes()
-       t.CreateFileLines("category/package/Makefile",
+       t.CreateFileLines("devel/zlib/buildlink3.mk", "")
+       t.CreateFileLines("licenses/gnu-gpl-v2", "")
+       t.CreateFileLines("mk/bsd.pkg.mk", "")
+       t.CreateFileLines("sysutils/coreutils/buildlink3.mk", "")
+
+       t.Chdir("category/package")
+       t.CreateFileLines("Makefile",
                MkRcsID,
                "",
                "COMMENT\t=Description",
@@ -419,37 +424,29 @@ func (s *Suite) Test_Package_conditional
                ".include \"../../sysutils/coreutils/buildlink3.mk\"",
                ".endif",
                ".include \"../../mk/bsd.pkg.mk\"")
-       t.CreateFileLines("category/package/options.mk",
+       t.CreateFileLines("options.mk",
                MkRcsID,
                "",
                ".if !empty(PKG_OPTIONS:Mzlib)",
                ".  include \"../../devel/zlib/buildlink3.mk\"",
                ".endif",
                ".include \"../../sysutils/coreutils/buildlink3.mk\"")
-       t.CreateFileLines("category/package/PLIST",
+       t.CreateFileLines("PLIST",
                PlistRcsID,
                "bin/program")
-       t.CreateFileLines("category/package/distinfo",
+       t.CreateFileLines("distinfo",
                RcsID)
 
-       t.CreateFileLines("devel/zlib/buildlink3.mk", "")
-       t.CreateFileLines("licenses/gnu-gpl-v2", "")
-       t.CreateFileLines("mk/bsd.pkg.mk", "")
-       t.CreateFileLines("sysutils/coreutils/buildlink3.mk", "")
-
-       pkg := NewPackage("category/package")
-       G.Pkg = pkg
-
-       G.checkdirPackage("category/package")
+       G.checkdirPackage(".")
 
        t.CheckOutputLines(
-               "WARN: ~/category/package/Makefile:3: The canonical order of the variables is CATEGORIES, empty line, COMMENT, LICENSE.",
-               "WARN: ~/category/package/options.mk:3: Unknown option \"zlib\".",
-               "WARN: ~/category/package/options.mk:4: \"../../devel/zlib/buildlink3.mk\" is "+
+               "WARN: Makefile:3: The canonical order of the variables is CATEGORIES, empty line, COMMENT, LICENSE.",
+               "WARN: options.mk:3: Unknown option \"zlib\".",
+               "WARN: options.mk:4: \"../../devel/zlib/buildlink3.mk\" is "+
                        "included conditionally here (depending on PKG_OPTIONS) and unconditionally in Makefile:5.",
-               "WARN: ~/category/package/options.mk:6: \"../../sysutils/coreutils/buildlink3.mk\" is "+
+               "WARN: options.mk:6: \"../../sysutils/coreutils/buildlink3.mk\" is "+
                        "included unconditionally here and conditionally in Makefile:7 (depending on OPSYS).",
-               "WARN: ~/category/package/options.mk:3: Expected definition of PKG_OPTIONS_VAR.")
+               "WARN: options.mk:3: Expected definition of PKG_OPTIONS_VAR.")
 }
 
 // See https://github.com/rillig/pkglint/issues/1
@@ -465,7 +462,7 @@ func (s *Suite) Test_Package_includeWith
                "",
                ".include \"../../mk/bsd.pkg.mk\"")
 
-       G.checkdirPackage("category/package")
+       G.checkdirPackage(t.File("category/package"))
 
        t.CheckOutputLines(
                "ERROR: ~/category/package/options.mk: Cannot be read.")
@@ -477,7 +474,8 @@ func (s *Suite) Test_Package_includeAfte
 
        t.SetupVartypes()
        t.CreateFileLines("mk/bsd.pkg.mk")
-       t.CreateFileLines("category/package/Makefile",
+       t.Chdir("category/package")
+       t.CreateFileLines("Makefile",
                MkRcsID,
                "",
                ".if exists(options.mk)",
@@ -486,14 +484,14 @@ func (s *Suite) Test_Package_includeAfte
                "",
                ".include \"../../mk/bsd.pkg.mk\"")
 
-       G.checkdirPackage("category/package")
+       G.checkdirPackage(".")
 
        t.CheckOutputLines(
-               "WARN: ~/category/package/Makefile: Neither PLIST nor PLIST.common exist, and PLIST_SRC is unset.",
-               "WARN: ~/category/package/distinfo: File not found. Please run \""+confMake+" makesum\" or define NO_CHECKSUM=yes in the package Makefile.",
-               "ERROR: ~/category/package/Makefile: Each package must define its LICENSE.",
-               "WARN: ~/category/package/Makefile: No COMMENT given.",
-               "ERROR: ~/category/package/Makefile:4: \"options.mk\" does not exist.")
+               "WARN: Makefile: Neither PLIST nor PLIST.common exist, and PLIST_SRC is unset.",
+               "WARN: distinfo: File not found. Please run \""+confMake+" makesum\" or define NO_CHECKSUM=yes in the package Makefile.",
+               "ERROR: Makefile: Each package must define its LICENSE.",
+               "WARN: Makefile: No COMMENT given.",
+               "ERROR: Makefile:4: \"options.mk\" does not exist.")
 }
 
 // See https://github.com/rillig/pkglint/issues/1
@@ -511,7 +509,7 @@ func (s *Suite) Test_Package_includeOthe
                "",
                ".include \"../../mk/bsd.pkg.mk\"")
 
-       G.checkdirPackage("category/package")
+       G.checkdirPackage(t.File("category/package"))
 
        t.CheckOutputLines(
                "ERROR: ~/category/package/another.mk: Cannot be read.")
@@ -547,7 +545,7 @@ func (s *Suite) Test_Package__redundant_
 
        // See Package.checkfilePackageMakefile
        // See Scope.uncond
-       G.checkdirPackage("math/R-date")
+       G.checkdirPackage(t.File("math/R-date"))
 
        t.CheckOutputLines(
                "NOTE: ~/math/R-date/Makefile:6: Definition of MASTER_SITES is redundant because of ../R/Makefile.extension:4.")

Index: pkgsrc/pkgtools/pkglint/files/parser_test.go
diff -u pkgsrc/pkgtools/pkglint/files/parser_test.go:1.7 pkgsrc/pkgtools/pkglint/files/parser_test.go:1.8
--- pkgsrc/pkgtools/pkglint/files/parser_test.go:1.7    Sat Jan 27 18:50:36 2018
+++ pkgsrc/pkgtools/pkglint/files/parser_test.go        Thu Aug 16 20:41:42 2018
@@ -31,6 +31,14 @@ func (s *Suite) Test_Parser_Dependency(c
                }
        }
 
+       checkNil := func(pattern string) {
+               parser := NewParser(dummyLine, pattern, false)
+               dp := parser.Dependency()
+               if c.Check(dp, check.IsNil) {
+                       c.Check(parser.Rest(), equals, pattern)
+               }
+       }
+
        check := func(pattern string, expected DependencyPattern) {
                checkRest(pattern, expected, "")
        }
@@ -50,5 +58,7 @@ func (s *Suite) Test_Parser_Dependency(c
        check("ncurses-${NC_VERS}{,nb*}", DependencyPattern{"ncurses", "", "", "", "", "${NC_VERS}{,nb*}"})
        check("xulrunner10>=${MOZ_BRANCH}${MOZ_BRANCH_MINOR}", DependencyPattern{"xulrunner10", ">=", "${MOZ_BRANCH}${MOZ_BRANCH_MINOR}", "", "", ""})
        checkRest("gnome-control-center>=2.20.1{,nb*}", DependencyPattern{"gnome-control-center", ">=", "2.20.1", "", "", ""}, "{,nb*}")
+       checkNil(">=2.20.1{,nb*}")
+       checkNil("pkgbase<=")
        // "{ssh{,6}-[0-9]*,openssh-[0-9]*}" is not representable using the current data structure
 }
Index: pkgsrc/pkgtools/pkglint/files/pkgsrc.go
diff -u pkgsrc/pkgtools/pkglint/files/pkgsrc.go:1.7 pkgsrc/pkgtools/pkglint/files/pkgsrc.go:1.8
--- pkgsrc/pkgtools/pkglint/files/pkgsrc.go:1.7 Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/pkgsrc.go     Thu Aug 16 20:41:42 2018
@@ -79,14 +79,14 @@ func NewPkgsrc(dir string) *Pkgsrc {
        return src
 }
 
-// Load reads the pkgsrc infrastructure files to
+// LoadInfrastructure reads the pkgsrc infrastructure files to
 // extract information like the tools, packages to update,
 // user-defined variables.
 //
 // This work is not done in the constructor to keep the tests
 // simple, since setting up a realistic pkgsrc environment requires
 // a lot of files.
-func (src *Pkgsrc) Load() {
+func (src *Pkgsrc) LoadInfrastructure() {
        src.InitVartypes()
        src.loadMasterSites()
        src.loadPkgOptions()
@@ -148,9 +148,10 @@ func (src *Pkgsrc) loadTools() {
        toolFiles := []string{"defaults.mk"}
        {
                toc := G.Pkgsrc.File("mk/tools/bsd.tools.mk")
-               lines := LoadExistingLines(toc, true)
-               for _, line := range lines {
-                       if m, _, _, includefile := MatchMkInclude(line.Text); m {
+               mklines := LoadMk(toc, MustSucceed|NotEmpty)
+               for _, mkline := range mklines.mklines {
+                       if mkline.IsInclude() {
+                               includefile := mkline.IncludeFile()
                                if !contains(includefile, "/") {
                                        toolFiles = append(toolFiles, includefile)
                                }
@@ -162,41 +163,38 @@ func (src *Pkgsrc) loadTools() {
        }
 
        reg := src.Tools
-       reg.RegisterTool(&Tool{"echo", "ECHO", true, true, true}, dummyLine)
-       reg.RegisterTool(&Tool{"echo -n", "ECHO_N", true, true, true}, dummyLine)
-       reg.RegisterTool(&Tool{"false", "FALSE", true /*why?*/, true, false}, dummyLine)
-       reg.RegisterTool(&Tool{"test", "TEST", true, true, true}, dummyLine)
-       reg.RegisterTool(&Tool{"true", "TRUE", true /*why?*/, true, true}, dummyLine)
+       reg.RegisterTool(&Tool{"echo", "ECHO", true, true, true}, dummyMkLine)
+       reg.RegisterTool(&Tool{"echo -n", "ECHO_N", true, true, true}, dummyMkLine)
+       reg.RegisterTool(&Tool{"false", "FALSE", true /*why?*/, true, false}, dummyMkLine)
+       reg.RegisterTool(&Tool{"test", "TEST", true, true, true}, dummyMkLine)
+       reg.RegisterTool(&Tool{"true", "TRUE", true /*why?*/, true, true}, dummyMkLine)
 
        for _, basename := range toolFiles {
-               lines := G.Pkgsrc.LoadExistingLines("mk/tools/"+basename, true)
-               for _, line := range lines {
-                       reg.ParseToolLine(line)
+               mklines := G.Pkgsrc.LoadMk("mk/tools/"+basename, MustSucceed|NotEmpty)
+               for _, mkline := range mklines.mklines {
+                       reg.ParseToolLine(mkline)
                }
        }
 
        for _, relativeName := range [...]string{"mk/bsd.prefs.mk", "mk/bsd.pkg.mk"} {
-               condDepth := 0
+               dirDepth := 0
 
-               lines := G.Pkgsrc.LoadExistingLines(relativeName, true)
-               for _, line := range lines {
-                       text := line.Text
-                       if hasPrefix(text, "#") {
-                               continue
-                       }
-
-                       if m, _, varname, _, _, _, value, _, _ := MatchVarassign(text); m {
+               mklines := G.Pkgsrc.LoadMk(relativeName, MustSucceed|NotEmpty)
+               for _, mkline := range mklines.mklines {
+                       if mkline.IsVarassign() {
+                               varname := mkline.Varname()
+                               value := mkline.Value()
                                if varname == "USE_TOOLS" {
                                        if trace.Tracing {
-                                               trace.Stepf("[condDepth=%d] %s", condDepth, value)
+                                               trace.Stepf("[dirDepth=%d] %s", dirDepth, value)
                                        }
-                                       if condDepth == 0 || condDepth == 1 && relativeName == "mk/bsd.prefs.mk" {
+                                       if dirDepth == 0 || dirDepth == 1 && relativeName == "mk/bsd.prefs.mk" {
                                                for _, toolname := range splitOnSpace(value) {
                                                        if !containsVarRef(toolname) {
-                                                               tool := reg.Register(toolname, line)
+                                                               tool := reg.Register(toolname, mkline)
                                                                tool.Predefined = true
                                                                if relativeName == "mk/bsd.prefs.mk" {
-                                                                       tool.UsableAtLoadtime = true
+                                                                       tool.UsableAtLoadTime = true
                                                                }
                                                        }
                                                }
@@ -208,12 +206,12 @@ func (src *Pkgsrc) loadTools() {
                                        }
                                }
 
-                       } else if m, _, cond, _, _ := matchMkCond(text); m {
-                               switch cond {
+                       } else if mkline.IsDirective() {
+                               switch mkline.Directive() {
                                case "if", "ifdef", "ifndef", "for":
-                                       condDepth++
+                                       dirDepth++
                                case "endif", "endfor":
-                                       condDepth--
+                                       dirDepth--
                                }
                        }
                }
@@ -224,11 +222,6 @@ func (src *Pkgsrc) loadTools() {
        }
 }
 
-func (src *Pkgsrc) loadSuggestedUpdatesFile(fname string) []SuggestedUpdate {
-       lines := LoadExistingLines(fname, false)
-       return src.parseSuggestedUpdates(lines)
-}
-
 func (src *Pkgsrc) parseSuggestedUpdates(lines []Line) []SuggestedUpdate {
        var updates []SuggestedUpdate
        state := 0
@@ -261,14 +254,11 @@ func (src *Pkgsrc) parseSuggestedUpdates
 }
 
 func (src *Pkgsrc) loadSuggestedUpdates() {
-       src.suggestedUpdates = src.loadSuggestedUpdatesFile(G.Pkgsrc.File("doc/TODO"))
-       if wipFilename := G.Pkgsrc.File("wip/TODO"); fileExists(wipFilename) {
-               src.suggestedWipUpdates = src.loadSuggestedUpdatesFile(wipFilename)
-       }
+       src.suggestedUpdates = src.parseSuggestedUpdates(Load(G.Pkgsrc.File("doc/TODO"), MustSucceed))
+       src.suggestedWipUpdates = src.parseSuggestedUpdates(Load(G.Pkgsrc.File("wip/TODO"), NotEmpty))
 }
 
 func (src *Pkgsrc) loadDocChangesFromFile(fname string) []*Change {
-       lines := LoadExistingLines(fname, false)
 
        parseChange := func(line Line) *Change {
                text := line.Text
@@ -306,6 +296,7 @@ func (src *Pkgsrc) loadDocChangesFromFil
                year = yyyy
        }
 
+       lines := Load(fname, MustSucceed|NotEmpty)
        var changes []*Change
        for _, line := range lines {
                if change := parseChange(line); change != nil {
@@ -371,8 +362,7 @@ func (src *Pkgsrc) loadDocChanges() {
 }
 
 func (src *Pkgsrc) loadUserDefinedVars() {
-       lines := G.Pkgsrc.LoadExistingLines("mk/defaults/mk.conf", true)
-       mklines := NewMkLines(lines)
+       mklines := G.Pkgsrc.LoadMk("mk/defaults/mk.conf", MustSucceed|NotEmpty)
 
        for _, mkline := range mklines.mklines {
                if mkline.IsVarassign() {
@@ -542,9 +532,14 @@ func (src *Pkgsrc) initDeprecatedVars() 
        }
 }
 
-// LoadExistingLines loads the file relative to the pkgsrc top directory.
-func (src *Pkgsrc) LoadExistingLines(fileName string, joinBackslashLines bool) []Line {
-       return LoadExistingLines(src.File(fileName), joinBackslashLines)
+// Load loads the file relative to the pkgsrc top directory.
+func (src *Pkgsrc) Load(fileName string, options LoadOptions) []Line {
+       return Load(src.File(fileName), options)
+}
+
+// LoadMk loads the Makefile relative to the pkgsrc top directory.
+func (src *Pkgsrc) LoadMk(fileName string, options LoadOptions) *MkLines {
+       return LoadMk(src.File(fileName), options)
 }
 
 // File resolves a file name relative to the pkgsrc top directory.
@@ -572,14 +567,15 @@ func (src *Pkgsrc) IsBuildDef(varname st
 }
 
 func (src *Pkgsrc) loadMasterSites() {
-       lines := src.LoadExistingLines("mk/fetch/sites.mk", true)
+       mklines := src.LoadMk("mk/fetch/sites.mk", MustSucceed|NotEmpty)
 
        nameToUrl := src.MasterSiteVarToURL
        urlToName := src.MasterSiteURLToVar
-       for _, line := range lines {
-               if m, commented, varname, _, _, _, urls, _, _ := MatchVarassign(line.Text); m {
-                       if !commented && hasPrefix(varname, "MASTER_SITE_") && varname != "MASTER_SITE_BACKUP" {
-                               for _, url := range splitOnSpace(urls) {
+       for _, mkline := range mklines.mklines {
+               if mkline.IsVarassign() {
+                       varname := mkline.Varname()
+                       if hasPrefix(varname, "MASTER_SITE_") && varname != "MASTER_SITE_BACKUP" {
+                               for _, url := range splitOnSpace(mkline.Value()) {
                                        if matches(url, `^(?:http://|https://|ftp://)`) {
                                                if nameToUrl[varname] == "" {
                                                        nameToUrl[varname] = url
@@ -600,7 +596,7 @@ func (src *Pkgsrc) loadMasterSites() {
 }
 
 func (src *Pkgsrc) loadPkgOptions() {
-       lines := src.LoadExistingLines("mk/defaults/options.description", false)
+       lines := src.Load("mk/defaults/options.description", MustSucceed)
 
        for _, line := range lines {
                if m, optname, optdescr := match2(line.Text, `^([-0-9a-z_+]+)(?:\s+(.*))?$`); m {

Index: pkgsrc/pkgtools/pkglint/files/patches_test.go
diff -u pkgsrc/pkgtools/pkglint/files/patches_test.go:1.18 pkgsrc/pkgtools/pkglint/files/patches_test.go:1.19
--- pkgsrc/pkgtools/pkglint/files/patches_test.go:1.18  Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/patches_test.go       Thu Aug 16 20:41:42 2018
@@ -31,6 +31,7 @@ func (s *Suite) Test_ChecklinesPatch__wi
 func (s *Suite) Test_ChecklinesPatch__without_empty_line__autofix(c *check.C) {
        t := s.Init(c)
 
+       t.Chdir("category/package")
        patchLines := t.SetupFileLines("patch-WithoutEmptyLines",
                RcsID,
                "Text",
@@ -48,14 +49,14 @@ func (s *Suite) Test_ChecklinesPatch__wi
                "SHA1 (some patch) = 49abd735b7e706ea9ed6671628bb54e91f7f5ffb")
 
        t.SetupCommandLine("-Wall", "--autofix")
-       G.Pkg = &Package{DistinfoFile: "distinfo"}
+       G.Pkg = NewPackage(".")
 
        ChecklinesPatch(patchLines)
 
        t.CheckOutputLines(
-               "AUTOFIX: ~/patch-WithoutEmptyLines:2: Inserting a line \"\" before this line.",
-               "AUTOFIX: ~/patch-WithoutEmptyLines:3: Inserting a line \"\" before this line.",
-               "AUTOFIX: ~/distinfo:3: Replacing \"49abd735b7e706ea9ed6671628bb54e91f7f5ffb\" "+
+               "AUTOFIX: patch-WithoutEmptyLines:2: Inserting a line \"\" before this line.",
+               "AUTOFIX: patch-WithoutEmptyLines:3: Inserting a line \"\" before this line.",
+               "AUTOFIX: distinfo:3: Replacing \"49abd735b7e706ea9ed6671628bb54e91f7f5ffb\" "+
                        "with \"4938fc8c0b483dc2e33e741b0da883d199e78164\".")
 
        t.CheckFileLines("patch-WithoutEmptyLines",

Index: pkgsrc/pkgtools/pkglint/files/pkglint_test.go
diff -u pkgsrc/pkgtools/pkglint/files/pkglint_test.go:1.22 pkgsrc/pkgtools/pkglint/files/pkglint_test.go:1.23
--- pkgsrc/pkgtools/pkglint/files/pkglint_test.go:1.22  Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/pkglint_test.go       Thu Aug 16 20:41:42 2018
@@ -291,7 +291,7 @@ func (s *Suite) Test_resolveVariableRefs
        t := s.Init(c)
 
        mkline := t.NewMkLine("fname", 1, "GCC_VERSION=${GCC_VERSION}")
-       G.Pkg = NewPackage(".")
+       G.Pkg = NewPackage(t.File("category/pkgbase"))
        G.Pkg.vars.Define("GCC_VERSION", mkline)
 
        resolved := resolveVariableRefs("gcc-${GCC_VERSION}")
@@ -305,7 +305,7 @@ func (s *Suite) Test_resolveVariableRefs
        mkline1 := t.NewMkLine("fname", 10, "_=${SECOND}")
        mkline2 := t.NewMkLine("fname", 11, "_=${THIRD}")
        mkline3 := t.NewMkLine("fname", 12, "_=got it")
-       G.Pkg = NewPackage(".")
+       G.Pkg = NewPackage(t.File("category/pkgbase"))
        defineVar(mkline1, "FIRST")
        defineVar(mkline2, "SECOND")
        defineVar(mkline3, "THIRD")
@@ -322,7 +322,7 @@ func (s *Suite) Test_resolveVariableRefs
        t := s.Init(c)
 
        mkline := t.NewMkLine("fname", 10, "_=x11")
-       G.Pkg = NewPackage("category/pkg")
+       G.Pkg = NewPackage(t.File("category/pkg"))
        G.Pkg.vars.Define("GST_PLUGINS0.10_TYPE", mkline)
 
        resolved := resolveVariableRefs("gst-plugins0.10-${GST_PLUGINS0.10_TYPE}/distinfo")
@@ -484,3 +484,52 @@ func (s *Suite) Test_Pkglint_Checkfile__
                "Looks fine.",
                "(Run \"pkglint -e\" to show explanations.)")
 }
+
+func (s *Suite) Test_Pkglint__profiling(c *check.C) {
+       t := s.Init(c)
+
+       t.SetupPkgsrc()
+       G.Main("pkglint", "--profiling", t.File("."))
+
+       // Pkglint always writes the profiling data into the current directory.
+       // Luckily, this directory is usually writable.
+       c.Check(fileExists("pkglint.pprof"), equals, true)
+
+       err := os.Remove("pkglint.pprof")
+       c.Check(err, check.IsNil)
+
+       // Everything but the first few lines of output is not easily testable
+       // or not interesting enough, since that info includes the exact timing
+       // that the top time-consuming regular expressions took.
+       firstOutput := strings.Split(t.Output(), "\n")[0]
+       c.Check(firstOutput, equals, "ERROR: ~/Makefile: Cannot be read.")
+}
+
+func (s *Suite) Test_Pkglint_Checkfile__in_current_working_directory(c *check.C) {
+       t := s.Init(c)
+
+       t.SetupPkgsrc()
+       t.SetupVartypes()
+       t.CreateFileLines("licenses/mit")
+       t.Chdir("category/package")
+       t.CreateFileLines("log")
+       t.CreateFileLines("Makefile",
+               MkRcsID,
+               "",
+               "NO_CHECKSUM=    yes",
+               "COMMENT=        Useful utilities",
+               "LICENSE=        mit",
+               "",
+               ".include \"../../mk/bsd.pkg.mk\"")
+       t.CreateFileLines("PLIST",
+               PlistRcsID,
+               "bin/program")
+       t.CreateFileLines("DESCR",
+               "Package description")
+
+       G.Main("pkglint")
+
+       t.CheckOutputLines(
+               "WARN: log: Unexpected file found.",
+               "0 errors and 1 warning found.")
+}

Index: pkgsrc/pkgtools/pkglint/files/pkgsrc_test.go
diff -u pkgsrc/pkgtools/pkglint/files/pkgsrc_test.go:1.5 pkgsrc/pkgtools/pkglint/files/pkgsrc_test.go:1.6
--- pkgsrc/pkgtools/pkglint/files/pkgsrc_test.go:1.5    Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/pkgsrc_test.go        Thu Aug 16 20:41:42 2018
@@ -1,9 +1,6 @@
 package main
 
-import (
-       "gopkg.in/check.v1"
-       "netbsd.org/pkglint/trace"
-)
+import "gopkg.in/check.v1"
 
 // Ensures that pkglint can handle MASTER_SITES definitions with and
 // without line continuations.
@@ -99,25 +96,26 @@ func (s *Suite) Test_Pkgsrc_loadTools(c 
 
        G.Pkgsrc.loadTools()
 
-       trace.Tracing = true
+       t.EnableTracingToLog()
        G.Pkgsrc.Tools.Trace()
+       t.DisableTracing()
 
        t.CheckOutputLines(
                "TRACE: + (*ToolRegistry).Trace()",
-               "TRACE: 1   tool &{Name:bzcat Varname: MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
-               "TRACE: 1   tool &{Name:bzip2 Varname: MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
-               "TRACE: 1   tool &{Name:chown Varname:CHOWN MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
-               "TRACE: 1   tool &{Name:echo Varname:ECHO MustUseVarForm:true Predefined:true UsableAtLoadtime:true}",
-               "TRACE: 1   tool &{Name:echo -n Varname:ECHO_N MustUseVarForm:true Predefined:true UsableAtLoadtime:true}",
-               "TRACE: 1   tool &{Name:false Varname:FALSE MustUseVarForm:true Predefined:true UsableAtLoadtime:false}",
-               "TRACE: 1   tool &{Name:gawk Varname:AWK MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
-               "TRACE: 1   tool &{Name:m4 Varname: MustUseVarForm:false Predefined:true UsableAtLoadtime:true}",
-               "TRACE: 1   tool &{Name:msgfmt Varname: MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
-               "TRACE: 1   tool &{Name:mv Varname:MV MustUseVarForm:false Predefined:true UsableAtLoadtime:false}",
-               "TRACE: 1   tool &{Name:pwd Varname:PWD MustUseVarForm:false Predefined:true UsableAtLoadtime:true}",
-               "TRACE: 1   tool &{Name:strip Varname: MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
-               "TRACE: 1   tool &{Name:test Varname:TEST MustUseVarForm:true Predefined:true UsableAtLoadtime:true}",
-               "TRACE: 1   tool &{Name:true Varname:TRUE MustUseVarForm:true Predefined:true UsableAtLoadtime:true}",
+               "TRACE: 1   tool &{Name:bzcat Varname: MustUseVarForm:false Predefined:false UsableAtLoadTime:false}",
+               "TRACE: 1   tool &{Name:bzip2 Varname: MustUseVarForm:false Predefined:false UsableAtLoadTime:false}",
+               "TRACE: 1   tool &{Name:chown Varname:CHOWN MustUseVarForm:false Predefined:false UsableAtLoadTime:false}",
+               "TRACE: 1   tool &{Name:echo Varname:ECHO MustUseVarForm:true Predefined:true UsableAtLoadTime:true}",
+               "TRACE: 1   tool &{Name:echo -n Varname:ECHO_N MustUseVarForm:true Predefined:true UsableAtLoadTime:true}",
+               "TRACE: 1   tool &{Name:false Varname:FALSE MustUseVarForm:true Predefined:true UsableAtLoadTime:false}",
+               "TRACE: 1   tool &{Name:gawk Varname:AWK MustUseVarForm:false Predefined:false UsableAtLoadTime:false}",
+               "TRACE: 1   tool &{Name:m4 Varname: MustUseVarForm:false Predefined:true UsableAtLoadTime:true}",
+               "TRACE: 1   tool &{Name:msgfmt Varname: MustUseVarForm:false Predefined:false UsableAtLoadTime:false}",
+               "TRACE: 1   tool &{Name:mv Varname:MV MustUseVarForm:false Predefined:true UsableAtLoadTime:false}",
+               "TRACE: 1   tool &{Name:pwd Varname:PWD MustUseVarForm:false Predefined:true UsableAtLoadTime:true}",
+               "TRACE: 1   tool &{Name:strip Varname: MustUseVarForm:false Predefined:false UsableAtLoadTime:false}",
+               "TRACE: 1   tool &{Name:test Varname:TEST MustUseVarForm:true Predefined:true UsableAtLoadTime:true}",
+               "TRACE: 1   tool &{Name:true Varname:TRUE MustUseVarForm:true Predefined:true UsableAtLoadTime:true}",
                "TRACE: - (*ToolRegistry).Trace()")
 }
 

Index: pkgsrc/pkgtools/pkglint/files/plist.go
diff -u pkgsrc/pkgtools/pkglint/files/plist.go:1.26 pkgsrc/pkgtools/pkglint/files/plist.go:1.27
--- pkgsrc/pkgtools/pkglint/files/plist.go:1.26 Thu Jul 12 16:23:36 2018
+++ pkgsrc/pkgtools/pkglint/files/plist.go      Thu Aug 16 20:41:42 2018
@@ -45,9 +45,9 @@ type PlistChecker struct {
 }
 
 type PlistLine struct {
-       line        Line
-       conditional string // e.g. PLIST.docs
-       text        string // Like line.text, without the conditional
+       line      Line
+       condition string // e.g. PLIST.docs
+       text      string // Like line.text, without the condition
 }
 
 func (ck *PlistChecker) Check(plainLines []Line) {
@@ -55,8 +55,8 @@ func (ck *PlistChecker) Check(plainLines
        ck.collectFilesAndDirs(plines)
 
        if fname := plines[0].line.Filename; path.Base(fname) == "PLIST.common_end" {
-               commonLines, err := readLines(strings.TrimSuffix(fname, "_end"), false)
-               if err == nil {
+               commonLines := Load(strings.TrimSuffix(fname, "_end"), NotEmpty)
+               if commonLines != nil {
                        ck.collectFilesAndDirs(ck.NewLines(commonLines))
                }
        }
@@ -81,13 +81,13 @@ func (ck *PlistChecker) Check(plainLines
 func (ck *PlistChecker) NewLines(lines []Line) []*PlistLine {
        plines := make([]*PlistLine, len(lines))
        for i, line := range lines {
-               conditional, text := "", line.Text
+               condition, text := "", line.Text
                if hasPrefix(text, "${PLIST.") {
                        if m, cond, rest := match2(text, `^(?:\$\{(PLIST\.[\w-.]+)\})+(.*)`); m {
-                               conditional, text = cond, rest
+                               condition, text = cond, rest
                        }
                }
-               plines[i] = &PlistLine{line, conditional, text}
+               plines[i] = &PlistLine{line, condition, text}
        }
        return plines
 }
@@ -101,7 +101,7 @@ func (ck *PlistChecker) collectFilesAndD
                                first == '$',
                                'A' <= first && first <= 'Z',
                                '0' <= first && first <= '9':
-                               if prev := ck.allFiles[text]; prev == nil || pline.conditional < prev.conditional {
+                               if prev := ck.allFiles[text]; prev == nil || pline.condition < prev.condition {
                                        ck.allFiles[text] = pline
                                }
                                for dir := path.Dir(text); dir != "."; dir = path.Dir(dir) {
@@ -224,7 +224,7 @@ func (ck *PlistChecker) checkDuplicate(p
        }
 
        prev := ck.allFiles[text]
-       if prev == pline || prev.conditional != "" {
+       if prev == pline || prev.condition != "" {
                return
        }
 
@@ -518,7 +518,7 @@ func (s *plistLineSorter) Sort() {
                mi := s.middle[i]
                mj := s.middle[j]
                less := mi.text < mj.text || (mi.text == mj.text &&
-                       mi.conditional < mj.conditional)
+                       mi.condition < mj.condition)
                if (i < j) != less {
                        s.changed = true
                }
Index: pkgsrc/pkgtools/pkglint/files/util.go
diff -u pkgsrc/pkgtools/pkglint/files/util.go:1.26 pkgsrc/pkgtools/pkglint/files/util.go:1.27
--- pkgsrc/pkgtools/pkglint/files/util.go:1.26  Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/util.go       Thu Aug 16 20:41:42 2018
@@ -169,8 +169,8 @@ func loadCvsEntries(fname string) []Line
                return G.CvsEntriesLines
        }
 
-       lines, err := readLines(dir+"/CVS/Entries", false)
-       if err != nil {
+       lines := Load(dir+"/CVS/Entries", 0)
+       if lines == nil {
                return nil
        }
        G.CvsEntriesDir = dir
@@ -301,7 +301,7 @@ func dirglob(dirname string) []string {
        var fnames []string
        for _, fi := range fis {
                if !(isIgnoredFilename(fi.Name())) {
-                       fnames = append(fnames, dirname+"/"+fi.Name())
+                       fnames = append(fnames, cleanpath(dirname+"/"+fi.Name()))
                }
        }
        return fnames
@@ -585,7 +585,7 @@ func naturalLess(str1, str2 string) bool
 // but that's deep in the infrastructure and only affects the "nb13" extension.)
 type RedundantScope struct {
        vars        map[string]*redundantScopeVarinfo
-       condLevel   int
+       dirLevel    int
        OnIgnore    func(old, new MkLine)
        OnOverwrite func(old, new MkLine)
 }
@@ -602,7 +602,7 @@ func (s *RedundantScope) Handle(mkline M
        switch {
        case mkline.IsVarassign():
                varname := mkline.Varname()
-               if s.condLevel != 0 {
+               if s.dirLevel != 0 {
                        s.vars[varname] = nil
                        break
                }
@@ -645,12 +645,12 @@ func (s *RedundantScope) Handle(mkline M
                        }
                }
 
-       case mkline.IsCond():
+       case mkline.IsDirective():
                switch mkline.Directive() {
                case "for", "if", "ifdef", "ifndef":
-                       s.condLevel++
+                       s.dirLevel++
                case "endfor", "endif":
-                       s.condLevel--
+                       s.dirLevel--
                }
        }
 }

Index: pkgsrc/pkgtools/pkglint/files/shell_test.go
diff -u pkgsrc/pkgtools/pkglint/files/shell_test.go:1.28 pkgsrc/pkgtools/pkglint/files/shell_test.go:1.29
--- pkgsrc/pkgtools/pkglint/files/shell_test.go:1.28    Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/shell_test.go Thu Aug 16 20:41:42 2018
@@ -184,7 +184,7 @@ func (s *Suite) Test_ShellLine_CheckShel
 
        t.CheckOutputEmpty()
 
-       checkShellCommandLine("${RUN} echo $${variable+set}")
+       checkShellCommandLine("${RUN} set +x; echo $${variable+set}")
 
        t.CheckOutputEmpty()
 
@@ -234,7 +234,7 @@ func (s *Suite) Test_ShellLine_CheckShel
                "WARN: fname:1: The shell command \"cp\" should not be hidden.",
                "WARN: fname:1: Unknown shell command \"cp\".")
 
-       G.Pkg = NewPackage("category/pkgbase")
+       G.Pkg = NewPackage(t.File("category/pkgbase"))
        G.Pkg.PlistDirs["share/pkgbase"] = true
 
        // A directory that is found in the PLIST.

Index: pkgsrc/pkgtools/pkglint/files/substcontext.go
diff -u pkgsrc/pkgtools/pkglint/files/substcontext.go:1.11 pkgsrc/pkgtools/pkglint/files/substcontext.go:1.12
--- pkgsrc/pkgtools/pkglint/files/substcontext.go:1.11  Thu Jul 12 16:23:36 2018
+++ pkgsrc/pkgtools/pkglint/files/substcontext.go       Thu Aug 16 20:41:42 2018
@@ -134,13 +134,13 @@ func (ctx *SubstContext) Varassign(mklin
        }
 }
 
-func (ctx *SubstContext) Conditional(mkline MkLine) {
+func (ctx *SubstContext) Directive(mkline MkLine) {
        if ctx.id == "" || !G.opts.WarnExtra {
                return
        }
 
        if trace.Tracing {
-               trace.Stepf("+ SubstContext.Conditional %#v %v#", ctx.curr, ctx.inAllBranches)
+               trace.Stepf("+ SubstContext.Directive %#v %v#", ctx.curr, ctx.inAllBranches)
        }
        dir := mkline.Directive()
        if dir == "if" {
@@ -159,7 +159,7 @@ func (ctx *SubstContext) Conditional(mkl
                ctx.curr.Or(ctx.inAllBranches)
        }
        if trace.Tracing {
-               trace.Stepf("- SubstContext.Conditional %#v %v#", ctx.curr, ctx.inAllBranches)
+               trace.Stepf("- SubstContext.Directive %#v %v#", ctx.curr, ctx.inAllBranches)
        }
 }
 
Index: pkgsrc/pkgtools/pkglint/files/util_test.go
diff -u pkgsrc/pkgtools/pkglint/files/util_test.go:1.11 pkgsrc/pkgtools/pkglint/files/util_test.go:1.12
--- pkgsrc/pkgtools/pkglint/files/util_test.go:1.11     Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/util_test.go  Thu Aug 16 20:41:42 2018
@@ -86,11 +86,13 @@ func (s *Suite) Test_isEmptyDir_and_getS
 
        if absent := t.File("nonexistent"); true {
                c.Check(isEmptyDir(absent), equals, true) // Counts as empty.
-               defer t.ExpectFatalError(func() {
-                       c.Check(t.Output(), check.Matches, `FATAL: (.+): Cannot be read: open (.+): (.+)\n`)
-               })
-               getSubdirs(absent) // Panics with a pkglintFatal.
-               c.FailNow()
+
+               func() {
+                       defer t.ExpectFatalError()
+                       getSubdirs(absent) // Panics with a pkglintFatal.
+               }()
+               // The last group from the error message is localized, therefore the matching.
+               c.Check(t.Output(), check.Matches, `FATAL: ~/nonexistent: Cannot be read: open ~/nonexistent: (.+)\n`)
        }
 }
 

Index: pkgsrc/pkgtools/pkglint/files/vardefs.go
diff -u pkgsrc/pkgtools/pkglint/files/vardefs.go:1.43 pkgsrc/pkgtools/pkglint/files/vardefs.go:1.44
--- pkgsrc/pkgtools/pkglint/files/vardefs.go:1.43       Thu Jul 19 06:38:15 2018
+++ pkgsrc/pkgtools/pkglint/files/vardefs.go    Thu Aug 16 20:41:42 2018
@@ -71,41 +71,18 @@ func (src *Pkgsrc) InitVartypes() {
                acl(varname, kindOfList, checker, "buildlink3.mk, builtin.mk:; *: use-loadtime, use")
        }
 
-       jvms := enum(func() string {
-               lines, _ := readLines(src.File("mk/java-vm.mk"), true)
-               mklines := NewMkLines(lines)
-               jvms := make(map[string]bool)
-               for _, mkline := range mklines.mklines {
-                       if mkline.IsVarassign() && mkline.Varcanon() == "_PKG_JVMS.*" {
-                               words, _ := splitIntoMkWords(mkline.Line, mkline.Value())
-                               for _, word := range words {
-                                       if !contains(word, "$") {
-                                               jvms[word] = true
-                                       }
-                               }
-                       }
-               }
-               if len(jvms) == 0 {
-                       return "openjdk8 oracle-jdk8 openjdk7 sun-jdk7 sun-jdk6 jdk16 jdk15 kaffe"
-               }
-               joined := keysJoined(jvms)
-               if trace.Tracing {
-                       trace.Stepf("JVMs from mk/java-vm.mk: %s", joined)
-               }
-               return joined
-       }())
-
        languages := enum(
                func() string {
-                       lines, _ := readLines(src.File("mk/compiler.mk"), true)
-                       mklines := NewMkLines(lines)
+                       mklines := LoadMk(src.File("mk/compiler.mk"), NotEmpty)
                        languages := make(map[string]bool)
-                       for _, mkline := range mklines.mklines {
-                               if mkline.IsCond() && mkline.Directive() == "for" {
-                                       words := splitOnSpace(mkline.Args())
-                                       if len(words) > 2 && words[0] == "_version_" {
-                                               for _, word := range words[2:] {
-                                                       languages[word] = true
+                       if mklines != nil {
+                               for _, mkline := range mklines.mklines {
+                                       if mkline.IsDirective() && mkline.Directive() == "for" {
+                                               words := splitOnSpace(mkline.Args())
+                                               if len(words) > 2 && words[0] == "_version_" {
+                                                       for _, word := range words[2:] {
+                                                               languages[word] = true
+                                                       }
                                                }
                                        }
                                }
@@ -121,17 +98,68 @@ func (src *Pkgsrc) InitVartypes() {
                        return joined
                }())
 
-       enumFrom := func(fileName, varname, defval string) *BasicType {
-               lines, _ := readLines(src.File(fileName), true)
-               mklines := NewMkLines(lines)
-               for _, mkline := range mklines.mklines {
-                       if mkline.IsVarassign() && mkline.Varname() == varname {
-                               return enum(mkline.Value())
+       enumFrom := func(fileName string, defval string, varcanons ...string) *BasicType {
+               mklines := LoadMk(src.File(fileName), NotEmpty)
+               values := make(map[string]bool)
+
+               if mklines != nil {
+                       for _, mkline := range mklines.mklines {
+                               if mkline.IsVarassign() {
+                                       varcanon := mkline.Varcanon()
+                                       for _, vc := range varcanons {
+                                               if vc == varcanon {
+                                                       words, _ := splitIntoMkWords(mkline.Line, mkline.Value())
+                                                       for _, word := range words {
+                                                               if !contains(word, "$") {
+                                                                       values[word] = true
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               if len(values) != 0 {
+                       joined := keysJoined(values)
+                       if trace.Tracing {
+                               trace.Stepf("Enum from %s in: %s", strings.Join(varcanons, " "), fileName, joined)
                        }
+                       return enum(joined)
+               }
+
+               if trace.Tracing {
+                       trace.Stepf("Enum from default value: %s", defval)
                }
                return enum(defval)
        }
 
+       compilers := enumFrom(
+               "mk/compiler.mk",
+               "ccache ccc clang distcc f2c gcc hp icc ido mipspro mipspro-ucode pcc sunpro xlc",
+               "_COMPILERS",
+               "_PSEUDO_COMPILERS")
+
+       emacsVersions := enumFrom(
+               "editors/emacs/modules.mk",
+               "emacs25 emacs21 emacs21nox emacs20 xemacs215 xemacs215nox xemacs214 xemacs214nox",
+               "_EMACS_VERSIONS_ALL")
+
+       mysqlVersions := enumFrom(
+               "mk/mysql.buildlink3.mk",
+               "57 56 55 51 MARIADB55",
+               "MYSQL_VERSIONS_ACCEPTED")
+
+       pgsqlVersions := enumFrom(
+               "mk/pgsql.buildlink3.mk",
+               "10 96 95 94 93",
+               "PGSQL_VERSIONS_ACCEPTED")
+
+       jvms := enumFrom(
+               "mk/java-vm.mk",
+               "openjdk8 oracle-jdk8 openjdk7 sun-jdk7 sun-jdk6 jdk16 jdk15 kaffe",
+               "_PKG_JVMS.*")
+
        // Last synced with mk/defaults/mk.conf revision 1.269
        usr("USE_CWRAPPERS", lkNone, enum("yes no auto"))
        usr("ALLOW_VULNERABLE_PACKAGES", lkNone, BtYes)
@@ -153,7 +181,7 @@ func (src *Pkgsrc) InitVartypes() {
        usr("PKG_DEVELOPER", lkNone, BtYesNo)
        usr("USE_ABI_DEPENDS", lkNone, BtYesNo)
        usr("PKG_REGISTER_SHELLS", lkNone, enum("YES NO"))
-       usr("PKGSRC_COMPILER", lkShell, enum("ccache ccc clang distcc f2c gcc hp icc ido mipspro mipspro-ucode pcc sunpro xlc"))
+       usr("PKGSRC_COMPILER", lkShell, compilers)
        usr("PKGSRC_KEEP_BIN_PKGS", lkNone, BtYesNo)
        usr("PKGSRC_MESSAGE_RECIPIENTS", lkShell, BtMailAddress)
        usr("PKGSRC_SHOW_BUILD_DEFS", lkNone, BtYesNo)
@@ -599,10 +627,10 @@ func (src *Pkgsrc) InitVartypes() {
        sys("EMACS_PKGNAME_PREFIX", lkNone, BtIdentifier) // Or the empty string.
        sys("EMACS_TYPE", lkNone, enum("emacs xemacs"))
        acl("EMACS_USE_LEIM", lkNone, BtYes, "")
-       acl("EMACS_VERSIONS_ACCEPTED", lkShell, enumFrom("editors/emacs/modules.mk", "_EMACS_VERSIONS_ALL", "emacs25 emacs21 emacs21nox emacs20 xemacs215 xemacs215nox xemacs214 xemacs214nox"), 
"Makefile: set")
+       acl("EMACS_VERSIONS_ACCEPTED", lkShell, emacsVersions, "Makefile: set")
        sys("EMACS_VERSION_MAJOR", lkNone, BtInteger)
        sys("EMACS_VERSION_MINOR", lkNone, BtInteger)
-       acl("EMACS_VERSION_REQD", lkShell, enum("emacs25 emacs25nox emacs21 emacs21nox emacs20 xemacs215 xemacs214"), "Makefile: set, append")
+       acl("EMACS_VERSION_REQD", lkShell, emacsVersions, "Makefile: set, append")
        sys("EMULDIR", lkNone, BtPathname)
        sys("EMULSUBDIR", lkNone, BtPathname)
        sys("OPSYS_EMULDIR", lkNone, BtPathname)
@@ -796,11 +824,11 @@ func (src *Pkgsrc) InitVartypes() {
        acl("MESSAGE_SUBST", lkShell, BtShellWord, "Makefile, Makefile.common, options.mk: append")
        pkg("META_PACKAGE", lkNone, BtYes)
        sys("MISSING_FEATURES", lkShell, BtIdentifier)
-       acl("MYSQL_VERSIONS_ACCEPTED", lkShell, enumFrom("mk/mysql.buildlink3.mk", "MYSQL_VERSIONS_ACCEPTED", "57 56 55 51 MARIADB55"), "Makefile: set")
+       acl("MYSQL_VERSIONS_ACCEPTED", lkShell, mysqlVersions, "Makefile: set")
        usr("MYSQL_VERSION_DEFAULT", lkNone, BtVersion)
        sys("NM", lkNone, BtShellCommand)
        sys("NONBINMODE", lkNone, BtFileMode)
-       pkg("NOT_FOR_COMPILER", lkShell, enum("ccache ccc clang distcc f2c gcc hp icc ido mipspro mipspro-ucode pcc sunpro xlc"))
+       pkg("NOT_FOR_COMPILER", lkShell, compilers)
        pkglist("NOT_FOR_BULK_PLATFORM", lkSpace, BtMachinePlatformPattern)
        pkglist("NOT_FOR_PLATFORM", lkSpace, BtMachinePlatformPattern)
        pkg("NOT_FOR_UNPRIVILEGED", lkNone, BtYesNo)
@@ -817,7 +845,7 @@ func (src *Pkgsrc) InitVartypes() {
        acl("NO_PKGTOOLS_REQD_CHECK", lkNone, BtYes, "Makefile: set")
        acl("NO_SRC_ON_CDROM", lkNone, BtRestricted, "Makefile, Makefile.common: set")
        acl("NO_SRC_ON_FTP", lkNone, BtRestricted, "Makefile, Makefile.common: set")
-       pkglist("ONLY_FOR_COMPILER", lkShell, enum("ccc clang gcc hp icc ido mipspro mipspro-ucode pcc sunpro xlc"))
+       pkglist("ONLY_FOR_COMPILER", lkShell, compilers)
        pkglist("ONLY_FOR_PLATFORM", lkSpace, BtMachinePlatformPattern)
        pkg("ONLY_FOR_UNPRIVILEGED", lkNone, BtYesNo)
        sys("OPSYS", lkNone, BtIdentifier)
@@ -844,7 +872,7 @@ func (src *Pkgsrc) InitVartypes() {
        pkg("PERL5_REQD", lkShell, BtVersion)
        pkg("PERL5_USE_PACKLIST", lkNone, BtYesNo)
        sys("PGSQL_PREFIX", lkNone, BtPathname)
-       acl("PGSQL_VERSIONS_ACCEPTED", lkShell, enumFrom("mk/pgsql.buildlink3.mk", "PGSQL_VERSIONS_ACCEPTED", "10 96 95 94 93"), "")
+       acl("PGSQL_VERSIONS_ACCEPTED", lkShell, pgsqlVersions, "")
        usr("PGSQL_VERSION_DEFAULT", lkNone, BtVersion)
        sys("PG_LIB_EXT", lkNone, enum("dylib so"))
        sys("PGSQL_TYPE", lkNone, enum("postgresql81-client postgresql80-client"))
@@ -924,7 +952,7 @@ func (src *Pkgsrc) InitVartypes() {
        acl("PKG_USERS", lkShell, BtShellWord, "Makefile: set, append")
        pkg("PKG_USERS_VARS", lkShell, BtVariableName)
        acl("PKG_USE_KERBEROS", lkNone, BtYes, "Makefile, Makefile.common: set")
-       // PLIST.* has special handling code
+       pkg("PLIST.*", lkNone, BtYes)
        pkglist("PLIST_VARS", lkShell, BtIdentifier)
        pkglist("PLIST_SRC", lkShell, BtRelativePkgPath)
        pkglist("PLIST_SUBST", lkShell, BtShellWord)

Index: pkgsrc/pkgtools/pkglint/files/vardefs_test.go
diff -u pkgsrc/pkgtools/pkglint/files/vardefs_test.go:1.1 pkgsrc/pkgtools/pkglint/files/vardefs_test.go:1.2
--- pkgsrc/pkgtools/pkglint/files/vardefs_test.go:1.1   Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/vardefs_test.go       Thu Aug 16 20:41:42 2018
@@ -8,14 +8,39 @@ func (s *Suite) Test_InitVartypes__enumF
        t.SetupFileMkLines("editors/emacs/modules.mk",
                MkRcsID,
                "",
-               "_EMACS_VERSIONS_ALL=\temacs31",
-               "_EMACS_VERSIONS_ALL=\tignored")
+               "_EMACS_VERSIONS_ALL=    emacs31",
+               "_EMACS_VERSIONS_ALL+=   emacs29")
+       t.SetupFileMkLines("mk/java-vm.mk",
+               MkRcsID,
+               "",
+               "_PKG_JVMS.8=            openjdk8 oracle-jdk8",
+               "_PKG_JVMS.7=            ${_PKG_JVMS.8} openjdk7 sun-jdk7",
+               "_PKG_JVMS.6=            ${_PKG_JVMS.7} sun-jdk6 jdk16")
+       t.SetupFileMkLines("mk/compiler.mk",
+               MkRcsID,
+               "",
+               "_COMPILERS=             gcc ido mipspro-ucode \\",
+               "                        sunpro",
+               "_PSEUDO_COMPILERS=          ccache distcc f2c g95",
+               "",
+               ".for _version_ in gnu++14 c++14 gnu++11 c++11 gnu++0x c++0x gnu++03 c++03",
+               ".  if !empty(USE_LANGUAGES:M${_version_})",
+               "USE_LANGUAGES+=                c++",
+               ".  endif",
+               ".endfor")
        mklines := t.SetupFileMkLines("Makefile",
                MkRcsID,
                "")
 
        t.SetupVartypes()
-       vartype := mklines.mklines[1].VariableType("EMACS_VERSIONS_ACCEPTED")
 
-       c.Check(vartype.String(), equals, "ShellList of enum: emacs31 ")
+       checkEnumValues := func(varname, values string) {
+               vartype := mklines.mklines[1].VariableType(varname).String()
+               c.Check(vartype, equals, values)
+       }
+
+       checkEnumValues("EMACS_VERSIONS_ACCEPTED", "ShellList of enum: emacs29 emacs31 ")
+       checkEnumValues("PKG_JVM", "enum: jdk16 openjdk7 openjdk8 oracle-jdk8 sun-jdk6 sun-jdk7 ")
+       checkEnumValues("USE_LANGUAGES", "ShellList of enum: ada c c++ c++03 c++0x c++11 c++14 c99 fortran fortran77 gnu++03 gnu++0x gnu++11 gnu++14 java obj-c++ objc ")
+       checkEnumValues("PKGSRC_COMPILER", "ShellList of enum: ccache distcc f2c g95 gcc ido mipspro-ucode sunpro ")
 }

Index: pkgsrc/pkgtools/pkglint/files/vartypecheck.go
diff -u pkgsrc/pkgtools/pkglint/files/vartypecheck.go:1.37 pkgsrc/pkgtools/pkglint/files/vartypecheck.go:1.38
--- pkgsrc/pkgtools/pkglint/files/vartypecheck.go:1.37  Sun Aug 12 16:31:56 2018
+++ pkgsrc/pkgtools/pkglint/files/vartypecheck.go       Thu Aug 16 20:41:42 2018
@@ -39,7 +39,7 @@ const (
        opAssignEval                      // :=
        opAssignAppend                    // +=
        opAssignDefault                   // ?=
-       opUseCompare                      // A variable is compared to a value, e.g. in a conditional.
+       opUseCompare                      // A variable is compared to a value, e.g. in a condition.
        opUseMatch                        // A variable is matched using the :M or :N modifier.
 )
 
@@ -1085,7 +1085,7 @@ func (cv *VartypeCheck) WrksrcSubdirecto
 func (cv *VartypeCheck) Yes() {
        switch cv.Op {
        case opUseMatch:
-               cv.Line.Warnf("%s should only be used in a \".if defined(...)\" conditional.", cv.Varname)
+               cv.Line.Warnf("%s should only be used in a \".if defined(...)\" condition.", cv.Varname)
                Explain(
                        "This variable can have only two values: defined or undefined.",
                        "When it is defined, it means \"yes\", even when its value is",

Index: pkgsrc/pkgtools/pkglint/files/regex/regex.go
diff -u pkgsrc/pkgtools/pkglint/files/regex/regex.go:1.2 pkgsrc/pkgtools/pkglint/files/regex/regex.go:1.3
--- pkgsrc/pkgtools/pkglint/files/regex/regex.go:1.2    Sun Oct  8 22:31:13 2017
+++ pkgsrc/pkgtools/pkglint/files/regex/regex.go        Thu Aug 16 20:41:42 2018
@@ -6,8 +6,8 @@ package regex
 
 import (
        "fmt"
+       "io"
        "netbsd.org/pkglint/histogram"
-       "os"
        "regexp"
        "time"
 )
@@ -19,16 +19,13 @@ var (
 )
 
 var (
-       res       map[Pattern]*regexp.Regexp
-       rematch   *histogram.Histogram
-       renomatch *histogram.Histogram
-       retime    *histogram.Histogram
+       res       = make(map[Pattern]*regexp.Regexp)
+       rematch   = histogram.New()
+       renomatch = histogram.New()
+       retime    = histogram.New()
 )
 
 func Compile(re Pattern) *regexp.Regexp {
-       if res == nil {
-               res = make(map[Pattern]*regexp.Regexp)
-       }
        cre := res[re]
        if cre == nil {
                cre = regexp.MustCompile(string(re))
@@ -50,12 +47,6 @@ func Match(s string, re Pattern) []strin
        delay := immediatelyBefore.UnixNano() - before.UnixNano()
        timeTaken := after.UnixNano() - immediatelyBefore.UnixNano() - delay
 
-       if retime == nil {
-               retime = histogram.New()
-               rematch = histogram.New()
-               renomatch = histogram.New()
-       }
-
        retime.Add(string(re), int(timeTaken))
        if m != nil {
                rematch.Add(string(re), 1)
@@ -124,11 +115,11 @@ func ReplaceFirst(s string, re Pattern, 
        return nil, s
 }
 
-func PrintStats() {
+func PrintStats(out io.Writer) {
        if Profiling {
-               rematch.PrintStats("rematch", os.Stdout, 10)
-               renomatch.PrintStats("renomatch", os.Stdout, 10)
-               retime.PrintStats("retime", os.Stdout, 10)
+               rematch.PrintStats("rematch", out, 10)
+               renomatch.PrintStats("renomatch", out, 10)
+               retime.PrintStats("retime", out, 10)
        }
 }
 



Home | Main Index | Thread Index | Old Index