pkgsrc-Changes archive

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

CVS commit: pkgsrc/pkgtools/pkglint/files



Module Name:    pkgsrc
Committed By:   rillig
Date:           Sun Jan 29 14:27:48 UTC 2017

Modified Files:
        pkgsrc/pkgtools/pkglint/files: buildlink3.go buildlink3_test.go
            category.go category_test.go check_test.go distinfo.go
            distinfo_test.go files.go files_test.go globaldata.go
            globaldata_test.go globalvars.go licenses.go licenses_test.go
            line.go line_test.go linechecker.go linechecker_test.go mkline.go
            mkline_test.go mklinechecker.go mklinechecker_test.go mklines.go
            mklines_test.go mkparser.go mkparser_test.go mkshparser.go
            package.go package_test.go parser.go patches.go patches_test.go
            pkglint.go pkglint_test.go plist.go plist_test.go shell.go
            shell_test.go shtokenizer.go shtokenizer_test.go substcontext.go
            substcontext_test.go toplevel.go toplevel_test.go util.go
            vardefs.go vartypecheck.go vartypecheck_test.go
Added Files:
        pkgsrc/pkgtools/pkglint/files/line: line.go
        pkgsrc/pkgtools/pkglint/files/textproc: expecter.go

Log Message:
Refactored the code into separate packages. No functional changes.


To generate a diff of this commit:
cvs rdiff -u -r1.9 -r1.10 pkgsrc/pkgtools/pkglint/files/buildlink3.go \
    pkgsrc/pkgtools/pkglint/files/distinfo_test.go \
    pkgsrc/pkgtools/pkglint/files/files_test.go \
    pkgsrc/pkgtools/pkglint/files/licenses.go \
    pkgsrc/pkgtools/pkglint/files/line_test.go \
    pkgsrc/pkgtools/pkglint/files/patches_test.go
cvs rdiff -u -r1.7 -r1.8 pkgsrc/pkgtools/pkglint/files/buildlink3_test.go \
    pkgsrc/pkgtools/pkglint/files/category.go \
    pkgsrc/pkgtools/pkglint/files/licenses_test.go \
    pkgsrc/pkgtools/pkglint/files/mkparser.go \
    pkgsrc/pkgtools/pkglint/files/parser.go \
    pkgsrc/pkgtools/pkglint/files/substcontext_test.go
cvs rdiff -u -r1.5 -r1.6 pkgsrc/pkgtools/pkglint/files/category_test.go \
    pkgsrc/pkgtools/pkglint/files/shtokenizer.go
cvs rdiff -u -r1.12 -r1.13 pkgsrc/pkgtools/pkglint/files/check_test.go \
    pkgsrc/pkgtools/pkglint/files/distinfo.go \
    pkgsrc/pkgtools/pkglint/files/mklines.go \
    pkgsrc/pkgtools/pkglint/files/mklines_test.go \
    pkgsrc/pkgtools/pkglint/files/plist.go \
    pkgsrc/pkgtools/pkglint/files/plist_test.go
cvs rdiff -u -r1.10 -r1.11 pkgsrc/pkgtools/pkglint/files/files.go \
    pkgsrc/pkgtools/pkglint/files/globaldata_test.go \
    pkgsrc/pkgtools/pkglint/files/pkglint_test.go
cvs rdiff -u -r1.19 -r1.20 pkgsrc/pkgtools/pkglint/files/globaldata.go
cvs rdiff -u -r1.6 -r1.7 pkgsrc/pkgtools/pkglint/files/globalvars.go \
    pkgsrc/pkgtools/pkglint/files/toplevel.go \
    pkgsrc/pkgtools/pkglint/files/toplevel_test.go
cvs rdiff -u -r1.14 -r1.15 pkgsrc/pkgtools/pkglint/files/line.go
cvs rdiff -u -r1.1 -r1.2 pkgsrc/pkgtools/pkglint/files/linechecker.go \
    pkgsrc/pkgtools/pkglint/files/linechecker_test.go \
    pkgsrc/pkgtools/pkglint/files/mklinechecker.go \
    pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go
cvs rdiff -u -r1.21 -r1.22 pkgsrc/pkgtools/pkglint/files/mkline.go \
    pkgsrc/pkgtools/pkglint/files/vardefs.go
cvs rdiff -u -r1.22 -r1.23 pkgsrc/pkgtools/pkglint/files/mkline_test.go
cvs rdiff -u -r1.4 -r1.5 pkgsrc/pkgtools/pkglint/files/mkparser_test.go \
    pkgsrc/pkgtools/pkglint/files/mkshparser.go \
    pkgsrc/pkgtools/pkglint/files/shtokenizer_test.go
cvs rdiff -u -r1.17 -r1.18 pkgsrc/pkgtools/pkglint/files/package.go \
    pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go
cvs rdiff -u -r1.13 -r1.14 pkgsrc/pkgtools/pkglint/files/package_test.go \
    pkgsrc/pkgtools/pkglint/files/patches.go \
    pkgsrc/pkgtools/pkglint/files/util.go
cvs rdiff -u -r1.18 -r1.19 pkgsrc/pkgtools/pkglint/files/pkglint.go
cvs rdiff -u -r1.15 -r1.16 pkgsrc/pkgtools/pkglint/files/shell.go \
    pkgsrc/pkgtools/pkglint/files/shell_test.go
cvs rdiff -u -r1.8 -r1.9 pkgsrc/pkgtools/pkglint/files/substcontext.go
cvs rdiff -u -r1.24 -r1.25 pkgsrc/pkgtools/pkglint/files/vartypecheck.go
cvs rdiff -u -r0 -r1.1 pkgsrc/pkgtools/pkglint/files/line/line.go
cvs rdiff -u -r0 -r1.1 pkgsrc/pkgtools/pkglint/files/textproc/expecter.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/files/buildlink3.go
diff -u pkgsrc/pkgtools/pkglint/files/buildlink3.go:1.9 pkgsrc/pkgtools/pkglint/files/buildlink3.go:1.10
--- pkgsrc/pkgtools/pkglint/files/buildlink3.go:1.9     Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/buildlink3.go Sun Jan 29 14:27:48 2017
@@ -1,7 +1,9 @@
 package main
 
 import (
+       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/pkgver"
+       "netbsd.org/pkglint/textproc"
        "netbsd.org/pkglint/trace"
        "strings"
 )
@@ -13,7 +15,7 @@ func ChecklinesBuildlink3Mk(mklines *MkL
 
        mklines.Check()
 
-       exp := NewExpecter(mklines.lines)
+       exp := textproc.NewExpecter(mklines.lines)
 
        for exp.AdvanceIfPrefix("#") {
                line := exp.PreviousLine()
@@ -23,7 +25,7 @@ func ChecklinesBuildlink3Mk(mklines *MkL
                }
        }
 
-       exp.ExpectEmptyLine()
+       exp.ExpectEmptyLine(G.opts.WarnSpace)
 
        if exp.AdvanceIfMatches(`^BUILDLINK_DEPMETHOD\.(\S+)\?=.*$`) {
                exp.PreviousLine().Warnf("This line belongs inside the .ifdef block.")
@@ -32,7 +34,7 @@ func ChecklinesBuildlink3Mk(mklines *MkL
        }
 
        pkgbaseLine, pkgbase := exp.CurrentLine(), ""
-       var abiLine, apiLine Line
+       var abiLine, apiLine line.Line
        var abi, api *DependencyPattern
 
        // First paragraph: Introduction of the package identifier
@@ -40,7 +42,7 @@ func ChecklinesBuildlink3Mk(mklines *MkL
                exp.CurrentLine().Warnf("Expected a BUILDLINK_TREE line.")
                return
        }
-       pkgbase = exp.m[1]
+       pkgbase = exp.Group(1)
        if containsVarRef(pkgbase) {
                warned := false
                for _, pair := range [...]struct{ varuse, simple string }{
@@ -70,19 +72,19 @@ func ChecklinesBuildlink3Mk(mklines *MkL
                }
        }
 
-       exp.ExpectEmptyLine()
+       exp.ExpectEmptyLine(G.opts.WarnSpace)
 
        // Second paragraph: multiple inclusion protection and introduction
        // of the uppercase package identifier.
        if !exp.AdvanceIfMatches(`^\.if !defined\((\S+)_BUILDLINK3_MK\)$`) {
                return
        }
-       pkgupperLine, pkgupper := exp.PreviousLine(), exp.m[1]
+       pkgupperLine, pkgupper := exp.PreviousLine(), exp.Group(1)
 
        if !exp.ExpectText(pkgupper + "_BUILDLINK3_MK:=") {
                return
        }
-       exp.ExpectEmptyLine()
+       exp.ExpectEmptyLine(G.opts.WarnSpace)
 
        // See pkgtools/createbuildlink/files/createbuildlink, keyword PKGUPPER
        ucPkgbase := strings.ToUpper(strings.Replace(pkgbase, "-", "_", -1))
@@ -93,7 +95,7 @@ func ChecklinesBuildlink3Mk(mklines *MkL
        if G.Pkg != nil {
                if mkbase := G.Pkg.EffectivePkgbase; mkbase != "" && mkbase != pkgbase {
                        pkgbaseLine.Errorf("Package name mismatch between %q in this file and %q from %s.",
-                               pkgbase, mkbase, G.Pkg.EffectivePkgnameLine.Line.ReferenceFrom(pkgbaseLine))
+                               pkgbase, mkbase, G.Pkg.EffectivePkgnameLine.ReferenceFrom(pkgbaseLine))
                }
        }
 
@@ -106,7 +108,7 @@ func ChecklinesBuildlink3Mk(mklines *MkL
                }
 
                line := exp.CurrentLine()
-               mkline := mklines.mklines[exp.index]
+               mkline := mklines.mklines[exp.Index()]
 
                if mkline.IsVarassign() {
                        exp.Advance()
@@ -185,7 +187,7 @@ func ChecklinesBuildlink3Mk(mklines *MkL
        if apiLine == nil {
                exp.CurrentLine().Warnf("Definition of BUILDLINK_API_DEPENDS is missing.")
        }
-       exp.ExpectEmptyLine()
+       exp.ExpectEmptyLine(G.opts.WarnSpace)
 
        // Fourth paragraph: Cleanup, corresponding to the first paragraph.
        if !exp.ExpectText("BUILDLINK_TREE+=\t-" + pkgbase) {
Index: pkgsrc/pkgtools/pkglint/files/distinfo_test.go
diff -u pkgsrc/pkgtools/pkglint/files/distinfo_test.go:1.9 pkgsrc/pkgtools/pkglint/files/distinfo_test.go:1.10
--- pkgsrc/pkgtools/pkglint/files/distinfo_test.go:1.9  Tue Dec 13 00:58:07 2016
+++ pkgsrc/pkgtools/pkglint/files/distinfo_test.go      Sun Jan 29 14:27:48 2017
@@ -22,14 +22,15 @@ func (s *Suite) Test_ChecklinesDistinfo(
                "SHA1 (patch-ab) = 6b98dd609f85a9eb9c4c1e4e7055a6aaa62b7cc7",
                "SHA1 (patch-nonexistent) = 1234"))
 
-       c.Check(s.Output(), equals, ""+
-               "ERROR: distinfo:1: Expected \"$"+"NetBSD$\".\n"+
-               "NOTE: distinfo:2: Empty line expected.\n"+
-               "ERROR: distinfo:5: Expected SHA1, RMD160, SHA512, Size checksums for \"distfile.tar.gz\", got MD5, SHA1.\n"+
-               "WARN: distinfo:7: Patch file \"patch-nonexistent\" does not exist in directory \"patches\".\n")
+       s.CheckOutputLines(
+               "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.",
+               "WARN: distinfo:7: Patch file \"patch-nonexistent\" does not exist in directory \"patches\".")
 }
 
 func (s *Suite) Test_ChecklinesDistinfo_global_hash_mismatch(c *check.C) {
+       s.Init(c)
        otherLine := NewLine("other/distinfo", 7, "dummy", nil)
        G.Hash = make(map[string]*Hash)
        G.Hash["SHA512:pkgname-1.0.tar.gz"] = &Hash{"asdfasdf", otherLine}
@@ -39,9 +40,9 @@ func (s *Suite) Test_ChecklinesDistinfo_
                "",
                "SHA512 (pkgname-1.0.tar.gz) = 12341234"))
 
-       c.Check(s.Output(), equals, ""+
-               "ERROR: distinfo:3: The hash SHA512 for pkgname-1.0.tar.gz is 12341234, which differs from asdfasdf in other/distinfo:7.\n"+
-               "ERROR: distinfo:EOF: Expected SHA1, RMD160, SHA512, Size checksums for \"pkgname-1.0.tar.gz\", got SHA512.\n")
+       s.CheckOutputLines(
+               "ERROR: distinfo:3: The hash SHA512 for pkgname-1.0.tar.gz is 12341234, which differs from asdfasdf in other/distinfo:7.",
+               "ERROR: distinfo:EOF: Expected SHA1, RMD160, SHA512, Size checksums for \"pkgname-1.0.tar.gz\", got SHA512.")
 }
 
 func (s *Suite) Test_ChecklinesDistinfo_uncommitted_patch(c *check.C) {
@@ -63,8 +64,8 @@ func (s *Suite) Test_ChecklinesDistinfo_
                "",
                "SHA1 (patch-aa) = 5ad1fb9b3c328fff5caa1a23e8f330e707dd50c0"))
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: ~/distinfo:3: patches/patch-aa is registered in distinfo but not added to CVS.\n")
+       s.CheckOutputLines(
+               "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) {
@@ -82,9 +83,9 @@ func (s *Suite) Test_ChecklinesDistinfo_
                "SHA512 (distfile.tar.gz) = ...",
                "Size (distfile.tar.gz) = 1024 bytes"))
 
-       c.Check(s.Output(), equals, ""+
-               "ERROR: ~/distinfo: patch \"patches/patch-aa\" is not recorded. Run \""+confMake+" makepatchsum\".\n"+
-               "ERROR: ~/distinfo: patch \"patches/patch-src-Makefile\" is not recorded. Run \""+confMake+" makepatchsum\".\n")
+       s.CheckOutputLines(
+               "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) {
@@ -97,6 +98,6 @@ func (s *Suite) Test_ChecklinesDistinfo_
                "",
                "SHA1 (patch-aa) = ..."))
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: ~/distinfo:3: Patch file \"patch-aa\" does not exist in directory \"patches\".\n")
+       s.CheckOutputLines(
+               "WARN: ~/distinfo:3: Patch file \"patch-aa\" does not exist in directory \"patches\".")
 }
Index: pkgsrc/pkgtools/pkglint/files/files_test.go
diff -u pkgsrc/pkgtools/pkglint/files/files_test.go:1.9 pkgsrc/pkgtools/pkglint/files/files_test.go:1.10
--- pkgsrc/pkgtools/pkglint/files/files_test.go:1.9     Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/files_test.go Sun Jan 29 14:27:48 2017
@@ -72,9 +72,9 @@ func (s *Suite) Test_show_autofix(c *che
 
        c.Check(lines[1].(*LineImpl).raw[0].textnl, equals, "XXXXX\n")
        c.Check(s.LoadTmpFile("Makefile"), equals, "line1\nline2\nline3\n")
-       c.Check(s.Output(), equals, ""+
-               "WARN: ~/Makefile:2: Something's wrong here.\n"+
-               "AUTOFIX: ~/Makefile:2: Replacing regular expression \".\" with \"X\".\n")
+       s.CheckOutputLines(
+               "WARN: ~/Makefile:2: Something's wrong here.",
+               "AUTOFIX: ~/Makefile:2: Replacing regular expression \".\" with \"X\".")
 }
 
 func (s *Suite) Test_autofix(c *check.C) {
@@ -92,7 +92,7 @@ func (s *Suite) Test_autofix(c *check.C)
        SaveAutofixChanges(lines)
 
        c.Check(s.LoadTmpFile("Makefile"), equals, "line1\nXXXXX\nline3\n")
-       c.Check(s.Output(), equals, ""+
-               "AUTOFIX: ~/Makefile:2: Replacing regular expression \".\" with \"X\".\n"+
-               "AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.\n")
+       s.CheckOutputLines(
+               "AUTOFIX: ~/Makefile:2: Replacing regular expression \".\" with \"X\".",
+               "AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.")
 }
Index: pkgsrc/pkgtools/pkglint/files/licenses.go
diff -u pkgsrc/pkgtools/pkglint/files/licenses.go:1.9 pkgsrc/pkgtools/pkglint/files/licenses.go:1.10
--- pkgsrc/pkgtools/pkglint/files/licenses.go:1.9       Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/licenses.go   Sun Jan 29 14:27:48 2017
@@ -24,7 +24,7 @@ func checkToplevelUnusedLicenses() {
 }
 
 type LicenseChecker struct {
-       MkLine *MkLine
+       MkLine MkLine
 }
 
 func (lc *LicenseChecker) Check(value string, op MkOperator) {
@@ -47,7 +47,7 @@ func (lc *LicenseChecker) checkLicenseNa
        var licenseFile string
        if G.Pkg != nil {
                if licenseFileValue, ok := G.Pkg.varValue("LICENSE_FILE"); ok {
-                       licenseFile = G.CurrentDir + "/" + lc.MkLine.resolveVarsInRelativePath(licenseFileValue, false)
+                       licenseFile = G.CurrentDir + "/" + lc.MkLine.ResolveVarsInRelativePath(licenseFileValue, false)
                }
        }
        if licenseFile == "" {
Index: pkgsrc/pkgtools/pkglint/files/line_test.go
diff -u pkgsrc/pkgtools/pkglint/files/line_test.go:1.9 pkgsrc/pkgtools/pkglint/files/line_test.go:1.10
--- pkgsrc/pkgtools/pkglint/files/line_test.go:1.9      Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/line_test.go  Sun Jan 29 14:27:48 2017
@@ -66,14 +66,14 @@ func (s *Suite) Test_Line_show_autofix_A
                line.Warnf("Using \"old\" is deprecated.")
        }
 
-       c.Check(s.Output(), equals, ""+
-               "\n"+
-               "> before\n"+
-               "- The old song\n"+
-               "+ The new song\n"+
-               "> after\n"+
-               "WARN: Makefile:27--29: Using \"old\" is deprecated.\n"+
-               "AUTOFIX: Makefile:27--29: Replacing \"old\" with \"new\".\n")
+       s.CheckOutputLines(
+               "",
+               "> before",
+               "- The old song",
+               "+ The new song",
+               "> after",
+               "WARN: Makefile:27--29: Using \"old\" is deprecated.",
+               "AUTOFIX: Makefile:27--29: Replacing \"old\" with \"new\".")
 }
 
 func (s *Suite) Test_Line_show_autofix_AutofixInsertBefore(c *check.C) {
@@ -85,12 +85,12 @@ func (s *Suite) Test_Line_show_autofix_A
                line.Warnf("Dummy")
        }
 
-       c.Check(s.Output(), equals, ""+
-               "\n"+
-               "+ inserted\n"+
-               "> original\n"+
-               "WARN: Makefile:30: Dummy\n"+
-               "AUTOFIX: Makefile:30: Inserting a line \"inserted\" before this line.\n")
+       s.CheckOutputLines(
+               "",
+               "+ inserted",
+               "> original",
+               "WARN: Makefile:30: Dummy",
+               "AUTOFIX: Makefile:30: Inserting a line \"inserted\" before this line.")
 }
 
 func (s *Suite) Test_Line_show_autofix_AutofixDelete(c *check.C) {
@@ -102,9 +102,9 @@ func (s *Suite) Test_Line_show_autofix_A
                line.Warnf("Dummy")
        }
 
-       c.Check(s.Output(), equals, ""+
-               "\n"+
-               "- to be deleted\n"+
-               "WARN: Makefile:30: Dummy\n"+
-               "AUTOFIX: Makefile:30: Deleting this line.\n")
+       s.CheckOutputLines(
+               "",
+               "- to be deleted",
+               "WARN: Makefile:30: Dummy",
+               "AUTOFIX: Makefile:30: Deleting this line.")
 }
Index: pkgsrc/pkgtools/pkglint/files/patches_test.go
diff -u pkgsrc/pkgtools/pkglint/files/patches_test.go:1.9 pkgsrc/pkgtools/pkglint/files/patches_test.go:1.10
--- pkgsrc/pkgtools/pkglint/files/patches_test.go:1.9   Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/patches_test.go       Sun Jan 29 14:27:48 2017
@@ -24,7 +24,7 @@ func (s *Suite) Test_ChecklinesPatch__wi
 
        ChecklinesPatch(lines)
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_ChecklinesPatch__without_empty_line(c *check.C) {
@@ -44,10 +44,10 @@ func (s *Suite) Test_ChecklinesPatch__wi
 
        ChecklinesPatch(lines)
 
-       c.Check(s.Output(), equals, ""+
-               "AUTOFIX: ~/patch-WithoutEmptyLines:2: Inserting a line \"\" before this line.\n"+
-               "AUTOFIX: ~/patch-WithoutEmptyLines:3: Inserting a line \"\" before this line.\n"+
-               "AUTOFIX: ~/patch-WithoutEmptyLines: Has been auto-fixed. Please re-run pkglint.\n")
+       s.CheckOutputLines(
+               "AUTOFIX: ~/patch-WithoutEmptyLines:2: Inserting a line \"\" before this line.",
+               "AUTOFIX: ~/patch-WithoutEmptyLines:3: Inserting a line \"\" before this line.",
+               "AUTOFIX: ~/patch-WithoutEmptyLines: Has been auto-fixed. Please re-run pkglint.")
 
        fixed, err := ioutil.ReadFile(fname)
        c.Assert(err, check.IsNil)
@@ -81,7 +81,8 @@ func (s *Suite) Test_ChecklinesPatch__wi
 
        ChecklinesPatch(lines)
 
-       c.Check(s.Output(), equals, "ERROR: patch-WithoutComment:3: Each patch must be documented.\n")
+       s.CheckOutputLines(
+               "ERROR: patch-WithoutComment:3: Each patch must be documented.")
 }
 
 func (s *Suite) Test_ChecklinesPatch__git_without_comment(c *check.C) {
@@ -100,15 +101,17 @@ func (s *Suite) Test_ChecklinesPatch__gi
 
        ChecklinesPatch(lines)
 
-       c.Check(s.Output(), equals, "ERROR: patch-aa:5: Each patch must be documented.\n")
+       s.CheckOutputLines(
+               "ERROR: patch-aa:5: Each patch must be documented.")
 }
 
 func (s *Suite) Test_checklineOtherAbsolutePathname(c *check.C) {
+       s.Init(c)
        line := NewLine("patch-ag", 1, "+$install -s -c ./bin/rosegarden ${DESTDIR}$BINDIR", nil)
 
        checklineOtherAbsolutePathname(line, line.Text())
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_ChecklinesPatch__error_code(c *check.C) {
@@ -129,7 +132,7 @@ func (s *Suite) Test_ChecklinesPatch__er
 
        ChecklinesPatch(lines)
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_ChecklinesPatch__wrong_header_order(c *check.C) {
@@ -151,7 +154,8 @@ func (s *Suite) Test_ChecklinesPatch__wr
 
        ChecklinesPatch(lines)
 
-       c.Check(s.Output(), equals, "WARN: patch-WrongOrder:7: Unified diff headers should be first ---, then +++.\n")
+       s.CheckOutputLines(
+               "WARN: patch-WrongOrder:7: Unified diff headers should be first ---, then +++.")
 }
 
 func (s *Suite) Test_ChecklinesPatch__context_diff(c *check.C) {
@@ -166,12 +170,13 @@ func (s *Suite) Test_ChecklinesPatch__co
 
        ChecklinesPatch(lines)
 
-       c.Check(s.Output(), equals, ""+
-               "ERROR: patch-ctx:4: Each patch must be documented.\n"+
-               "WARN: patch-ctx:4: Please use unified diffs (diff -u) for patches.\n")
+       s.CheckOutputLines(
+               "ERROR: patch-ctx:4: Each patch must be documented.",
+               "WARN: patch-ctx:4: Please use unified diffs (diff -u) for patches.")
 }
 
 func (s *Suite) Test_ChecklinesPatch__no_patch(c *check.C) {
+       s.Init(c)
        lines := s.NewLines("patch-aa",
                "$"+"NetBSD$",
                "",
@@ -180,10 +185,12 @@ func (s *Suite) Test_ChecklinesPatch__no
 
        ChecklinesPatch(lines)
 
-       c.Check(s.Output(), equals, "ERROR: patch-aa: Contains no patch.\n")
+       s.CheckOutputLines(
+               "ERROR: patch-aa: Contains no patch.")
 }
 
 func (s *Suite) Test_ChecklinesPatch__two_patched_files(c *check.C) {
+       s.Init(c)
        lines := s.NewLines("patch-aa",
                "$"+"NetBSD$",
                "",
@@ -200,12 +207,13 @@ func (s *Suite) Test_ChecklinesPatch__tw
 
        ChecklinesPatch(lines)
 
-       c.Check(s.Output(), equals, ""+
-               "ERROR: patch-aa:3: Each patch must be documented.\n"+
-               "WARN: patch-aa: Contains patches for 2 files, should be only one.\n")
+       s.CheckOutputLines(
+               "ERROR: patch-aa:3: Each patch must be documented.",
+               "WARN: patch-aa: Contains patches for 2 files, should be only one.")
 }
 
 func (s *Suite) Test_ChecklinesPatch__documentation_that_looks_like_patch_lines(c *check.C) {
+       s.Init(c)
        lines := s.NewLines("patch-aa",
                "$"+"NetBSD$",
                "",
@@ -217,10 +225,12 @@ func (s *Suite) Test_ChecklinesPatch__do
 
        ChecklinesPatch(lines)
 
-       c.Check(s.Output(), equals, "ERROR: patch-aa: Contains no patch.\n")
+       s.CheckOutputLines(
+               "ERROR: patch-aa: Contains no patch.")
 }
 
 func (s *Suite) Test_ChecklinesPatch__only_unified_header_but_no_content(c *check.C) {
+       s.Init(c)
        lines := s.NewLines("patch-unified",
                "$"+"NetBSD$",
                "",
@@ -231,10 +241,12 @@ func (s *Suite) Test_ChecklinesPatch__on
 
        ChecklinesPatch(lines)
 
-       c.Check(s.Output(), equals, "ERROR: patch-unified:EOF: No patch hunks for \"file\".\n")
+       s.CheckOutputLines(
+               "ERROR: patch-unified:EOF: No patch hunks for \"file\".")
 }
 
 func (s *Suite) Test_ChecklinesPatch__only_context_header_but_no_content(c *check.C) {
+       s.Init(c)
        lines := s.NewLines("patch-context",
                "$"+"NetBSD$",
                "",
@@ -247,10 +259,12 @@ func (s *Suite) Test_ChecklinesPatch__on
 
        // Context diffs are deprecated, therefore it is not worth
        // adding extra code for checking them thoroughly.
-       c.Check(s.Output(), equals, "WARN: patch-context:5: Please use unified diffs (diff -u) for patches.\n")
+       s.CheckOutputLines(
+               "WARN: patch-context:5: Please use unified diffs (diff -u) for patches.")
 }
 
 func (s *Suite) Test_ChecklinesPatch__Makefile_with_absolute_pathnames(c *check.C) {
+       s.Init(c)
        lines := s.NewLines("patch-unified",
                "$"+"NetBSD$",
                "",
@@ -270,22 +284,23 @@ func (s *Suite) Test_ChecklinesPatch__Ma
 
        ChecklinesPatch(lines)
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: patch-unified:10: Found absolute pathname: /bin/cp\n"+
-               "WARN: patch-unified:13: Found absolute pathname: /bin/cp\n")
+       s.CheckOutputLines(
+               "WARN: patch-unified:10: Found absolute pathname: /bin/cp",
+               "WARN: patch-unified:13: Found absolute pathname: /bin/cp")
 
        G.opts.WarnExtra = true
 
        ChecklinesPatch(lines)
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: patch-unified:8: Found absolute pathname: /bin/cp\n"+
-               "WARN: patch-unified:10: Found absolute pathname: /bin/cp\n"+
-               "WARN: patch-unified:13: Found absolute pathname: /bin/cp\n"+
-               "WARN: patch-unified:15: Found absolute pathname: /bin/cp\n")
+       s.CheckOutputLines(
+               "WARN: patch-unified:8: Found absolute pathname: /bin/cp",
+               "WARN: patch-unified:10: Found absolute pathname: /bin/cp",
+               "WARN: patch-unified:13: Found absolute pathname: /bin/cp",
+               "WARN: patch-unified:15: Found absolute pathname: /bin/cp")
 }
 
 func (s *Suite) Test_ChecklinesPatch__no_newline_with_text_following(c *check.C) {
+       s.Init(c)
        lines := s.NewLines("patch-aa",
                "$"+"NetBSD$",
                "",
@@ -302,10 +317,12 @@ func (s *Suite) Test_ChecklinesPatch__no
 
        ChecklinesPatch(lines)
 
-       c.Check(s.Output(), equals, "WARN: patch-aa:12: Empty line or end of file expected.\n")
+       s.CheckOutputLines(
+               "WARN: patch-aa:12: Empty line or end of file expected.")
 }
 
 func (s *Suite) Test_ChecklinesPatch__no_newline(c *check.C) {
+       s.Init(c)
        lines := s.NewLines("patch-aa",
                "$"+"NetBSD$",
                "",
@@ -321,10 +338,11 @@ func (s *Suite) Test_ChecklinesPatch__no
 
        ChecklinesPatch(lines)
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_ChecklinesPatch__empty_lines_left_out_at_eof(c *check.C) {
+       s.Init(c)
        lines := s.NewLines("patch-aa",
                "$"+"NetBSD$",
                "",
@@ -342,12 +360,13 @@ func (s *Suite) Test_ChecklinesPatch__em
 
        ChecklinesPatch(lines)
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
 
 // In some context lines, the leading space character is missing.
 // Since this is no problem for patch(1), pkglint also doesn't complain.
 func (s *Suite) Test_ChecklinesPatch__context_lines_with_tab_instead_of_space(c *check.C) {
+       s.Init(c)
        lines := s.NewLines("patch-aa",
                "$"+"NetBSD$",
                "",
@@ -363,5 +382,5 @@ func (s *Suite) Test_ChecklinesPatch__co
 
        ChecklinesPatch(lines)
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }

Index: pkgsrc/pkgtools/pkglint/files/buildlink3_test.go
diff -u pkgsrc/pkgtools/pkglint/files/buildlink3_test.go:1.7 pkgsrc/pkgtools/pkglint/files/buildlink3_test.go:1.8
--- pkgsrc/pkgtools/pkglint/files/buildlink3_test.go:1.7        Sun Dec  4 15:28:36 2016
+++ pkgsrc/pkgtools/pkglint/files/buildlink3_test.go    Sun Jan 29 14:27:48 2017
@@ -5,6 +5,7 @@ import (
 )
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk(c *check.C) {
+       s.Init(c)
        G.globalData.InitVartypes()
        mklines := s.NewMkLines("buildlink3.mk",
                mkrcsid,
@@ -27,17 +28,18 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       c.Check(s.Output(), equals, ""+
-               "ERROR: buildlink3.mk:12: \"/x11/Xbae\" does not exist.\n"+
-               "ERROR: buildlink3.mk:12: There is no package in \"x11/Xbae\".\n"+
-               "ERROR: buildlink3.mk:14: \"/mk/motif.buildlink3.mk\" does not exist.\n"+
-               "ERROR: buildlink3.mk:2: This comment indicates unfinished work (url2pkg).\n")
+       s.CheckOutputLines(
+               "ERROR: buildlink3.mk:12: \"/x11/Xbae\" does not exist.",
+               "ERROR: buildlink3.mk:12: There is no package in \"x11/Xbae\".",
+               "ERROR: buildlink3.mk:14: \"/mk/motif.buildlink3.mk\" does not exist.",
+               "ERROR: buildlink3.mk:2: This comment indicates unfinished work (url2pkg).")
 }
 
 // Before version 5.3, pkglint wrongly warned here.
 // The mk/haskell.mk file takes care of constructing the correct PKGNAME,
 // but pkglint had not looked at that file.
 func (s *Suite) Test_ChecklinesBuildlink3Mk_name_mismatch(c *check.C) {
+       s.Init(c)
        G.globalData.InitVartypes()
        G.Pkg = NewPackage("x11/hs-X11")
        G.Pkg.EffectivePkgbase = "X11"
@@ -59,10 +61,12 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       c.Check(s.Output(), equals, "ERROR: buildlink3.mk:3: Package name mismatch between \"hs-X11\" in this file and \"X11\" from Makefile:3.\n")
+       s.CheckOutputLines(
+               "ERROR: buildlink3.mk:3: Package name mismatch between \"hs-X11\" in this file and \"X11\" from Makefile:3.")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_name_mismatch_multiple_inclusion(c *check.C) {
+       s.Init(c)
        G.globalData.InitVartypes()
        mklines := s.NewMkLines("buildlink3.mk",
                mkrcsid,
@@ -78,12 +82,13 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       c.Check(s.Output(), equals, ""+
-               "ERROR: buildlink3.mk:5: Package name mismatch between multiple-inclusion guard \"PKGBASE2\" (expected \"PKGBASE1\") and package name \"pkgbase1\" (from line 3).\n"+
-               "WARN: buildlink3.mk:9: Definition of BUILDLINK_API_DEPENDS is missing.\n")
+       s.CheckOutputLines(
+               "ERROR: buildlink3.mk:5: Package name mismatch between multiple-inclusion guard \"PKGBASE2\" (expected \"PKGBASE1\") and package name \"pkgbase1\" (from line 3).",
+               "WARN: buildlink3.mk:9: Definition of BUILDLINK_API_DEPENDS is missing.")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_name_mismatch_abi_api(c *check.C) {
+       s.Init(c)
        G.globalData.InitVartypes()
        mklines := s.NewMkLines("buildlink3.mk",
                mkrcsid,
@@ -102,10 +107,12 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       c.Check(s.Output(), equals, "WARN: buildlink3.mk:9: Package name mismatch between ABI \"hs-X12\" and API \"hs-X11\" (from line 8).\n")
+       s.CheckOutputLines(
+               "WARN: buildlink3.mk:9: Package name mismatch between ABI \"hs-X12\" and API \"hs-X11\" (from line 8).")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_abi_api_versions(c *check.C) {
+       s.Init(c)
        G.globalData.InitVartypes()
        mklines := s.NewMkLines("buildlink3.mk",
                mkrcsid,
@@ -124,11 +131,12 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: buildlink3.mk:9: ABI version \"1.6.0\" should be at least API version \"1.6.1\" (see line 8).\n")
+       s.CheckOutputLines(
+               "WARN: buildlink3.mk:9: ABI version \"1.6.0\" should be at least API version \"1.6.1\" (see line 8).")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_no_BUILDLINK_TREE_at_beginning(c *check.C) {
+       s.Init(c)
        G.globalData.InitVartypes()
        mklines := s.NewMkLines("buildlink3.mk",
                mkrcsid,
@@ -146,10 +154,12 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       c.Check(s.Output(), equals, "WARN: buildlink3.mk:3: Expected a BUILDLINK_TREE line.\n")
+       s.CheckOutputLines(
+               "WARN: buildlink3.mk:3: Expected a BUILDLINK_TREE line.")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_no_BUILDLINK_TREE_at_end(c *check.C) {
+       s.Init(c)
        G.globalData.InitVartypes()
        mklines := s.NewMkLines("buildlink3.mk",
                mkrcsid,
@@ -171,12 +181,13 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: buildlink3.mk:3: This line belongs inside the .ifdef block.\n"+
-               "WARN: buildlink3.mk:15: This line should contain the following text: BUILDLINK_TREE+=\t-hs-X11\n")
+       s.CheckOutputLines(
+               "WARN: buildlink3.mk:3: This line belongs inside the .ifdef block.",
+               "WARN: buildlink3.mk:15: This line should contain the following text: BUILDLINK_TREE+=\t-hs-X11")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_multiple_inclusion_wrong(c *check.C) {
+       s.Init(c)
        G.globalData.InitVartypes()
        mklines := s.NewMkLines("buildlink3.mk",
                mkrcsid,
@@ -188,12 +199,13 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: buildlink3.mk:6: UNRELATED_BUILDLINK3_MK is defined but not used. Spelling mistake?\n"+
-               "WARN: buildlink3.mk:6: This line should contain the following text: HS_X11_BUILDLINK3_MK:=\n")
+       s.CheckOutputLines(
+               "WARN: buildlink3.mk:6: UNRELATED_BUILDLINK3_MK is defined but not used. Spelling mistake?",
+               "WARN: buildlink3.mk:6: This line should contain the following text: HS_X11_BUILDLINK3_MK:=")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_missing_endif(c *check.C) {
+       s.Init(c)
        G.globalData.InitVartypes()
        mklines := s.NewMkLines("buildlink3.mk",
                mkrcsid,
@@ -205,10 +217,12 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       c.Check(s.Output(), equals, "WARN: buildlink3.mk:EOF: Expected .endif\n")
+       s.CheckOutputLines(
+               "WARN: buildlink3.mk:EOF: Expected .endif")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_unknown_dependency_patterns(c *check.C) {
+       s.Init(c)
        G.globalData.InitVartypes()
        mklines := s.NewMkLines("buildlink3.mk",
                mkrcsid,
@@ -228,12 +242,13 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: buildlink3.mk:9: Unknown dependency pattern \"hs-X11!=1.6.1\".\n"+
-               "WARN: buildlink3.mk:10: Unknown dependency pattern \"hs-X11!=1.6.1.2nb2\".\n")
+       s.CheckOutputLines(
+               "WARN: buildlink3.mk:9: Unknown dependency pattern \"hs-X11!=1.6.1\".",
+               "WARN: buildlink3.mk:10: Unknown dependency pattern \"hs-X11!=1.6.1.2nb2\".")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_PKGBASE_with_variable(c *check.C) {
+       s.Init(c)
        G.globalData.InitVartypes()
        mklines := s.NewMkLines("buildlink3.mk",
                mkrcsid,
@@ -252,10 +267,12 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       c.Check(s.Output(), equals, "WARN: buildlink3.mk:3: Please use \"py\" instead of \"${PYPKGPREFIX}\" (also in other variables in this file).\n")
+       s.CheckOutputLines(
+               "WARN: buildlink3.mk:3: Please use \"py\" instead of \"${PYPKGPREFIX}\" (also in other variables in this file).")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_PKGBASE_with_unknown_variable(c *check.C) {
+       s.Init(c)
        G.globalData.InitVartypes()
        mklines := s.NewMkLines("buildlink3.mk",
                mkrcsid,
@@ -274,7 +291,7 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: buildlink3.mk:3: Please replace \"${LICENSE}\" with a simple string (also in other variables in this file).\n"+
-               "WARN: buildlink3.mk:13: This line should contain the following text: BUILDLINK_TREE+=\t-${LICENSE}-wxWidgets\n")
+       s.CheckOutputLines(
+               "WARN: buildlink3.mk:3: Please replace \"${LICENSE}\" with a simple string (also in other variables in this file).",
+               "WARN: buildlink3.mk:13: This line should contain the following text: BUILDLINK_TREE+=\t-${LICENSE}-wxWidgets")
 }
Index: pkgsrc/pkgtools/pkglint/files/category.go
diff -u pkgsrc/pkgtools/pkglint/files/category.go:1.7 pkgsrc/pkgtools/pkglint/files/category.go:1.8
--- pkgsrc/pkgtools/pkglint/files/category.go:1.7       Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/category.go   Sun Jan 29 14:27:48 2017
@@ -1,6 +1,8 @@
 package main
 
 import (
+       "netbsd.org/pkglint/line"
+       "netbsd.org/pkglint/textproc"
        "netbsd.org/pkglint/trace"
        "sort"
 )
@@ -18,21 +20,21 @@ func CheckdirCategory() {
        mklines := NewMkLines(lines)
        mklines.Check()
 
-       exp := NewExpecter(lines)
+       exp := textproc.NewExpecter(lines)
        for exp.AdvanceIfPrefix("#") {
        }
-       exp.ExpectEmptyLine()
+       exp.ExpectEmptyLine(G.opts.WarnSpace)
 
        if exp.AdvanceIfMatches(`^COMMENT=\t*(.*)`) {
-               MkLineChecker{mklines.mklines[exp.index-1]}.CheckValidCharactersInValue(`[- '(),/0-9A-Za-z]`)
+               MkLineChecker{mklines.mklines[exp.Index()-1]}.CheckValidCharactersInValue(`[- '(),/0-9A-Za-z]`)
        } else {
                exp.CurrentLine().Errorf("COMMENT= line expected.")
        }
-       exp.ExpectEmptyLine()
+       exp.ExpectEmptyLine(G.opts.WarnSpace)
 
        type subdir struct {
                name   string
-               line   Line
+               line   line.Line
                active bool
        }
 
@@ -96,7 +98,7 @@ func CheckdirCategory() {
 
        var subdirs []string
 
-       var line Line
+       var line line.Line
        mActive := false
 
        for !(mAtend && fAtend) {
@@ -153,10 +155,10 @@ func CheckdirCategory() {
        // the pkgsrc-wip category Makefile defines its own targets for
        // generating indexes and READMEs. Just skip them.
        if G.Wip {
-               exp.index = len(exp.lines) - 2
+               exp.SkipToFooter()
        }
 
-       exp.ExpectEmptyLine()
+       exp.ExpectEmptyLine(G.opts.WarnSpace)
        exp.ExpectText(".include \"../mk/misc/category.mk\"")
        if !exp.EOF() {
                exp.CurrentLine().Errorf("The file should end here.")
Index: pkgsrc/pkgtools/pkglint/files/licenses_test.go
diff -u pkgsrc/pkgtools/pkglint/files/licenses_test.go:1.7 pkgsrc/pkgtools/pkglint/files/licenses_test.go:1.8
--- pkgsrc/pkgtools/pkglint/files/licenses_test.go:1.7  Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/licenses_test.go      Sun Jan 29 14:27:48 2017
@@ -14,29 +14,32 @@ func (s *Suite) Test_checklineLicense(c 
        licenseChecker := &LicenseChecker{mkline}
        licenseChecker.Check("gpl-v2", opAssign)
 
-       c.Check(s.Output(), equals, "WARN: Makefile:7: License file ~/licenses/gpl-v2 does not exist.\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:7: License file ~/licenses/gpl-v2 does not exist.")
 
        licenseChecker.Check("no-profit shareware", opAssign)
 
-       c.Check(s.Output(), equals, "ERROR: Makefile:7: Parse error for license condition \"no-profit shareware\".\n")
+       s.CheckOutputLines(
+               "ERROR: Makefile:7: Parse error for license condition \"no-profit shareware\".")
 
        licenseChecker.Check("no-profit AND shareware", opAssign)
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: Makefile:7: License file ~/licenses/no-profit does not exist.\n"+
-               "ERROR: Makefile:7: License \"no-profit\" must not be used.\n"+
-               "WARN: Makefile:7: License file ~/licenses/shareware does not exist.\n"+
-               "ERROR: Makefile:7: License \"shareware\" must not be used.\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:7: License file ~/licenses/no-profit does not exist.",
+               "ERROR: Makefile:7: License \"no-profit\" must not be used.",
+               "WARN: Makefile:7: License file ~/licenses/shareware does not exist.",
+               "ERROR: Makefile:7: License \"shareware\" must not be used.")
 
        licenseChecker.Check("gnu-gpl-v2", opAssign)
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 
        licenseChecker.Check("gnu-gpl-v2 AND gnu-gpl-v2 OR gnu-gpl-v2", opAssign)
 
-       c.Check(s.Output(), equals, "ERROR: Makefile:7: AND and OR operators in license conditions can only be combined using parentheses.\n")
+       s.CheckOutputLines(
+               "ERROR: Makefile:7: AND and OR operators in license conditions can only be combined using parentheses.")
 
        licenseChecker.Check("(gnu-gpl-v2 OR gnu-gpl-v2) AND gnu-gpl-v2", opAssign)
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
Index: pkgsrc/pkgtools/pkglint/files/mkparser.go
diff -u pkgsrc/pkgtools/pkglint/files/mkparser.go:1.7 pkgsrc/pkgtools/pkglint/files/mkparser.go:1.8
--- pkgsrc/pkgtools/pkglint/files/mkparser.go:1.7       Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/mkparser.go   Sun Jan 29 14:27:48 2017
@@ -1,6 +1,7 @@
 package main
 
 import (
+       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
        "strings"
@@ -10,7 +11,7 @@ type MkParser struct {
        *Parser
 }
 
-func NewMkParser(line Line, text string, emitWarnings bool) *MkParser {
+func NewMkParser(line line.Line, text string, emitWarnings bool) *MkParser {
        return &MkParser{NewParser(line, text, emitWarnings)}
 }
 
Index: pkgsrc/pkgtools/pkglint/files/parser.go
diff -u pkgsrc/pkgtools/pkglint/files/parser.go:1.7 pkgsrc/pkgtools/pkglint/files/parser.go:1.8
--- pkgsrc/pkgtools/pkglint/files/parser.go:1.7 Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/parser.go     Sun Jan 29 14:27:48 2017
@@ -1,17 +1,18 @@
 package main
 
 import (
+       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/textproc"
        "strings"
 )
 
 type Parser struct {
-       Line         Line
+       Line         line.Line
        repl         *textproc.PrefixReplacer
        EmitWarnings bool
 }
 
-func NewParser(line Line, s string, emitWarnings bool) *Parser {
+func NewParser(line line.Line, s string, emitWarnings bool) *Parser {
        return &Parser{line, textproc.NewPrefixReplacer(s), emitWarnings}
 }
 
Index: pkgsrc/pkgtools/pkglint/files/substcontext_test.go
diff -u pkgsrc/pkgtools/pkglint/files/substcontext_test.go:1.7 pkgsrc/pkgtools/pkglint/files/substcontext_test.go:1.8
--- pkgsrc/pkgtools/pkglint/files/substcontext_test.go:1.7      Tue Dec 13 00:58:07 2016
+++ pkgsrc/pkgtools/pkglint/files/substcontext_test.go  Sun Jan 29 14:27:48 2017
@@ -5,6 +5,7 @@ import (
 )
 
 func (s *Suite) Test_SubstContext__incomplete(c *check.C) {
+       s.Init(c)
        G.opts.WarnExtra = true
        ctx := new(SubstContext)
 
@@ -26,10 +27,12 @@ func (s *Suite) Test_SubstContext__incom
 
        ctx.Finish(newSubstLine(14, ""))
 
-       c.Check(s.Output(), equals, "WARN: Makefile:14: Incomplete SUBST block: SUBST_STAGE.interp missing.\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:14: Incomplete SUBST block: SUBST_STAGE.interp missing.")
 }
 
 func (s *Suite) Test_SubstContext__complete(c *check.C) {
+       s.Init(c)
        G.opts.WarnExtra = true
        ctx := new(SubstContext)
 
@@ -46,10 +49,11 @@ func (s *Suite) Test_SubstContext__compl
 
        ctx.Finish(newSubstLine(15, ""))
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_SubstContext__OPSYSVARS(c *check.C) {
+       s.Init(c)
        G.opts.WarnExtra = true
        ctx := new(SubstContext)
 
@@ -63,7 +67,7 @@ func (s *Suite) Test_SubstContext__OPSYS
 
        ctx.Finish(newSubstLine(15, ""))
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_SubstContext__no_class(c *check.C) {
@@ -76,11 +80,11 @@ func (s *Suite) Test_SubstContext__no_cl
        ctx.Varassign(newSubstLine(12, "SUBST_SED.repl+=-e s,from,to,g"))
        ctx.Finish(newSubstLine(13, ""))
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: Makefile:11: SUBST_CLASSES should come before the definition of \"SUBST_FILES.repl\".\n"+
-               "WARN: Makefile:13: Incomplete SUBST block: SUBST_STAGE.repl missing.\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:11: SUBST_CLASSES should come before the definition of \"SUBST_FILES.repl\".",
+               "WARN: Makefile:13: Incomplete SUBST block: SUBST_STAGE.repl missing.")
 }
 
-func newSubstLine(lineno int, text string) *MkLine {
+func newSubstLine(lineno int, text string) MkLine {
        return NewMkLine(NewLine("Makefile", lineno, text, nil))
 }

Index: pkgsrc/pkgtools/pkglint/files/category_test.go
diff -u pkgsrc/pkgtools/pkglint/files/category_test.go:1.5 pkgsrc/pkgtools/pkglint/files/category_test.go:1.6
--- pkgsrc/pkgtools/pkglint/files/category_test.go:1.5  Sun Jan  1 15:15:47 2017
+++ pkgsrc/pkgtools/pkglint/files/category_test.go      Sun Jan 29 14:27:48 2017
@@ -51,5 +51,6 @@ func (s *Suite) Test_CheckdirCategory_in
 
        CheckdirCategory()
 
-       c.Check(s.Output(), equals, "WARN: ~/archivers/Makefile:2: COMMENT contains invalid characters (U+005C U+0024 U+0024 U+0024 U+0024 U+0022).\n")
+       s.CheckOutputLines(
+               "WARN: ~/archivers/Makefile:2: COMMENT contains invalid characters (U+005C U+0024 U+0024 U+0024 U+0024 U+0022).")
 }
Index: pkgsrc/pkgtools/pkglint/files/shtokenizer.go
diff -u pkgsrc/pkgtools/pkglint/files/shtokenizer.go:1.5 pkgsrc/pkgtools/pkglint/files/shtokenizer.go:1.6
--- pkgsrc/pkgtools/pkglint/files/shtokenizer.go:1.5    Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/shtokenizer.go        Sun Jan 29 14:27:48 2017
@@ -1,13 +1,16 @@
 package main
 
-import "netbsd.org/pkglint/textproc"
+import (
+       "netbsd.org/pkglint/line"
+       "netbsd.org/pkglint/textproc"
+)
 
 type ShTokenizer struct {
        parser *Parser
        mkp    *MkParser
 }
 
-func NewShTokenizer(line Line, text string, emitWarnings bool) *ShTokenizer {
+func NewShTokenizer(line line.Line, text string, emitWarnings bool) *ShTokenizer {
        p := NewParser(line, text, emitWarnings)
        mkp := &MkParser{p}
        return &ShTokenizer{p, mkp}

Index: pkgsrc/pkgtools/pkglint/files/check_test.go
diff -u pkgsrc/pkgtools/pkglint/files/check_test.go:1.12 pkgsrc/pkgtools/pkglint/files/check_test.go:1.13
--- pkgsrc/pkgtools/pkglint/files/check_test.go:1.12    Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/check_test.go Sun Jan 29 14:27:48 2017
@@ -11,6 +11,7 @@ import (
        "testing"
 
        check "gopkg.in/check.v1"
+       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/textproc"
        "netbsd.org/pkglint/trace"
 )
@@ -61,6 +62,18 @@ func (s *Suite) Output() string {
        return output
 }
 
+func (s *Suite) CheckOutputEmpty() {
+       s.c().Check(s.Output(), equals, "")
+}
+
+func (s *Suite) CheckOutputLines(expectedLines ...string) {
+       expectedOutput := ""
+       for _, expectedLine := range expectedLines {
+               expectedOutput += expectedLine + "\n"
+       }
+       s.c().Check(s.Output(), equals, expectedOutput)
+}
+
 // Arguments are either (lineno, orignl) or (lineno, orignl, textnl).
 func (s *Suite) NewRawLines(args ...interface{}) []*RawLine {
        rawlines := make([]*RawLine, len(args)/2)
@@ -81,8 +94,8 @@ func (s *Suite) NewRawLines(args ...inte
        return rawlines[:j]
 }
 
-func (s *Suite) NewLines(fname string, texts ...string) []Line {
-       result := make([]Line, len(texts))
+func (s *Suite) NewLines(fname string, texts ...string) []line.Line {
+       result := make([]line.Line, len(texts))
        for i, text := range texts {
                textnl := text + "\n"
                result[i] = NewLine(fname, i+1, text, s.NewRawLines(i+1, textnl))
Index: pkgsrc/pkgtools/pkglint/files/distinfo.go
diff -u pkgsrc/pkgtools/pkglint/files/distinfo.go:1.12 pkgsrc/pkgtools/pkglint/files/distinfo.go:1.13
--- pkgsrc/pkgtools/pkglint/files/distinfo.go:1.12      Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/distinfo.go   Sun Jan 29 14:27:48 2017
@@ -5,11 +5,12 @@ import (
        "crypto/sha1"
        "fmt"
        "io/ioutil"
+       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/trace"
        "strings"
 )
 
-func ChecklinesDistinfo(lines []Line) {
+func ChecklinesDistinfo(lines []line.Line) {
        if trace.Tracing {
                defer trace.Call1(lines[0].Filename())()
        }
@@ -46,13 +47,13 @@ type distinfoLinesChecker struct {
        distinfoIsCommitted bool
 
        patches          map[string]bool // "patch-aa" => true
-       currentFirstLine Line
+       currentFirstLine line.Line
        currentFilename  string
        isPatch          bool
        algorithms       []string
 }
 
-func (ck *distinfoLinesChecker) checkLines(lines []Line) {
+func (ck *distinfoLinesChecker) checkLines(lines []line.Line) {
        LineChecker{lines[0]}.CheckRcsid(``, "")
        if 1 < len(lines) && lines[1].Text() != "" {
                lines[1].Notef("Empty line expected.")
@@ -79,7 +80,7 @@ func (ck *distinfoLinesChecker) checkLin
        ck.onFilenameChange(NewLineEOF(ck.distinfoFilename), "")
 }
 
-func (ck *distinfoLinesChecker) onFilenameChange(line Line, nextFname string) {
+func (ck *distinfoLinesChecker) onFilenameChange(line line.Line, nextFname string) {
        currentFname := ck.currentFilename
        if currentFname != "" {
                algorithms := strings.Join(ck.algorithms, ", ")
@@ -106,7 +107,7 @@ func (ck *distinfoLinesChecker) onFilena
        ck.algorithms = nil
 }
 
-func (ck *distinfoLinesChecker) checkPatchSha1(line Line, patchFname, distinfoSha1Hex string) {
+func (ck *distinfoLinesChecker) checkPatchSha1(line line.Line, patchFname, distinfoSha1Hex string) {
        patchBytes, err := ioutil.ReadFile(G.CurrentDir + "/" + patchFname)
        if err != nil {
                line.Errorf("%s does not exist.", patchFname)
@@ -146,7 +147,7 @@ func (ck *distinfoLinesChecker) checkUnr
 }
 
 // Inter-package check for differing distfile checksums.
-func (ck *distinfoLinesChecker) checkGlobalMismatch(line Line, fname, alg, hash string) {
+func (ck *distinfoLinesChecker) checkGlobalMismatch(line line.Line, fname, alg, hash string) {
        if G.Hash != nil && !hasPrefix(fname, "patch-") { // Intentionally checking the filename instead of ck.isPatch
                key := alg + ":" + fname
                otherHash := G.Hash[key]
@@ -161,7 +162,7 @@ func (ck *distinfoLinesChecker) checkGlo
        }
 }
 
-func (ck *distinfoLinesChecker) checkUncommittedPatch(line Line, patchName, sha1Hash string) {
+func (ck *distinfoLinesChecker) checkUncommittedPatch(line line.Line, patchName, sha1Hash string) {
        if ck.isPatch {
                patchFname := ck.patchdir + "/" + patchName
                if ck.distinfoIsCommitted && !isCommitted(G.CurrentDir+"/"+patchFname) {
Index: pkgsrc/pkgtools/pkglint/files/mklines.go
diff -u pkgsrc/pkgtools/pkglint/files/mklines.go:1.12 pkgsrc/pkgtools/pkglint/files/mklines.go:1.13
--- pkgsrc/pkgtools/pkglint/files/mklines.go:1.12       Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/mklines.go    Sun Jan 29 14:27:48 2017
@@ -1,6 +1,7 @@
 package main
 
 import (
+       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/trace"
        "path"
        "strings"
@@ -8,22 +9,22 @@ import (
 
 // MkLines contains data for the Makefile (or *.mk) that is currently checked.
 type MkLines struct {
-       mklines        []*MkLine
-       lines          []Line
-       forVars        map[string]bool    // The variables currently used in .for loops
-       target         string             // Current make(1) target
-       vardef         map[string]*MkLine // varname => line; for all variables that are defined in the current file
-       varuse         map[string]*MkLine // varname => line; for all variables that are used in the current file
-       buildDefs      map[string]bool    // Variables that are registered in BUILD_DEFS, to ensure that all user-defined variables are added to it.
-       plistVars      map[string]bool    // Variables that are registered in PLIST_VARS, to ensure that all user-defined variables are added to it.
-       tools          map[string]bool    // Set of tools that are declared to be used.
-       toolRegistry   ToolRegistry       // Tools defined in file scope.
+       mklines        []MkLine
+       lines          []line.Line
+       forVars        map[string]bool   // The variables currently used in .for loops
+       target         string            // Current make(1) target
+       vardef         map[string]MkLine // varname => line; for all variables that are defined in the current file
+       varuse         map[string]MkLine // varname => line; for all variables that are used in the current file
+       buildDefs      map[string]bool   // Variables that are registered in BUILD_DEFS, to ensure that all user-defined variables are added to it.
+       plistVars      map[string]bool   // Variables that are registered in PLIST_VARS, to ensure that all user-defined variables are added to it.
+       tools          map[string]bool   // Set of tools that are declared to be used.
+       toolRegistry   ToolRegistry      // Tools defined in file scope.
        SeenBsdPrefsMk bool
        indentation    Indentation // Indentation depth of preprocessing directives
 }
 
-func NewMkLines(lines []Line) *MkLines {
-       mklines := make([]*MkLine, len(lines))
+func NewMkLines(lines []line.Line) *MkLines {
+       mklines := make([]MkLine, len(lines))
        for i, line := range lines {
                mklines[i] = NewMkLine(line)
        }
@@ -39,8 +40,8 @@ func NewMkLines(lines []Line) *MkLines {
                lines,
                make(map[string]bool),
                "",
-               make(map[string]*MkLine),
-               make(map[string]*MkLine),
+               make(map[string]MkLine),
+               make(map[string]MkLine),
                make(map[string]bool),
                make(map[string]bool),
                tools,
@@ -49,7 +50,7 @@ func NewMkLines(lines []Line) *MkLines {
                Indentation{}}
 }
 
-func (mklines *MkLines) DefineVar(mkline *MkLine, varname string) {
+func (mklines *MkLines) DefineVar(mkline MkLine, varname string) {
        if mklines.vardef[varname] == nil {
                mklines.vardef[varname] = mkline
        }
@@ -59,7 +60,7 @@ func (mklines *MkLines) DefineVar(mkline
        }
 }
 
-func (mklines *MkLines) UseVar(mkline *MkLine, varname string) {
+func (mklines *MkLines) UseVar(mkline MkLine, varname string) {
        varcanon := varnameCanon(varname)
        mklines.varuse[varname] = mkline
        mklines.varuse[varcanon] = mkline
@@ -96,7 +97,7 @@ func (mklines *MkLines) Check() {
        // In the first pass, all additions to BUILD_DEFS and USE_TOOLS
        // are collected to make the order of the definitions irrelevant.
        mklines.DetermineUsedVariables()
-       mklines.determineDefinedVariables()
+       mklines.DetermineDefinedVariables()
 
        // In the second pass, the actual checks are done.
 
@@ -150,7 +151,7 @@ func (mklines *MkLines) Check() {
        SaveAutofixChanges(mklines.lines)
 }
 
-func (mklines *MkLines) determineDefinedVariables() {
+func (mklines *MkLines) DetermineDefinedVariables() {
        if trace.Tracing {
                defer trace.Call0()()
        }
@@ -210,13 +211,13 @@ func (mklines *MkLines) determineDefined
                        }
                }
 
-               mklines.toolRegistry.ParseToolLine(mkline.Line)
+               mklines.toolRegistry.ParseToolLine(mkline)
        }
 }
 
 func (mklines *MkLines) DetermineUsedVariables() {
        for _, mkline := range mklines.mklines {
-               varnames := mkline.determineUsedVariables()
+               varnames := mkline.DetermineUsedVariables()
                for _, varname := range varnames {
                        mklines.UseVar(mkline, varname)
                }
@@ -234,7 +235,7 @@ func (mklines *MkLines) setSeenBsdPrefsM
 
 type VaralignBlock struct {
        info []struct {
-               mkline *MkLine
+               mkline MkLine
                prefix string
                align  string
        }
@@ -245,8 +246,8 @@ type VaralignBlock struct {
        maxTabWidth    int
 }
 
-func (va *VaralignBlock) Check(mkline *MkLine) {
-       if !G.opts.WarnSpace || mkline.Line.IsMultiline() || mkline.IsComment() || mkline.IsCond() {
+func (va *VaralignBlock) Check(mkline MkLine) {
+       if !G.opts.WarnSpace || mkline.IsMultiline() || mkline.IsComment() || mkline.IsCond() {
                return
        }
        if mkline.IsEmpty() {
@@ -263,7 +264,7 @@ func (va *VaralignBlock) Check(mkline *M
        align := valueAlign[len(prefix):]
 
        va.info = append(va.info, struct {
-               mkline *MkLine
+               mkline MkLine
                prefix string
                align  string
        }{mkline, prefix, align})
@@ -291,7 +292,7 @@ func (va *VaralignBlock) Check(mkline *M
 func (va *VaralignBlock) Finish() {
        if !va.skip {
                for _, info := range va.info {
-                       if !info.mkline.Line.IsMultiline() {
+                       if !info.mkline.IsMultiline() {
                                va.fixalign(info.mkline, info.prefix, info.align)
                        }
                }
@@ -299,7 +300,7 @@ func (va *VaralignBlock) Finish() {
        *va = VaralignBlock{}
 }
 
-func (va *VaralignBlock) fixalign(mkline *MkLine, prefix, oldalign string) {
+func (va *VaralignBlock) fixalign(mkline MkLine, prefix, oldalign string) {
        if mkline.Value() == "" && mkline.VarassignComment() == "" {
                return
        }
Index: pkgsrc/pkgtools/pkglint/files/mklines_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mklines_test.go:1.12 pkgsrc/pkgtools/pkglint/files/mklines_test.go:1.13
--- pkgsrc/pkgtools/pkglint/files/mklines_test.go:1.12  Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/mklines_test.go       Sun Jan 29 14:27:48 2017
@@ -21,12 +21,12 @@ func (s *Suite) Test_MkLines_Check__auto
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, ""+
-               "AUTOFIX: ~/fname.mk:3: Replacing \".\" with \".  \".\n"+
-               "AUTOFIX: ~/fname.mk:4: Replacing \".\" with \".    \".\n"+
-               "AUTOFIX: ~/fname.mk:5: Replacing \".\" with \".    \".\n"+
-               "AUTOFIX: ~/fname.mk:6: Replacing \".\" with \".  \".\n"+
-               "AUTOFIX: ~/fname.mk: Has been auto-fixed. Please re-run pkglint.\n")
+       s.CheckOutputLines(
+               "AUTOFIX: ~/fname.mk:3: Replacing \".\" with \".  \".",
+               "AUTOFIX: ~/fname.mk:4: Replacing \".\" with \".    \".",
+               "AUTOFIX: ~/fname.mk:5: Replacing \".\" with \".    \".",
+               "AUTOFIX: ~/fname.mk:6: Replacing \".\" with \".  \".",
+               "AUTOFIX: ~/fname.mk: Has been auto-fixed. Please re-run pkglint.")
        c.Check(s.LoadTmpFile("fname.mk"), equals, ""+
                "# $"+"NetBSD$\n"+
                ".if defined(A)\n"+
@@ -38,6 +38,7 @@ func (s *Suite) Test_MkLines_Check__auto
 }
 
 func (s *Suite) Test_MkLines_Check__unusual_target(c *check.C) {
+       s.Init(c)
        mklines := s.NewMkLines("Makefile",
                mkrcsid,
                "",
@@ -46,17 +47,19 @@ func (s *Suite) Test_MkLines_Check__unus
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, "WARN: Makefile:3: Unusual target \"echo\".\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:3: Unusual target \"echo\".")
 }
 
 func (s *Suite) Test_MkLineChecker_checkInclude__Makefile(c *check.C) {
+       s.Init(c)
        mkline := NewMkLine(NewLine("Makefile", 2, ".include \"../../other/package/Makefile\"", nil))
 
        MkLineChecker{mkline}.checkInclude()
 
-       c.Check(s.Output(), equals, ""+
-               "ERROR: Makefile:2: \"/other/package/Makefile\" does not exist.\n"+
-               "ERROR: Makefile:2: Other Makefiles must not be included directly.\n")
+       s.CheckOutputLines(
+               "ERROR: Makefile:2: \"/other/package/Makefile\" does not exist.",
+               "ERROR: Makefile:2: Other Makefiles must not be included directly.")
 }
 
 func (s *Suite) Test_MkLines_quoting_LDFLAGS_for_GNU_configure(c *check.C) {
@@ -71,9 +74,9 @@ func (s *Suite) Test_MkLines_quoting_LDF
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: Makefile:3: Please use ${X11_LDFLAGS:M*:Q} instead of ${X11_LDFLAGS:Q}.\n"+
-               "WARN: Makefile:3: Please use ${X11_LDFLAGS:M*:Q} instead of ${X11_LDFLAGS:Q}.\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:3: Please use ${X11_LDFLAGS:M*:Q} instead of ${X11_LDFLAGS:Q}.",
+               "WARN: Makefile:3: Please use ${X11_LDFLAGS:M*:Q} instead of ${X11_LDFLAGS:Q}.")
 }
 
 func (s *Suite) Test_MkLines__variable_alignment_advanced(c *check.C) {
@@ -105,28 +108,28 @@ func (s *Suite) Test_MkLines__variable_a
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, ""+
-               "NOTE: ~/Makefile:6: This variable value should be aligned with tabs, not spaces, to column 9.\n"+
-               "NOTE: ~/Makefile:7: This variable value should be aligned with tabs, not spaces, to column 9.\n"+
-               "NOTE: ~/Makefile:12: This variable value should be aligned to column 17.\n"+
-               "NOTE: ~/Makefile:15: This variable value should be aligned with tabs, not spaces, to column 17.\n"+
-               "NOTE: ~/Makefile:16: This variable value should be aligned with tabs, not spaces, to column 17.\n"+
-               "NOTE: ~/Makefile:17: This variable value should be aligned with tabs, not spaces, to column 17.\n"+
-               "NOTE: ~/Makefile:18: This variable value should be aligned with tabs, not spaces, to column 17.\n")
+       s.CheckOutputLines(
+               "NOTE: ~/Makefile:6: This variable value should be aligned with tabs, not spaces, to column 9.",
+               "NOTE: ~/Makefile:7: This variable value should be aligned with tabs, not spaces, to column 9.",
+               "NOTE: ~/Makefile:12: This variable value should be aligned to column 17.",
+               "NOTE: ~/Makefile:15: This variable value should be aligned with tabs, not spaces, to column 17.",
+               "NOTE: ~/Makefile:16: This variable value should be aligned with tabs, not spaces, to column 17.",
+               "NOTE: ~/Makefile:17: This variable value should be aligned with tabs, not spaces, to column 17.",
+               "NOTE: ~/Makefile:18: This variable value should be aligned with tabs, not spaces, to column 17.")
 
        s.UseCommandLine("-Wspace", "--autofix")
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, ""+
-               "AUTOFIX: ~/Makefile:6: Replacing \"VAR= \" with \"VAR=\\t\".\n"+
-               "AUTOFIX: ~/Makefile:7: Replacing \"VAR=  \" with \"VAR=\\t\".\n"+
-               "AUTOFIX: ~/Makefile:12: Replacing \"BLOCK=\\t\" with \"BLOCK=\\t\\t\".\n"+
-               "AUTOFIX: ~/Makefile:15: Replacing \"GRP_A= \" with \"GRP_A=\\t\\t\".\n"+
-               "AUTOFIX: ~/Makefile:16: Replacing \"GRP_AA= \" with \"GRP_AA=\\t\\t\".\n"+
-               "AUTOFIX: ~/Makefile:17: Replacing \"GRP_AAA= \" with \"GRP_AAA=\\t\".\n"+
-               "AUTOFIX: ~/Makefile:18: Replacing \"GRP_AAAA= \" with \"GRP_AAAA=\\t\".\n"+
-               "AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.\n")
+       s.CheckOutputLines(
+               "AUTOFIX: ~/Makefile:6: Replacing \"VAR= \" with \"VAR=\\t\".",
+               "AUTOFIX: ~/Makefile:7: Replacing \"VAR=  \" with \"VAR=\\t\".",
+               "AUTOFIX: ~/Makefile:12: Replacing \"BLOCK=\\t\" with \"BLOCK=\\t\\t\".",
+               "AUTOFIX: ~/Makefile:15: Replacing \"GRP_A= \" with \"GRP_A=\\t\\t\".",
+               "AUTOFIX: ~/Makefile:16: Replacing \"GRP_AA= \" with \"GRP_AA=\\t\\t\".",
+               "AUTOFIX: ~/Makefile:17: Replacing \"GRP_AAA= \" with \"GRP_AAA=\\t\".",
+               "AUTOFIX: ~/Makefile:18: Replacing \"GRP_AAAA= \" with \"GRP_AAAA=\\t\".",
+               "AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.")
        c.Check(s.LoadTmpFile("Makefile"), equals, ""+
                "# $"+"NetBSD$\n"+
                "\n"+
@@ -162,7 +165,8 @@ func (s *Suite) Test_MkLines__variable_a
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, "NOTE: Makefile:3: Variable values should be aligned with tabs, not spaces.\n")
+       s.CheckOutputLines(
+               "NOTE: Makefile:3: Variable values should be aligned with tabs, not spaces.")
 }
 
 func (s *Suite) Test_MkLines__for_loop_multiple_variables(c *check.C) {
@@ -181,10 +185,10 @@ func (s *Suite) Test_MkLines__for_loop_m
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: audio/squeezeboxserver/Makefile:3: Variable names starting with an underscore (_list_) are reserved for internal pkgsrc use.\n"+
-               "WARN: audio/squeezeboxserver/Makefile:3: Variable names starting with an underscore (_dir_) are reserved for internal pkgsrc use.\n"+
-               "WARN: audio/squeezeboxserver/Makefile:4: The exitcode of the left-hand-side command of the pipe operator is ignored.\n")
+       s.CheckOutputLines(
+               "WARN: audio/squeezeboxserver/Makefile:3: Variable names starting with an underscore (_list_) are reserved for internal pkgsrc use.",
+               "WARN: audio/squeezeboxserver/Makefile:3: Variable names starting with an underscore (_dir_) are reserved for internal pkgsrc use.",
+               "WARN: audio/squeezeboxserver/Makefile:4: The exitcode of the left-hand-side command of the pipe operator is ignored.")
 }
 
 func (s *Suite) Test_MkLines__comparing_YesNo_variable_to_string(c *check.C) {
@@ -213,17 +217,17 @@ func (s *Suite) Test_MkLines__varuse_sh_
                "qore-version=\tqore --short-version | ${SED} -e s/-.*//",
                "PLIST_SUBST+=\tQORE_VERSION=\"${qore-version:sh}\"")
 
-       vars2 := mklines.mklines[1].determineUsedVariables()
+       vars2 := mklines.mklines[1].DetermineUsedVariables()
 
        c.Check(vars2, deepEquals, []string{"SED"})
 
-       vars3 := mklines.mklines[2].determineUsedVariables()
+       vars3 := mklines.mklines[2].DetermineUsedVariables()
 
        c.Check(vars3, deepEquals, []string{"qore-version"})
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, "") // No warnings about defined but not used or vice versa
+       s.CheckOutputEmpty() // No warnings about defined but not used or vice versa
 }
 
 func (s *Suite) Test_MkLines__varuse_parameterized(c *check.C) {
@@ -237,7 +241,7 @@ func (s *Suite) Test_MkLines__varuse_par
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, "") // No warnings about defined but not used or vice versa
+       s.CheckOutputEmpty() // No warnings about defined but not used or vice versa
 }
 
 func (s *Suite) Test_MkLines__loop_modifier(c *check.C) {
@@ -260,6 +264,7 @@ func (s *Suite) Test_MkLines__loop_modif
 
 // PR 46570
 func (s *Suite) Test_MkLines__PKG_SKIP_REASON_depending_on_OPSYS(c *check.C) {
+       s.Init(c)
        G.globalData.InitVartypes()
        mklines := s.NewMkLines("Makefile",
                mkrcsid,
@@ -270,7 +275,8 @@ func (s *Suite) Test_MkLines__PKG_SKIP_R
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, "NOTE: Makefile:4: Consider defining NOT_FOR_PLATFORM instead of setting PKG_SKIP_REASON depending on ${OPSYS}.\n")
+       s.CheckOutputLines(
+               "NOTE: Makefile:4: Consider defining NOT_FOR_PLATFORM instead of setting PKG_SKIP_REASON depending on ${OPSYS}.")
 }
 
 // PR 46570, item "15. net/uucp/Makefile has a make loop"
@@ -288,8 +294,8 @@ func (s *Suite) Test_MkLines__indirect_v
        mklines.Check()
 
        // No warning about UUCP_${var} being used but not defined.
-       c.Check(s.Output(), equals, ""+
-               "WARN: net/uucp/Makefile:5: Unknown shell command \"${ECHO}\".\n")
+       s.CheckOutputLines(
+               "WARN: net/uucp/Makefile:5: Unknown shell command \"${ECHO}\".")
 }
 
 func (s *Suite) Test_MkLines_Check__list_variable_as_part_of_word(c *check.C) {
@@ -301,9 +307,9 @@ func (s *Suite) Test_MkLines_Check__list
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: converters/chef/Makefile:2: Unknown shell command \"tr\".\n"+
-               "WARN: converters/chef/Makefile:2: The list variable DISTFILES should not be embedded in a word.\n")
+       s.CheckOutputLines(
+               "WARN: converters/chef/Makefile:2: Unknown shell command \"tr\".",
+               "WARN: converters/chef/Makefile:2: The list variable DISTFILES should not be embedded in a word.")
 }
 
 func (s *Suite) Test_MkLines_Check__absolute_pathname_depending_on_OPSYS(c *check.C) {
@@ -321,10 +327,10 @@ func (s *Suite) Test_MkLines_Check__abso
 
        // No warning about an unknown shell command in line 3,
        // since that line depends on OPSYS.
-       c.Check(s.Output(), equals, ""+
-               "WARN: games/heretic2-demo/Makefile:3: The variable TOOLS_PLATFORM.gtar may not be set by any package.\n"+
-               "WARN: games/heretic2-demo/Makefile:5: The variable TOOLS_PLATFORM.gtar may not be set by any package.\n"+
-               "WARN: games/heretic2-demo/Makefile:5: Unknown shell command \"/usr/bin/bsdtar\".\n")
+       s.CheckOutputLines(
+               "WARN: games/heretic2-demo/Makefile:3: The variable TOOLS_PLATFORM.gtar may not be set by any package.",
+               "WARN: games/heretic2-demo/Makefile:5: The variable TOOLS_PLATFORM.gtar may not be set by any package.",
+               "WARN: games/heretic2-demo/Makefile:5: Unknown shell command \"/usr/bin/bsdtar\".")
 }
 
 func (s *Suite) Test_MkLines_checkForUsedComment(c *check.C) {
@@ -336,24 +342,24 @@ func (s *Suite) Test_MkLines_checkForUse
                "# used by sysutils/mc",
        ).checkForUsedComment("sysutils/mc")
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 
        s.NewMkLines("Makefile.common").checkForUsedComment("category/package")
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 
        s.NewMkLines("Makefile.common",
                mkrcsid,
        ).checkForUsedComment("category/package")
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 
        s.NewMkLines("Makefile.common",
                mkrcsid,
                "",
        ).checkForUsedComment("category/package")
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 
        s.NewMkLines("Makefile.common",
                mkrcsid,
@@ -361,9 +367,9 @@ func (s *Suite) Test_MkLines_checkForUse
                "VARNAME=\tvalue",
        ).checkForUsedComment("category/package")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: Makefile.common:2: Please add a line \"# used by category/package\" here.\n"+
-               "AUTOFIX: Makefile.common:2: Inserting a line \"# used by category/package\" before this line.\n")
+       s.CheckOutputLines(
+               "WARN: Makefile.common:2: Please add a line \"# used by category/package\" here.",
+               "AUTOFIX: Makefile.common:2: Inserting a line \"# used by category/package\" before this line.")
 
        s.NewMkLines("Makefile.common",
                mkrcsid,
@@ -371,9 +377,9 @@ func (s *Suite) Test_MkLines_checkForUse
                "#",
        ).checkForUsedComment("category/package")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: Makefile.common:3: Please add a line \"# used by category/package\" here.\n"+
-               "AUTOFIX: Makefile.common:3: Inserting a line \"# used by category/package\" before this line.\n")
+       s.CheckOutputLines(
+               "WARN: Makefile.common:3: Please add a line \"# used by category/package\" here.",
+               "AUTOFIX: Makefile.common:3: Inserting a line \"# used by category/package\" before this line.")
 }
 
 func (s *Suite) Test_MkLines_DetermineUsedVariables__simple(c *check.C) {
@@ -413,7 +419,8 @@ func (s *Suite) Test_MkLines_PrivateTool
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, "WARN: fname:3: Unknown shell command \"md5sum\".\n")
+       s.CheckOutputLines(
+               "WARN: fname:3: Unknown shell command \"md5sum\".")
 }
 
 func (s *Suite) Test_MkLines_PrivateTool_Defined(c *check.C) {
@@ -428,7 +435,7 @@ func (s *Suite) Test_MkLines_PrivateTool
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_MkLines_Check_indentation(c *check.C) {
Index: pkgsrc/pkgtools/pkglint/files/plist.go
diff -u pkgsrc/pkgtools/pkglint/files/plist.go:1.12 pkgsrc/pkgtools/pkglint/files/plist.go:1.13
--- pkgsrc/pkgtools/pkglint/files/plist.go:1.12 Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/plist.go      Sun Jan 29 14:27:48 2017
@@ -1,6 +1,7 @@
 package main
 
 import (
+       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
        "path"
@@ -8,7 +9,7 @@ import (
        "strings"
 )
 
-func ChecklinesPlist(lines []Line) {
+func ChecklinesPlist(lines []line.Line) {
        if trace.Tracing {
                defer trace.Call1(lines[0].Filename())()
        }
@@ -43,12 +44,12 @@ type PlistChecker struct {
 }
 
 type PlistLine struct {
-       line        Line
+       line        line.Line
        conditional string // e.g. PLIST.docs
        text        string // Like line.text, without the conditional
 }
 
-func (ck *PlistChecker) Check(plainLines []Line) {
+func (ck *PlistChecker) Check(plainLines []line.Line) {
        plines := ck.NewLines(plainLines)
        ck.collectFilesAndDirs(plines)
 
@@ -76,7 +77,7 @@ func (ck *PlistChecker) Check(plainLines
        }
 }
 
-func (ck *PlistChecker) NewLines(lines []Line) []*PlistLine {
+func (ck *PlistChecker) NewLines(lines []line.Line) []*PlistLine {
        plines := make([]*PlistLine, len(lines))
        for i, line := range lines {
                conditional, text := "", line.Text()
@@ -471,14 +472,14 @@ func (pline *PlistLine) warnImakeMannews
 type plistLineSorter struct {
        first     *PlistLine
        plines    []*PlistLine
-       lines     []Line
-       after     map[*PlistLine][]Line
+       lines     []line.Line
+       after     map[*PlistLine][]line.Line
        swapped   bool
        autofixed bool
 }
 
 func NewPlistLineSorter(plines []*PlistLine) *plistLineSorter {
-       s := &plistLineSorter{first: plines[0], after: make(map[*PlistLine][]Line)}
+       s := &plistLineSorter{first: plines[0], after: make(map[*PlistLine][]line.Line)}
        prev := plines[0]
        for _, pline := range plines[1:] {
                if hasPrefix(pline.text, "@") || contains(pline.text, "$") {
@@ -513,7 +514,7 @@ func (s *plistLineSorter) Sort() {
 
        firstLine := s.first.line
        firstLine.AutofixMark("Sorting the whole file.")
-       lines := []Line{firstLine}
+       lines := []line.Line{firstLine}
        lines = append(lines, s.after[s.first]...)
        for _, pline := range s.plines {
                lines = append(lines, pline.line)
Index: pkgsrc/pkgtools/pkglint/files/plist_test.go
diff -u pkgsrc/pkgtools/pkglint/files/plist_test.go:1.12 pkgsrc/pkgtools/pkglint/files/plist_test.go:1.13
--- pkgsrc/pkgtools/pkglint/files/plist_test.go:1.12    Tue Dec 13 00:58:07 2016
+++ pkgsrc/pkgtools/pkglint/files/plist_test.go Sun Jan 29 14:27:48 2017
@@ -28,32 +28,34 @@ func (s *Suite) Test_ChecklinesPlist(c *
 
        ChecklinesPlist(lines)
 
-       c.Check(s.Output(), equals, ""+
-               "ERROR: PLIST:1: Expected \"@comment $"+"NetBSD$\".\n"+
-               "WARN: PLIST:1: The bin/ directory should not have subdirectories.\n"+
-               "WARN: PLIST:2: Manual page missing for bin/program.\n"+
-               "ERROR: PLIST:3: Configuration files must not be registered in the PLIST. Please use the CONF_FILES framework, which is described in mk/pkginstall/bsd.pkginstall.mk.\n"+
-               "ERROR: PLIST:4: RCD_SCRIPTS must not be registered in the PLIST. Please use the RCD_SCRIPTS framework.\n"+
-               "ERROR: PLIST:6: \"info/dir\" must not be listed. Use install-info to add/remove an entry.\n"+
-               "WARN: PLIST:7: Library filename \"c.so\" should start with \"lib\".\n"+
-               "WARN: PLIST:8: Redundant library found. The libtool library is in line 9.\n"+
-               "WARN: PLIST:9: \"lib/libc.la\" should be sorted before \"lib/libc.so.6\".\n"+
-               "WARN: PLIST:10: Preformatted manual page without unformatted one.\n"+
-               "WARN: PLIST:10: Preformatted manual pages should end in \".0\".\n"+
-               "WARN: PLIST:11: IMAKE_MANNEWSUFFIX is not meant to appear in PLISTs.\n"+
-               "WARN: PLIST:12: Please remove this line. It is no longer necessary.\n"+
-               "WARN: PLIST:13: Manual page missing for sbin/clockctl.\n"+
-               "ERROR: PLIST:14: The package Makefile must include \"../../graphics/gnome-icon-theme/buildlink3.mk\".\n"+
-               "ERROR: PLIST:16: Duplicate filename \"share/tzinfo\", already appeared in line 15.\n")
+       s.CheckOutputLines(
+               "ERROR: PLIST:1: Expected \"@comment $"+"NetBSD$\".",
+               "WARN: PLIST:1: The bin/ directory should not have subdirectories.",
+               "WARN: PLIST:2: Manual page missing for bin/program.",
+               "ERROR: PLIST:3: Configuration files must not be registered in the PLIST. Please use the CONF_FILES framework, which is described in mk/pkginstall/bsd.pkginstall.mk.",
+               "ERROR: PLIST:4: RCD_SCRIPTS must not be registered in the PLIST. Please use the RCD_SCRIPTS framework.",
+               "ERROR: PLIST:6: \"info/dir\" must not be listed. Use install-info to add/remove an entry.",
+               "WARN: PLIST:7: Library filename \"c.so\" should start with \"lib\".",
+               "WARN: PLIST:8: Redundant library found. The libtool library is in line 9.",
+               "WARN: PLIST:9: \"lib/libc.la\" should be sorted before \"lib/libc.so.6\".",
+               "WARN: PLIST:10: Preformatted manual page without unformatted one.",
+               "WARN: PLIST:10: Preformatted manual pages should end in \".0\".",
+               "WARN: PLIST:11: IMAKE_MANNEWSUFFIX is not meant to appear in PLISTs.",
+               "WARN: PLIST:12: Please remove this line. It is no longer necessary.",
+               "WARN: PLIST:13: Manual page missing for sbin/clockctl.",
+               "ERROR: PLIST:14: The package Makefile must include \"../../graphics/gnome-icon-theme/buildlink3.mk\".",
+               "ERROR: PLIST:16: Duplicate filename \"share/tzinfo\", already appeared in line 15.")
 }
 
 func (s *Suite) Test_ChecklinesPlist__empty(c *check.C) {
+       s.Init(c)
        lines := s.NewLines("PLIST",
                "@comment $"+"NetBSD$")
 
        ChecklinesPlist(lines)
 
-       c.Check(s.Output(), equals, "WARN: PLIST:1: PLIST files shouldn't be empty.\n")
+       s.CheckOutputLines(
+               "WARN: PLIST:1: PLIST files shouldn't be empty.")
 }
 
 func (s *Suite) Test_ChecklinesPlist__commonEnd(c *check.C) {
@@ -67,10 +69,11 @@ func (s *Suite) Test_ChecklinesPlist__co
 
        ChecklinesPlist(LoadExistingLines(fname, false))
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_ChecklinesPlist__conditional(c *check.C) {
+       s.Init(c)
        G.Pkg = NewPackage("category/pkgbase")
        G.Pkg.plistSubstCond["PLIST.bincmds"] = true
        lines := s.NewLines("PLIST",
@@ -79,7 +82,8 @@ func (s *Suite) Test_ChecklinesPlist__co
 
        ChecklinesPlist(lines)
 
-       c.Check(s.Output(), equals, "WARN: PLIST:2: The bin/ directory should not have subdirectories.\n")
+       s.CheckOutputLines(
+               "WARN: PLIST:2: The bin/ directory should not have subdirectories.")
 }
 
 func (s *Suite) Test_ChecklinesPlist__sorting(c *check.C) {
@@ -95,9 +99,9 @@ func (s *Suite) Test_ChecklinesPlist__so
 
        ChecklinesPlist(lines)
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: PLIST:5: \"bin/otherprogram\" should be sorted before \"sbin/program\".\n"+
-               "WARN: PLIST:6: \"bin/cat\" should be sorted before \"bin/otherprogram\".\n")
+       s.CheckOutputLines(
+               "WARN: PLIST:5: \"bin/otherprogram\" should be sorted before \"sbin/program\".",
+               "WARN: PLIST:6: \"bin/cat\" should be sorted before \"bin/otherprogram\".")
 }
 
 func (s *Suite) Test_PlistLineSorter_Sort(c *check.C) {
@@ -126,9 +130,9 @@ func (s *Suite) Test_PlistLineSorter_Sor
 
        NewPlistLineSorter(plines).Sort()
 
-       c.Check(s.Output(), equals, ""+
-               "AUTOFIX: ~/PLIST:1: Sorting the whole file.\n"+
-               "AUTOFIX: ~/PLIST: Has been auto-fixed. Please re-run pkglint.\n")
+       s.CheckOutputLines(
+               "AUTOFIX: ~/PLIST:1: Sorting the whole file.",
+               "AUTOFIX: ~/PLIST: Has been auto-fixed. Please re-run pkglint.")
        c.Check(s.LoadTmpFile("PLIST"), equals, ""+
                "@comment $"+"NetBSD$\n"+
                "@comment Do not remove\n"+
@@ -160,37 +164,44 @@ func (s *Suite) Test_PlistChecker_checkp
                "@comment $"+"NetBSD$",
                "share/applications/pkgbase.desktop"))
 
-       c.Check(s.Output(), equals, "WARN: PLIST:2: Packages that install a .desktop entry should .include \"../../sysutils/desktop-file-utils/desktopdb.mk\".\n")
+       s.CheckOutputLines(
+               "WARN: PLIST:2: Packages that install a .desktop entry should .include \"../../sysutils/desktop-file-utils/desktopdb.mk\".")
 }
 
 func (s *Suite) Test_PlistChecker_checkpathMan_gz(c *check.C) {
+       s.Init(c)
        G.Pkg = NewPackage("category/pkgbase")
 
        ChecklinesPlist(s.NewLines("PLIST",
                "@comment $"+"NetBSD$",
                "man/man3/strerror.3.gz"))
 
-       c.Check(s.Output(), equals, "NOTE: PLIST:2: The .gz extension is unnecessary for manual pages.\n")
+       s.CheckOutputLines(
+               "NOTE: PLIST:2: The .gz extension is unnecessary for manual pages.")
 }
 
 func (s *Suite) TestPlistChecker_checkpath__PKGMANDIR(c *check.C) {
+       s.Init(c)
        lines := s.NewLines("PLIST",
                "@comment $"+"NetBSD$",
                "${PKGMANDIR}/man1/sh.1")
 
        ChecklinesPlist(lines)
 
-       c.Check(s.Output(), equals, "NOTE: PLIST:2: PLIST files should mention \"man/\" instead of \"${PKGMANDIR}\".\n")
+       s.CheckOutputLines(
+               "NOTE: PLIST:2: PLIST files should mention \"man/\" instead of \"${PKGMANDIR}\".")
 }
 
 func (s *Suite) TestPlistChecker_checkpath__python_egg(c *check.C) {
+       s.Init(c)
        lines := s.NewLines("PLIST",
                "@comment $"+"NetBSD$",
                "${PYSITELIB}/gdspy-${PKGVERSION}-py${PYVERSSUFFIX}.egg-info/PKG-INFO")
 
        ChecklinesPlist(lines)
 
-       c.Check(s.Output(), equals, "WARN: PLIST:2: Include \"../../lang/python/egg.mk\" instead of listing .egg-info files directly.\n")
+       s.CheckOutputLines(
+               "WARN: PLIST:2: Include \"../../lang/python/egg.mk\" instead of listing .egg-info files directly.")
 }
 
 func (s *Suite) Test_PlistChecker__autofix(c *check.C) {
@@ -221,20 +232,20 @@ func (s *Suite) Test_PlistChecker__autof
        lines := LoadExistingLines(fname, false)
        ChecklinesPlist(lines)
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: ~/PLIST:3: \"lib/libvirt/connection-driver/libvirt_driver_nodedev.la\" should be sorted before \"lib/libvirt/connection-driver/libvirt_driver_storage.la\".\n"+
-               "WARN: ~/PLIST:4: \"lib/libvirt/connection-driver/libvirt_driver_libxl.la\" should be sorted before \"lib/libvirt/connection-driver/libvirt_driver_nodedev.la\".\n"+
-               "NOTE: ~/PLIST:6: PLIST files should mention \"man/\" instead of \"${PKGMANDIR}\".\n")
+       s.CheckOutputLines(
+               "WARN: ~/PLIST:3: \"lib/libvirt/connection-driver/libvirt_driver_nodedev.la\" should be sorted before \"lib/libvirt/connection-driver/libvirt_driver_storage.la\".",
+               "WARN: ~/PLIST:4: \"lib/libvirt/connection-driver/libvirt_driver_libxl.la\" should be sorted before \"lib/libvirt/connection-driver/libvirt_driver_nodedev.la\".",
+               "NOTE: ~/PLIST:6: PLIST files should mention \"man/\" instead of \"${PKGMANDIR}\".")
 
        s.UseCommandLine("-Wall", "--autofix")
        ChecklinesPlist(lines)
 
        fixedLines := LoadExistingLines(fname, false)
 
-       c.Check(s.Output(), equals, ""+
-               "AUTOFIX: ~/PLIST:6: Replacing \"${PKGMANDIR}/\" with \"man/\".\n"+
-               "AUTOFIX: ~/PLIST:1: Sorting the whole file.\n"+
-               "AUTOFIX: ~/PLIST: Has been auto-fixed. Please re-run pkglint.\n")
+       s.CheckOutputLines(
+               "AUTOFIX: ~/PLIST:6: Replacing \"${PKGMANDIR}/\" with \"man/\".",
+               "AUTOFIX: ~/PLIST:1: Sorting the whole file.",
+               "AUTOFIX: ~/PLIST: Has been auto-fixed. Please re-run pkglint.")
        c.Check(len(lines), equals, len(fixedLines))
        c.Check(s.LoadTmpFile("PLIST"), equals, ""+
                "@comment $"+"NetBSD$\n"+

Index: pkgsrc/pkgtools/pkglint/files/files.go
diff -u pkgsrc/pkgtools/pkglint/files/files.go:1.10 pkgsrc/pkgtools/pkglint/files/files.go:1.11
--- pkgsrc/pkgtools/pkglint/files/files.go:1.10 Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/files.go      Sun Jan 29 14:27:48 2017
@@ -2,11 +2,12 @@ package main
 
 import (
        "io/ioutil"
+       "netbsd.org/pkglint/line"
        "os"
        "strings"
 )
 
-func LoadNonemptyLines(fname string, joinBackslashLines bool) []Line {
+func LoadNonemptyLines(fname string, joinBackslashLines bool) []line.Line {
        lines, err := readLines(fname, joinBackslashLines)
        if err != nil {
                NewLineWhole(fname).Errorf("Cannot be read.")
@@ -19,7 +20,7 @@ func LoadNonemptyLines(fname string, joi
        return lines
 }
 
-func LoadExistingLines(fname string, joinBackslashLines bool) []Line {
+func LoadExistingLines(fname string, joinBackslashLines bool) []line.Line {
        lines, err := readLines(fname, joinBackslashLines)
        if err != nil {
                NewLineWhole(fname).Fatalf("Cannot be read.")
@@ -30,7 +31,7 @@ func LoadExistingLines(fname string, joi
        return lines
 }
 
-func getLogicalLine(fname string, rawLines []*RawLine, pindex *int) Line {
+func getLogicalLine(fname string, rawLines []*RawLine, pindex *int) line.Line {
        { // Handle the common case efficiently
                index := *pindex
                rawLine := rawLines[index]
@@ -101,7 +102,7 @@ func splitRawLine(textnl string) (leadin
        return
 }
 
-func readLines(fname string, joinBackslashLines bool) ([]Line, error) {
+func readLines(fname string, joinBackslashLines bool) ([]line.Line, error) {
        rawText, err := ioutil.ReadFile(fname)
        if err != nil {
                return nil, err
@@ -110,7 +111,7 @@ func readLines(fname string, joinBacksla
        return convertToLogicalLines(fname, string(rawText), joinBackslashLines), nil
 }
 
-func convertToLogicalLines(fname string, rawText string, joinBackslashLines bool) []Line {
+func convertToLogicalLines(fname string, rawText string, joinBackslashLines bool) []line.Line {
        var rawLines []*RawLine
        for lineno, rawLine := range strings.SplitAfter(rawText, "\n") {
                if rawLine != "" {
@@ -118,7 +119,7 @@ func convertToLogicalLines(fname string,
                }
        }
 
-       var loglines []Line
+       var loglines []line.Line
        if joinBackslashLines {
                for lineno := 0; lineno < len(rawLines); {
                        loglines = append(loglines, getLogicalLine(fname, rawLines, &lineno))
@@ -138,7 +139,7 @@ func convertToLogicalLines(fname string,
        return loglines
 }
 
-func SaveAutofixChanges(lines []Line) (autofixed bool) {
+func SaveAutofixChanges(lines []line.Line) (autofixed bool) {
        if !G.opts.Autofix {
                for _, line := range lines {
                        if line.IsChanged() {
Index: pkgsrc/pkgtools/pkglint/files/globaldata_test.go
diff -u pkgsrc/pkgtools/pkglint/files/globaldata_test.go:1.10 pkgsrc/pkgtools/pkglint/files/globaldata_test.go:1.11
--- pkgsrc/pkgtools/pkglint/files/globaldata_test.go:1.10       Wed Jan 18 23:05:43 2017
+++ pkgsrc/pkgtools/pkglint/files/globaldata_test.go    Sun Jan 29 14:27:48 2017
@@ -100,12 +100,14 @@ func (s *Suite) Test_GlobalData_loadDocC
 }
 
 func (s *Suite) Test_GlobalData_deprecated(c *check.C) {
+       s.Init(c)
        G.globalData.loadDeprecatedVars()
 
        line := NewLine("Makefile", 5, "USE_PERL5=\tyes", nil)
        MkLineChecker{NewMkLine(line)}.checkVarassign()
 
-       c.Check(s.Output(), equals, "WARN: Makefile:5: Definition of USE_PERL5 is deprecated. Use USE_TOOLS+=perl or USE_TOOLS+=perl:run instead.\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:5: Definition of USE_PERL5 is deprecated. Use USE_TOOLS+=perl or USE_TOOLS+=perl:run instead.")
 }
 
 // https://mail-index.netbsd.org/tech-pkg/2017/01/18/msg017698.html
Index: pkgsrc/pkgtools/pkglint/files/pkglint_test.go
diff -u pkgsrc/pkgtools/pkglint/files/pkglint_test.go:1.10 pkgsrc/pkgtools/pkglint/files/pkglint_test.go:1.11
--- pkgsrc/pkgtools/pkglint/files/pkglint_test.go:1.10  Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/pkglint_test.go       Sun Jan 29 14:27:48 2017
@@ -47,7 +47,8 @@ func (s *Suite) Test_Pkglint_CheckDirent
 
        new(Pkglint).CheckDirent(s.tmpdir)
 
-       c.Check(s.Output(), equals, "ERROR: ~: Cannot determine the pkgsrc root directory for \"~\".\n")
+       s.CheckOutputLines(
+               "ERROR: ~: Cannot determine the pkgsrc root directory for \"~\".")
 }
 
 func (s *Suite) Test_Pkglint_CheckDirent(c *check.C) {
@@ -61,19 +62,23 @@ func (s *Suite) Test_Pkglint_CheckDirent
 
        pkglint.CheckDirent(s.tmpdir)
 
-       c.Check(s.Output(), equals, "ERROR: ~/Makefile: Must not be empty.\n")
+       s.CheckOutputLines(
+               "ERROR: ~/Makefile: Must not be empty.")
 
        pkglint.CheckDirent(s.tmpdir + "/category")
 
-       c.Check(s.Output(), equals, "ERROR: ~/category/Makefile: Must not be empty.\n")
+       s.CheckOutputLines(
+               "ERROR: ~/category/Makefile: Must not be empty.")
 
        pkglint.CheckDirent(s.tmpdir + "/category/package")
 
-       c.Check(s.Output(), equals, "ERROR: ~/category/package/Makefile: Must not be empty.\n")
+       s.CheckOutputLines(
+               "ERROR: ~/category/package/Makefile: Must not be empty.")
 
        pkglint.CheckDirent(s.tmpdir + "/category/package/nonexistent")
 
-       c.Check(s.Output(), equals, "ERROR: ~/category/package/nonexistent: No such file or directory.\n")
+       s.CheckOutputLines(
+               "ERROR: ~/category/package/nonexistent: No such file or directory.")
 }
 
 func (s *Suite) Test_resolveVariableRefs__circular_reference(c *check.C) {
@@ -111,6 +116,7 @@ func (s *Suite) Test_resolveVariableRefs
 }
 
 func (s *Suite) Test_ChecklinesDescr(c *check.C) {
+       s.Init(c)
        lines := s.NewLines("DESCR",
                strings.Repeat("X", 90),
                "", "", "", "", "", "", "", "", "10",
@@ -120,22 +126,25 @@ func (s *Suite) Test_ChecklinesDescr(c *
 
        ChecklinesDescr(lines)
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: DESCR:1: Line too long (should be no more than 80 characters).\n"+
-               "NOTE: DESCR:11: Variables are not expanded in the DESCR file.\n"+
-               "WARN: DESCR:25: File too long (should be no more than 24 lines).\n")
+       s.CheckOutputLines(
+               "WARN: DESCR:1: Line too long (should be no more than 80 characters).",
+               "NOTE: DESCR:11: Variables are not expanded in the DESCR file.",
+               "WARN: DESCR:25: File too long (should be no more than 24 lines).")
 }
 
 func (s *Suite) Test_ChecklinesMessage__short(c *check.C) {
+       s.Init(c)
        lines := s.NewLines("MESSAGE",
                "one line")
 
        ChecklinesMessage(lines)
 
-       c.Check(s.Output(), equals, "WARN: MESSAGE:1: File too short.\n")
+       s.CheckOutputLines(
+               "WARN: MESSAGE:1: File too short.")
 }
 
 func (s *Suite) Test_ChecklinesMessage__malformed(c *check.C) {
+       s.Init(c)
        lines := s.NewLines("MESSAGE",
                "1",
                "2",
@@ -145,10 +154,10 @@ func (s *Suite) Test_ChecklinesMessage__
 
        ChecklinesMessage(lines)
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: MESSAGE:1: Expected a line of exactly 75 \"=\" characters.\n"+
-               "ERROR: MESSAGE:2: Expected \"$"+"NetBSD$\".\n"+
-               "WARN: MESSAGE:5: Expected a line of exactly 75 \"=\" characters.\n")
+       s.CheckOutputLines(
+               "WARN: MESSAGE:1: Expected a line of exactly 75 \"=\" characters.",
+               "ERROR: MESSAGE:2: Expected \"$"+"NetBSD$\".",
+               "WARN: MESSAGE:5: Expected a line of exactly 75 \"=\" characters.")
 }
 
 func (s *Suite) Test_GlobalData_Latest(c *check.C) {
@@ -158,7 +167,8 @@ func (s *Suite) Test_GlobalData_Latest(c
        latest1 := G.globalData.Latest("lang", `^python[0-9]+$`, "../../lang/$0")
 
        c.Check(latest1, equals, "")
-       c.Check(s.Output(), equals, "ERROR: Cannot find latest version of \"^python[0-9]+$\" in \"~\".\n")
+       s.CheckOutputLines(
+               "ERROR: Cannot find latest version of \"^python[0-9]+$\" in \"~\".")
 
        s.CreateTmpFile("lang/Makefile", "")
        G.globalData.latest = nil
@@ -166,7 +176,8 @@ func (s *Suite) Test_GlobalData_Latest(c
        latest2 := G.globalData.Latest("lang", `^python[0-9]+$`, "../../lang/$0")
 
        c.Check(latest2, equals, "")
-       c.Check(s.Output(), equals, "ERROR: Cannot find latest version of \"^python[0-9]+$\" in \"~\".\n")
+       s.CheckOutputLines(
+               "ERROR: Cannot find latest version of \"^python[0-9]+$\" in \"~\".")
 
        s.CreateTmpFile("lang/python27/Makefile", "")
        G.globalData.latest = nil
@@ -174,7 +185,7 @@ func (s *Suite) Test_GlobalData_Latest(c
        latest3 := G.globalData.Latest("lang", `^python[0-9]+$`, "../../lang/$0")
 
        c.Check(latest3, equals, "../../lang/python27")
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 
        s.CreateTmpFile("lang/python35/Makefile", "")
        G.globalData.latest = nil
@@ -182,5 +193,5 @@ func (s *Suite) Test_GlobalData_Latest(c
        latest4 := G.globalData.Latest("lang", `^python[0-9]+$`, "../../lang/$0")
 
        c.Check(latest4, equals, "../../lang/python35")
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }

Index: pkgsrc/pkgtools/pkglint/files/globaldata.go
diff -u pkgsrc/pkgtools/pkglint/files/globaldata.go:1.19 pkgsrc/pkgtools/pkglint/files/globaldata.go:1.20
--- pkgsrc/pkgtools/pkglint/files/globaldata.go:1.19    Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/globaldata.go Sun Jan 29 14:27:48 2017
@@ -2,6 +2,7 @@ package main
 
 import (
        "io/ioutil"
+       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
        "path"
@@ -20,7 +21,7 @@ type GlobalData struct {
        suggestedUpdates    []SuggestedUpdate   //
        suggestedWipUpdates []SuggestedUpdate   //
        LastChange          map[string]*Change  //
-       UserDefinedVars     map[string]*MkLine  // varname => line
+       UserDefinedVars     map[string]MkLine   // varname => line
        Deprecated          map[string]string   //
        vartypes            map[string]*Vartype // varcanon => type
        latest              map[string]string   // "lang/php[0-9]*" => "lang/php70"
@@ -28,7 +29,7 @@ type GlobalData struct {
 
 // Change is a change entry from the `doc/CHANGES-*` files.
 type Change struct {
-       Line    Line
+       Line    line.Line
        Action  string
        Pkgpath string
        Version string
@@ -38,7 +39,7 @@ type Change struct {
 
 // SuggestedUpdate is from the `doc/TODO` file.
 type SuggestedUpdate struct {
-       Line    Line
+       Line    line.Line
        Pkgname string
        Version string
        Comment string
@@ -253,7 +254,7 @@ func loadSuggestedUpdates(fname string) 
        return parselinesSuggestedUpdates(lines)
 }
 
-func parselinesSuggestedUpdates(lines []Line) []SuggestedUpdate {
+func parselinesSuggestedUpdates(lines []line.Line) []SuggestedUpdate {
        var updates []SuggestedUpdate
        state := 0
        for _, line := range lines {
@@ -294,7 +295,7 @@ func (gd *GlobalData) loadSuggestedUpdat
 func (gd *GlobalData) loadDocChangesFromFile(fname string) []*Change {
        lines := LoadExistingLines(fname, false)
 
-       parseChange := func(line Line) *Change {
+       parseChange := func(line line.Line) *Change {
                text := line.Text()
                if !hasPrefix(text, "\t") {
                        return nil
@@ -374,7 +375,7 @@ func (gd *GlobalData) loadUserDefinedVar
        lines := LoadExistingLines(G.globalData.Pkgsrcdir+"/mk/defaults/mk.conf", true)
        mklines := NewMkLines(lines)
 
-       gd.UserDefinedVars = make(map[string]*MkLine)
+       gd.UserDefinedVars = make(map[string]MkLine)
        for _, mkline := range mklines.mklines {
                if mkline.IsVarassign() {
                        gd.UserDefinedVars[mkline.Varname()] = mkline
@@ -603,7 +604,7 @@ func (tr *ToolRegistry) Trace() {
        }
 }
 
-func (tr *ToolRegistry) ParseToolLine(line Line) {
+func (tr *ToolRegistry) ParseToolLine(line line.Line) {
        if m, varname, _, _, _, value, _, _ := MatchVarassign(line.Text()); m {
                if varname == "TOOLS_CREATE" && (value == "[" || matches(value, `^?[-\w.]+$`)) {
                        tr.Register(value)

Index: pkgsrc/pkgtools/pkglint/files/globalvars.go
diff -u pkgsrc/pkgtools/pkglint/files/globalvars.go:1.6 pkgsrc/pkgtools/pkglint/files/globalvars.go:1.7
--- pkgsrc/pkgtools/pkglint/files/globalvars.go:1.6     Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/globalvars.go Sun Jan 29 14:27:48 2017
@@ -3,6 +3,7 @@ package main
 import (
        "io"
        "netbsd.org/pkglint/histogram"
+       "netbsd.org/pkglint/line"
 )
 
 type GlobalVars struct {
@@ -19,7 +20,7 @@ type GlobalVars struct {
        Testing         bool     // Is pkglint in self-testing mode (only during development)?
        CurrentUsername string   // For checking against OWNER and MAINTAINER
        CvsEntriesDir   string   // Cached to avoid I/O
-       CvsEntriesLines []Line
+       CvsEntriesLines []line.Line
 
        Hash         map[string]*Hash // Maps "alg:fname" => hash (inter-package check).
        UsedLicenses map[string]bool  // Maps "license name" => true (inter-package check).
@@ -81,7 +82,7 @@ type CmdOpts struct {
 
 type Hash struct {
        hash string
-       line Line
+       line line.Line
 }
 
 var G GlobalVars
Index: pkgsrc/pkgtools/pkglint/files/toplevel.go
diff -u pkgsrc/pkgtools/pkglint/files/toplevel.go:1.6 pkgsrc/pkgtools/pkglint/files/toplevel.go:1.7
--- pkgsrc/pkgtools/pkglint/files/toplevel.go:1.6       Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/toplevel.go   Sun Jan 29 14:27:48 2017
@@ -1,6 +1,9 @@
 package main
 
-import "netbsd.org/pkglint/trace"
+import (
+       "netbsd.org/pkglint/line"
+       "netbsd.org/pkglint/trace"
+)
 
 type Toplevel struct {
        previousSubdir string
@@ -37,7 +40,7 @@ func CheckdirToplevel() {
        }
 }
 
-func (ctx *Toplevel) checkSubdir(line Line, commentedOut bool, indentation, subdir, comment string) {
+func (ctx *Toplevel) checkSubdir(line line.Line, commentedOut bool, indentation, subdir, comment string) {
        if commentedOut && comment == "" {
                line.Warnf("%q commented out without giving a reason.", subdir)
        }
Index: pkgsrc/pkgtools/pkglint/files/toplevel_test.go
diff -u pkgsrc/pkgtools/pkglint/files/toplevel_test.go:1.6 pkgsrc/pkgtools/pkglint/files/toplevel_test.go:1.7
--- pkgsrc/pkgtools/pkglint/files/toplevel_test.go:1.6  Sun Jan  1 15:15:47 2017
+++ pkgsrc/pkgtools/pkglint/files/toplevel_test.go      Sun Jan 29 14:27:48 2017
@@ -25,9 +25,9 @@ func (s *Suite) Test_CheckdirToplevel(c 
        G.CurrentDir = s.tmpdir
        CheckdirToplevel()
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: ~/Makefile:3: Indentation should be a single tab character.\n"+
-               "ERROR: ~/Makefile:6: Each subdir must only appear once.\n"+
-               "WARN: ~/Makefile:7: \"ignoreme\" commented out without giving a reason.\n"+
-               "WARN: ~/Makefile:9: bbb should come before ccc\n")
+       s.CheckOutputLines(
+               "WARN: ~/Makefile:3: Indentation should be a single tab character.",
+               "ERROR: ~/Makefile:6: Each subdir must only appear once.",
+               "WARN: ~/Makefile:7: \"ignoreme\" commented out without giving a reason.",
+               "WARN: ~/Makefile:9: bbb should come before ccc")
 }

Index: pkgsrc/pkgtools/pkglint/files/line.go
diff -u pkgsrc/pkgtools/pkglint/files/line.go:1.14 pkgsrc/pkgtools/pkglint/files/line.go:1.15
--- pkgsrc/pkgtools/pkglint/files/line.go:1.14  Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/line.go       Sun Jan 29 14:27:48 2017
@@ -16,6 +16,7 @@ package main
 import (
        "fmt"
        "io"
+       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/regex"
        "path"
        "strconv"
@@ -32,28 +33,6 @@ func (rline *RawLine) String() string {
        return strconv.Itoa(rline.Lineno) + ":" + rline.textnl
 }
 
-type Line interface {
-       fmt.Stringer
-
-       Filename() string
-       Linenos() string
-       Text() string
-       IsMultiline() bool
-       IsChanged() bool
-
-       Fatalf(fmt string, args ...interface{})
-       Errorf(fmt string, args ...interface{})
-       Warnf(fmt string, args ...interface{})
-       Notef(fmt string, args ...interface{})
-       ReferenceFrom(Line) string
-
-       AutofixReplace(from, to string) bool
-       AutofixReplaceRegexp(from regex.RegexPattern, to string) bool
-       AutofixInsertBefore(text string) bool
-       AutofixDelete() bool
-       AutofixMark(reason string)
-}
-
 type LineImpl struct {
        fname          string
        firstLine      int32 // Zero means not applicable, -1 means EOF
@@ -66,22 +45,22 @@ type LineImpl struct {
        autofixMessage string
 }
 
-func NewLine(fname string, lineno int, text string, rawLines []*RawLine) Line {
+func NewLine(fname string, lineno int, text string, rawLines []*RawLine) line.Line {
        return NewLineMulti(fname, lineno, lineno, text, rawLines)
 }
 
 // NewLineMulti is for logical Makefile lines that end with backslash.
-func NewLineMulti(fname string, firstLine, lastLine int, text string, rawLines []*RawLine) Line {
+func NewLineMulti(fname string, firstLine, lastLine int, text string, rawLines []*RawLine) line.Line {
        return &LineImpl{fname, int32(firstLine), int32(lastLine), text, rawLines, false, nil, nil, ""}
 }
 
 // NewLineEOF creates a dummy line for logging, with the "line number" EOF.
-func NewLineEOF(fname string) Line {
+func NewLineEOF(fname string) line.Line {
        return NewLineMulti(fname, -1, 0, "", nil)
 }
 
 // NewLineWhole creates a dummy line for logging messages that affect a file as a whole.
-func NewLineWhole(fname string) Line {
+func NewLineWhole(fname string) line.Line {
        return NewLine(fname, 0, "", nil)
 }
 
@@ -120,7 +99,7 @@ func (line *LineImpl) Linenos() string {
        }
 }
 
-func (line *LineImpl) ReferenceFrom(other Line) string {
+func (line *LineImpl) ReferenceFrom(other line.Line) string {
        if line.fname != other.Filename() {
                return cleanpath(relpath(path.Dir(other.Filename()), line.fname)) + ":" + line.Linenos()
        }
@@ -260,3 +239,7 @@ func (line *LineImpl) AutofixMark(reason
        line.logAutofix()
        line.changed = true
 }
+
+func init() {
+       line.NewLineEOF = NewLineEOF
+}

Index: pkgsrc/pkgtools/pkglint/files/linechecker.go
diff -u pkgsrc/pkgtools/pkglint/files/linechecker.go:1.1 pkgsrc/pkgtools/pkglint/files/linechecker.go:1.2
--- pkgsrc/pkgtools/pkglint/files/linechecker.go:1.1    Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/linechecker.go        Sun Jan 29 14:27:48 2017
@@ -2,12 +2,13 @@ package main
 
 import (
        "fmt"
+       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
 )
 
 type LineChecker struct {
-       Line Line
+       Line line.Line
 }
 
 func (ck LineChecker) CheckAbsolutePathname(text string) {
Index: pkgsrc/pkgtools/pkglint/files/linechecker_test.go
diff -u pkgsrc/pkgtools/pkglint/files/linechecker_test.go:1.1 pkgsrc/pkgtools/pkglint/files/linechecker_test.go:1.2
--- pkgsrc/pkgtools/pkglint/files/linechecker_test.go:1.1       Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/linechecker_test.go   Sun Jan 29 14:27:48 2017
@@ -3,23 +3,28 @@ package main
 import "gopkg.in/check.v1"
 
 func (s *Suite) Test_LineChecker_CheckAbsolutePathname(c *check.C) {
+       s.Init(c)
        ck := LineChecker{NewLine("Makefile", 1, "# dummy", nil)}
 
        ck.CheckAbsolutePathname("bindir=/bin")
        ck.CheckAbsolutePathname("bindir=/../lib")
 
-       c.Check(s.Output(), equals, "WARN: Makefile:1: Found absolute pathname: /bin\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:1: Found absolute pathname: /bin")
 }
 
 func (s *Suite) Test_LineChecker_CheckTrailingWhitespace(c *check.C) {
+       s.Init(c)
        ck := LineChecker{NewLine("Makefile", 32, "The line must go on   ", nil)}
 
        ck.CheckTrailingWhitespace()
 
-       c.Check(s.Output(), equals, "NOTE: Makefile:32: Trailing white-space.\n")
+       s.CheckOutputLines(
+               "NOTE: Makefile:32: Trailing white-space.")
 }
 
 func (s *Suite) Test_LineChecker_CheckRcsid(c *check.C) {
+       s.Init(c)
        lines := s.NewLines("fname",
                "$"+"NetBSD: dummy $",
                "$"+"NetBSD$",
@@ -31,8 +36,8 @@ func (s *Suite) Test_LineChecker_CheckRc
                LineChecker{line}.CheckRcsid(``, "")
        }
 
-       c.Check(s.Output(), equals, ""+
-               "ERROR: fname:3: Expected \"$"+"NetBSD$\".\n"+
-               "ERROR: fname:4: Expected \"$"+"NetBSD$\".\n"+
-               "ERROR: fname:5: Expected \"$"+"NetBSD$\".\n")
+       s.CheckOutputLines(
+               "ERROR: fname:3: Expected \"$"+"NetBSD$\".",
+               "ERROR: fname:4: Expected \"$"+"NetBSD$\".",
+               "ERROR: fname:5: Expected \"$"+"NetBSD$\".")
 }
Index: pkgsrc/pkgtools/pkglint/files/mklinechecker.go
diff -u pkgsrc/pkgtools/pkglint/files/mklinechecker.go:1.1 pkgsrc/pkgtools/pkglint/files/mklinechecker.go:1.2
--- pkgsrc/pkgtools/pkglint/files/mklinechecker.go:1.1  Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/mklinechecker.go      Sun Jan 29 14:27:48 2017
@@ -11,14 +11,14 @@ import (
 )
 
 type MkLineChecker struct {
-       MkLine *MkLine
+       MkLine MkLine
 }
 
 func (ck MkLineChecker) Check() {
        mkline := ck.MkLine
 
-       LineChecker{mkline.Line}.CheckTrailingWhitespace()
-       LineChecker{mkline.Line}.CheckValidCharacters(`[\t -~]`)
+       LineChecker{mkline}.CheckTrailingWhitespace()
+       LineChecker{mkline}.CheckValidCharacters(`[\t -~]`)
 
        switch {
        case mkline.IsVarassign():
@@ -30,8 +30,8 @@ func (ck MkLineChecker) Check() {
                NewShellLine(mkline).CheckShellCommandLine(shellcmd)
 
        case mkline.IsComment():
-               if hasPrefix(mkline.Line.Text(), "# url2pkg-marker") {
-                       mkline.Line.Errorf("This comment indicates unfinished work (url2pkg).")
+               if hasPrefix(mkline.Text(), "# url2pkg-marker") {
+                       mkline.Errorf("This comment indicates unfinished work (url2pkg).")
                }
 
        case mkline.IsInclude():
@@ -58,7 +58,7 @@ func (ck MkLineChecker) checkInclude() {
 
        switch {
        case hasSuffix(includefile, "/Makefile"):
-               mkline.Line.Errorf("Other Makefiles must not be included directly.")
+               mkline.Errorf("Other Makefiles must not be included directly.")
                Explain(
                        "If you want to include portions of another Makefile, extract",
                        "the common parts and put them into a Makefile.common.  After",
@@ -66,7 +66,7 @@ func (ck MkLineChecker) checkInclude() {
                        "Makefile.common.")
 
        case includefile == "../../mk/bsd.prefs.mk":
-               if path.Base(mkline.Line.Filename()) == "buildlink3.mk" {
+               if path.Base(mkline.Filename()) == "buildlink3.mk" {
                        mkline.Notef("For efficiency reasons, please include bsd.fast.prefs.mk instead of bsd.prefs.mk.")
                }
                if G.Pkg != nil {
@@ -88,7 +88,7 @@ func (ck MkLineChecker) checkInclude() {
                mkline.Warnf("Please write \"USE_TOOLS+= intltool\" instead of this line.")
 
        case hasSuffix(includefile, "/builtin.mk"):
-               mkline.Line.Errorf("%s must not be included directly. Include \"%s/buildlink3.mk\" instead.", includefile, path.Dir(includefile))
+               mkline.Errorf("%s must not be included directly. Include \"%s/buildlink3.mk\" instead.", includefile, path.Dir(includefile))
        }
 }
 
@@ -135,7 +135,7 @@ func (ck MkLineChecker) checkCond(forVar
                ck.CheckCond()
 
        } else if directive == "ifdef" || directive == "ifndef" {
-               mkline.Line.Warnf("The \".%s\" directive is deprecated. Please use \".if %sdefined(%s)\" instead.",
+               mkline.Warnf("The \".%s\" directive is deprecated. Please use \".if %sdefined(%s)\" instead.",
                        directive, ifelseStr(directive == "ifdef", "", "!"), args)
 
        } else if directive == "for" {
@@ -160,7 +160,7 @@ func (ck MkLineChecker) checkCond(forVar
                        guessed := true
                        for _, value := range splitOnSpace(values) {
                                if m, vname := match1(value, `^\$\{(.*)\}`); m {
-                                       vartype := mkline.getVariableType(vname)
+                                       vartype := mkline.VariableType(vname)
                                        if vartype != nil && !vartype.guessed {
                                                guessed = false
                                        }
@@ -169,7 +169,7 @@ func (ck MkLineChecker) checkCond(forVar
 
                        forLoopType := &Vartype{lkSpace, BtUnknown, []AclEntry{{"*", aclpAllRead}}, guessed}
                        forLoopContext := &VarUseContext{forLoopType, vucTimeParse, vucQuotFor, false}
-                       for _, forLoopVar := range mkline.extractUsedVariables(values) {
+                       for _, forLoopVar := range mkline.ExtractUsedVariables(values) {
                                ck.CheckVaruse(&MkVarUse{forLoopVar, nil}, forLoopContext)
                        }
                }
@@ -239,7 +239,7 @@ func (ck MkLineChecker) checkVarassignDe
        mkline := ck.MkLine
        varname := mkline.Varname()
        op := mkline.Op()
-       vartype := mkline.getVariableType(varname)
+       vartype := mkline.VariableType(varname)
        if vartype == nil {
                if trace.Tracing {
                        trace.Step1("No type definition found for %q.", varname)
@@ -247,7 +247,7 @@ func (ck MkLineChecker) checkVarassignDe
                return
        }
 
-       perms := vartype.EffectivePermissions(mkline.Line.Filename())
+       perms := vartype.EffectivePermissions(mkline.Filename())
        var needed AclPermissions
        switch op {
        case opAssign, opAssignShell, opAssignEval:
@@ -270,16 +270,16 @@ func (ck MkLineChecker) checkVarassignDe
                alternativeFiles := vartype.AllowedFiles(needed)
                switch {
                case alternativeActions != 0 && alternativeFiles != "":
-                       mkline.Line.Warnf("The variable %s may not be %s (only %s) in this file; it would be ok in %s.",
+                       mkline.Warnf("The variable %s may not be %s (only %s) in this file; it would be ok in %s.",
                                varname, needed.HumanString(), alternativeActions.HumanString(), alternativeFiles)
                case alternativeFiles != "":
-                       mkline.Line.Warnf("The variable %s may not be %s in this file; it would be ok in %s.",
+                       mkline.Warnf("The variable %s may not be %s in this file; it would be ok in %s.",
                                varname, needed.HumanString(), alternativeFiles)
                case alternativeActions != 0:
-                       mkline.Line.Warnf("The variable %s may not be %s (only %s) in this file.",
+                       mkline.Warnf("The variable %s may not be %s (only %s) in this file.",
                                varname, needed.HumanString(), alternativeActions.HumanString())
                default:
-                       mkline.Line.Warnf("The variable %s may not be %s by any package.",
+                       mkline.Warnf("The variable %s may not be %s by any package.",
                                varname, needed.HumanString())
                }
                Explain(
@@ -301,7 +301,7 @@ func (ck MkLineChecker) CheckVaruse(varu
        }
 
        varname := varuse.varname
-       vartype := mkline.getVariableType(varname)
+       vartype := mkline.VariableType(varname)
        if G.opts.WarnExtra &&
                (vartype == nil || vartype.guessed) &&
                !varIsUsed(varname) &&
@@ -316,7 +316,7 @@ func (ck MkLineChecker) CheckVaruse(varu
                ck.WarnVaruseLocalbase()
        }
 
-       needsQuoting := mkline.variableNeedsQuoting(varname, vartype, vuc)
+       needsQuoting := mkline.VariableNeedsQuoting(varname, vartype, vuc)
 
        if vuc.quoting == vucQuotFor {
                ck.checkVaruseFor(varname, vartype, needsQuoting)
@@ -708,7 +708,7 @@ func (ck MkLineChecker) checkVarassignVa
                time = vucTimeParse
        }
 
-       vartype := mkline.getVariableType(mkline.Varname())
+       vartype := mkline.VariableType(mkline.Varname())
        if op == opAssignShell {
                vartype = shellcommandsContextType
        }
@@ -725,7 +725,7 @@ func (ck MkLineChecker) checkVarassignVa
                defer trace.Call(vartype, time)()
        }
        mkline := ck.MkLine
-       tokens := NewMkParser(mkline.Line, mkline.Value(), false).MkTokens()
+       tokens := NewMkParser(mkline, mkline.Value(), false).MkTokens()
        for i, token := range tokens {
                if token.Varuse != nil {
                        spaceLeft := i-1 < 0 || matches(tokens[i-1].Text, `\s$`)
@@ -753,7 +753,7 @@ func (ck MkLineChecker) checkVarassignVa
        }
 
        mkline := ck.MkLine
-       atoms := NewShTokenizer(mkline.Line, mkline.Value(), false).ShAtoms()
+       atoms := NewShTokenizer(mkline, mkline.Value(), false).ShAtoms()
        for i, atom := range atoms {
                if atom.Type == shtVaruse {
                        isWordPart := isWordPart(atoms, i)
@@ -811,7 +811,7 @@ func (ck MkLineChecker) checkVarassignSp
 
        if m, revvarname := match1(value, `\$\{(PKGNAME|PKGVERSION)[:\}]`); m {
                if varname == "DIST_SUBDIR" || varname == "WRKSRC" {
-                       mkline.Line.Warnf("%s should not be used in %s, as it includes the PKGREVISION. Please use %s_NOREV instead.", revvarname, varname, revvarname)
+                       mkline.Warnf("%s should not be used in %s, as it includes the PKGREVISION. Please use %s_NOREV instead.", revvarname, varname, revvarname)
                }
        }
 
@@ -884,7 +884,7 @@ func (ck MkLineChecker) CheckVartype(var
        }
 
        mkline := ck.MkLine
-       vartype := mkline.getVariableType(varname)
+       vartype := mkline.VariableType(varname)
 
        if op == opAssignAppend {
                if vartype != nil && !vartype.MayBeAppendedTo() {
@@ -915,7 +915,7 @@ func (ck MkLineChecker) CheckVartype(var
                }
 
        case vartype.kindOfList == lkShell:
-               words, _ := splitIntoMkWords(mkline.Line, value)
+               words, _ := splitIntoMkWords(mkline, value)
                for _, word := range words {
                        ck.CheckVartypePrimitive(varname, vartype.basicType, op, word, comment, vartype.guessed)
                }
@@ -930,8 +930,8 @@ func (ck MkLineChecker) CheckVartypePrim
        }
 
        mkline := ck.MkLine
-       valueNoVar := mkline.withoutMakeVariables(value)
-       ctx := &VartypeCheck{mkline, mkline.Line, varname, op, value, valueNoVar, comment, guessed}
+       valueNoVar := mkline.WithoutMakeVariables(value)
+       ctx := &VartypeCheck{mkline, mkline, varname, op, value, valueNoVar, comment, guessed}
        checker.checker(ctx)
 }
 
@@ -989,7 +989,7 @@ func (ck MkLineChecker) CheckCond() {
                defer trace.Call1(mkline.Args())()
        }
 
-       p := NewMkParser(mkline.Line, mkline.Args(), false)
+       p := NewMkParser(mkline, mkline.Args(), false)
        cond := p.MkCond()
        if !p.EOF() {
                mkline.Warnf("Invalid conditional %q.", mkline.Args())
@@ -1033,7 +1033,9 @@ func (ck MkLineChecker) CheckCond() {
                }
        })
 
-       mkline.rememberUsedVariables(cond)
+       if G.Mk != nil {
+               G.Mk.indentation.RememberUsedVariables(cond)
+       }
 }
 
 func (ck MkLineChecker) checkCompareVarStr(varname, op, value string) {
@@ -1067,7 +1069,7 @@ func (ck MkLineChecker) CheckRelativePkg
 
        mkline := ck.MkLine
        ck.CheckRelativePath(pkgdir, true)
-       pkgdir = mkline.resolveVarsInRelativePath(pkgdir, false)
+       pkgdir = mkline.ResolveVarsInRelativePath(pkgdir, false)
 
        if m, otherpkgpath := match1(pkgdir, `^(?:\./)?\.\./\.\./([^/]+/[^/]+)$`); m {
                if !fileExists(G.globalData.Pkgsrcdir + "/" + otherpkgpath + "/Makefile") {
@@ -1093,7 +1095,7 @@ func (ck MkLineChecker) CheckRelativePat
                mkline.Errorf("A main pkgsrc package must not depend on a pkgsrc-wip package.")
        }
 
-       resolvedPath := mkline.resolveVarsInRelativePath(path, true)
+       resolvedPath := mkline.ResolveVarsInRelativePath(path, true)
        if containsVarRef(resolvedPath) {
                return
        }
Index: pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go:1.1 pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go:1.2
--- pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go:1.1     Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go Sun Jan 29 14:27:48 2017
@@ -12,7 +12,7 @@ func (s *Suite) Test_MkLineChecker_Check
        c.Assert(vartype1, check.NotNil)
        c.Check(vartype1.guessed, equals, false)
 
-       vartype := mkline.getVariableType("COMMENT")
+       vartype := mkline.VariableType("COMMENT")
 
        c.Assert(vartype, check.NotNil)
        c.Check(vartype.basicType.name, equals, "Comment")
@@ -34,13 +34,14 @@ func (s *Suite) Test_MkLineChecker_Check
 // Pkglint once interpreted all lists as consisting of shell tokens,
 // splitting this URL at the ampersands.
 func (s *Suite) Test_MkLineChecker_checkVarassign__URL_with_shell_special_characters(c *check.C) {
+       s.Init(c)
        G.Pkg = NewPackage("graphics/gimp-fix-ca")
        G.globalData.InitVartypes()
        mkline := NewMkLine(NewLine("fname", 10, "MASTER_SITES=http://registry.gimp.org/file/fix-ca.c?action=download&id=9884&file=";, nil))
 
        MkLineChecker{mkline}.checkVarassign()
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_MkLineChecker_Check__conditions(c *check.C) {
@@ -60,36 +61,42 @@ func (s *Suite) Test_MkLineChecker_Check
 
        MkLineChecker{NewMkLine(NewLine("fname", 1, ".if ${HOMEPAGE} == \"mailto:someone%example.org@localhost\"";, nil))}.CheckCond()
 
-       c.Check(s.Output(), equals, "WARN: fname:1: \"mailto:someone%example.org@localhost\"; is not a valid URL.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: \"mailto:someone%example.org@localhost\"; is not a valid URL.")
 
        MkLineChecker{NewMkLine(NewLine("fname", 1, ".if !empty(PKGSRC_RUN_TEST:M[Y][eE][sS])", nil))}.CheckCond()
 
-       c.Check(s.Output(), equals, "WARN: fname:1: PKGSRC_RUN_TEST should be matched against \"[yY][eE][sS]\" or \"[nN][oO]\", not \"[Y][eE][sS]\".\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: PKGSRC_RUN_TEST should be matched against \"[yY][eE][sS]\" or \"[nN][oO]\", not \"[Y][eE][sS]\".")
 
        MkLineChecker{NewMkLine(NewLine("fname", 1, ".if !empty(IS_BUILTIN.Xfixes:M[yY][eE][sS])", nil))}.CheckCond()
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 
        MkLineChecker{NewMkLine(NewLine("fname", 1, ".if !empty(${IS_BUILTIN.Xfixes:M[yY][eE][sS]})", nil))}.CheckCond()
 
-       c.Check(s.Output(), equals, "WARN: fname:1: The empty() function takes a variable name as parameter, not a variable expression.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: The empty() function takes a variable name as parameter, not a variable expression.")
 
        MkLineChecker{NewMkLine(NewLine("fname", 1, ".if ${EMUL_PLATFORM} == \"linux-x386\"", nil))}.CheckCond()
 
-       c.Check(s.Output(), equals, "WARN: fname:1: \"x386\" is not valid for the hardware architecture part of EMUL_PLATFORM. Use one of { aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt 
coldfire convex dreamcast earm earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 
i586 i686 ia64 m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } instead.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: \"x386\" is not valid for the hardware architecture part of EMUL_PLATFORM. Use one of { aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex 
dreamcast earm earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 
m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } instead.")
 
        MkLineChecker{NewMkLine(NewLine("fname", 1, ".if ${EMUL_PLATFORM:Mlinux-x386}", nil))}.CheckCond()
 
-       c.Check(s.Output(), equals, "WARN: fname:1: The pattern \"x386\" cannot match any of { aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast earm earmeb earmhf 
earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 m68000 m68k m88k mips mips64 
mips64eb mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } for the hardware architecture part of EMUL_PLATFORM.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: The pattern \"x386\" cannot match any of { aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast earm earmeb earmhf earmhfeb earmv4 
earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 m68000 m68k m88k mips mips64 mips64eb mips64el 
mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } for the hardware architecture part of EMUL_PLATFORM.")
 
        MkLineChecker{NewMkLine(NewLine("fname", 98, ".if ${MACHINE_PLATFORM:MUnknownOS-*-*} || ${MACHINE_ARCH:Mx86}", nil))}.CheckCond()
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:98: The pattern \"UnknownOS\" cannot match any of { AIX BSDOS Bitrig Cygwin Darwin DragonFly FreeBSD FreeMiNT GNUkFreeBSD HPUX Haiku IRIX Interix Linux Minix MirBSD 
NetBSD OSF1 OpenBSD QNX SCO_SV SunOS UnixWare } for the operating system part of MACHINE_PLATFORM.\n"+
-               "WARN: fname:98: The pattern \"x86\" cannot match any of { aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast earm earmeb earmhf earmhfeb earmv4 
earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 m68000 m68k m88k mips mips64 mips64eb mips64el 
mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } for MACHINE_ARCH.\n")
+       s.CheckOutputLines(
+               "WARN: fname:98: The pattern \"UnknownOS\" cannot match any of { AIX BSDOS Bitrig Cygwin Darwin DragonFly FreeBSD FreeMiNT GNUkFreeBSD HPUX Haiku IRIX Interix Linux Minix MirBSD 
NetBSD OSF1 OpenBSD QNX SCO_SV SunOS UnixWare } for the operating system part of MACHINE_PLATFORM.",
+               "WARN: fname:98: The pattern \"x86\" cannot match any of { aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast earm earmeb earmhf earmhfeb earmv4 
earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 m68000 m68k m88k mips mips64 mips64eb mips64el 
mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } for MACHINE_ARCH.")
 }
 
 func (s *Suite) Test_MkLineChecker_checkVarassign(c *check.C) {
+       s.Init(c)
        G.globalData.InitVartypes()
 
        G.Mk = s.NewMkLines("Makefile",
@@ -98,7 +105,8 @@ func (s *Suite) Test_MkLineChecker_check
 
        MkLineChecker{G.Mk.mklines[1]}.checkVarassign()
 
-       c.Check(s.Output(), equals, "WARN: Makefile:2: ac_cv_libpari_libs is defined but not used. Spelling mistake?\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:2: ac_cv_libpari_libs is defined but not used. Spelling mistake?")
 }
 
 func (s *Suite) Test_MkLineChecker_checkVarassignDefPermissions(c *check.C) {
@@ -109,7 +117,8 @@ func (s *Suite) Test_MkLineChecker_check
 
        MkLineChecker{mkline}.checkVarassignDefPermissions()
 
-       c.Check(s.Output(), equals, "WARN: options.mk:2: The variable PKG_DEVELOPER may not be given a default value by any package.\n")
+       s.CheckOutputLines(
+               "WARN: options.mk:2: The variable PKG_DEVELOPER may not be given a default value by any package.")
 }
 
 func (s *Suite) Test_MkLineChecker_CheckVarusePermissions(c *check.C) {
@@ -121,18 +130,18 @@ func (s *Suite) Test_MkLineChecker_Check
                "COMMENT=\t${GAMES_USER}",
                "COMMENT:=\t${PKGBASE}",
                "PYPKGPREFIX=${PKGBASE}")
-       G.globalData.UserDefinedVars = map[string]*MkLine{
+       G.globalData.UserDefinedVars = map[string]MkLine{
                "GAMES_USER": mklines.mklines[0],
        }
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: options.mk:2: The user-defined variable GAMES_USER is used but not added to BUILD_DEFS.\n"+
-               "WARN: options.mk:3: PKGBASE should not be evaluated at load time.\n"+
-               "WARN: options.mk:4: The variable PYPKGPREFIX may not be set in this file; it would be ok in pyversion.mk.\n"+
-               "WARN: options.mk:4: PKGBASE should not be evaluated indirectly at load time.\n"+
-               "NOTE: options.mk:4: This variable value should be aligned to column 17.\n")
+       s.CheckOutputLines(
+               "WARN: options.mk:2: The user-defined variable GAMES_USER is used but not added to BUILD_DEFS.",
+               "WARN: options.mk:3: PKGBASE should not be evaluated at load time.",
+               "WARN: options.mk:4: The variable PYPKGPREFIX may not be set in this file; it would be ok in pyversion.mk.",
+               "WARN: options.mk:4: PKGBASE should not be evaluated indirectly at load time.",
+               "NOTE: options.mk:4: This variable value should be aligned to column 17.")
 }
 
 func (s *Suite) Test_MkLineChecker_CheckVarusePermissions__load_time(c *check.C) {
@@ -145,37 +154,41 @@ func (s *Suite) Test_MkLineChecker_Check
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, "") // Don't warn that ".CURDIR should not be evaluated at load time."
+       s.CheckOutputEmpty() // Don't warn that ".CURDIR should not be evaluated at load time."
 }
 
 func (s *Suite) Test_MkLineChecker_WarnVaruseLocalbase(c *check.C) {
+       s.Init(c)
        mkline := NewMkLine(NewLine("options.mk", 56, "PKGNAME=${LOCALBASE}", nil))
 
        MkLineChecker{mkline}.WarnVaruseLocalbase()
 
-       c.Check(s.Output(), equals, "WARN: options.mk:56: The LOCALBASE variable should not be used by packages.\n")
+       s.CheckOutputLines(
+               "WARN: options.mk:56: The LOCALBASE variable should not be used by packages.")
 }
 
 func (s *Suite) Test_MkLineChecker_CheckRelativePkgdir(c *check.C) {
+       s.Init(c)
        mkline := NewMkLine(NewLine("Makefile", 46, "# dummy", nil))
 
        MkLineChecker{mkline}.CheckRelativePkgdir("../pkgbase")
 
-       c.Check(s.Output(), equals, ""+
-               "ERROR: Makefile:46: \"../pkgbase\" does not exist.\n"+
-               "WARN: Makefile:46: \"../pkgbase\" is not a valid relative package directory.\n")
+       s.CheckOutputLines(
+               "ERROR: Makefile:46: \"../pkgbase\" does not exist.",
+               "WARN: Makefile:46: \"../pkgbase\" is not a valid relative package directory.")
 }
 
 // PR pkg/46570, item 2
 func (s *Suite) Test_MkLineChecker__unclosed_varuse(c *check.C) {
+       s.Init(c)
        mkline := NewMkLine(NewLine("Makefile", 93, "EGDIRS=${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d", nil))
 
        MkLineChecker{mkline}.checkVarassign()
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: Makefile:93: Pkglint parse error in MkLine.Tokenize at \"${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d\".\n"+
-               "WARN: Makefile:93: Pkglint parse error in ShTokenizer.ShAtom at \"${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d\" (quoting=plain)\n"+
-               "WARN: Makefile:93: EGDIRS is defined but not used. Spelling mistake?\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:93: Pkglint parse error in MkLine.Tokenize at \"${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d\".",
+               "WARN: Makefile:93: Pkglint parse error in ShTokenizer.ShAtom at \"${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d\" (quoting=plain)",
+               "WARN: Makefile:93: EGDIRS is defined but not used. Spelling mistake?")
 }
 
 func (s *Suite) Test_MkLineChecker__Varuse_Modifier_L(c *check.C) {
@@ -187,7 +200,7 @@ func (s *Suite) Test_MkLineChecker__Varu
 
        MkLineChecker{G.Mk.mklines[0]}.Check()
 
-       c.Check(s.Output(), equals, "") // Don't warn that ${XKBBASE}/xkbcomp is used but not defined.
+       s.CheckOutputEmpty() // Don't warn that ${XKBBASE}/xkbcomp is used but not defined.
 }
 
 func (s *Suite) Test_MkLineChecker_CheckCond__comparison_with_shell_command(c *check.C) {
@@ -202,7 +215,8 @@ func (s *Suite) Test_MkLineChecker_Check
        G.Mk.Check()
 
        // Don't warn about unknown shell command "cc".
-       c.Check(s.Output(), equals, "WARN: security/openssl/Makefile:2: Use ${PKGSRC_COMPILER:Mgcc} instead of the == operator.\n")
+       s.CheckOutputLines(
+               "WARN: security/openssl/Makefile:2: Use ${PKGSRC_COMPILER:Mgcc} instead of the == operator.")
 }
 
 func (s *Suite) Test_MkLine_CheckCond_comparing_PKGSRC_COMPILER_with_eqeq(c *check.C) {
@@ -216,7 +230,8 @@ func (s *Suite) Test_MkLine_CheckCond_co
 
        G.Mk.Check()
 
-       c.Check(s.Output(), equals, "WARN: audio/pulseaudio/Makefile:2: Use ${PKGSRC_COMPILER:Mclang} instead of the == operator.\n")
+       s.CheckOutputLines(
+               "WARN: audio/pulseaudio/Makefile:2: Use ${PKGSRC_COMPILER:Mclang} instead of the == operator.")
 }
 
 func (s *Suite) Test_MkLineChecker_CheckVartype__CFLAGS_with_backticks(c *check.C) {
@@ -228,20 +243,21 @@ func (s *Suite) Test_MkLineChecker_Check
                "CFLAGS+=\t`pkg-config pidgin --cflags`")
        mkline := G.Mk.mklines[1]
 
-       words, rest := splitIntoMkWords(mkline.Line, mkline.Value())
+       words, rest := splitIntoMkWords(mkline, mkline.Value())
 
        c.Check(words, deepEquals, []string{"`pkg-config pidgin --cflags`"})
        c.Check(rest, equals, "")
 
        MkLineChecker{G.Mk.mklines[1]}.CheckVartype("CFLAGS", opAssignAppend, "`pkg-config pidgin --cflags`", "")
 
-       c.Check(s.Output(), equals, "") // No warning about "`pkg-config" being an unknown CFlag.
+       s.CheckOutputEmpty() // No warning about "`pkg-config" being an unknown CFlag.
 }
 
 // See PR 46570, Ctrl+F "4. Shell quoting".
 // Pkglint is correct, since the shell sees this definition for
 // CPPFLAGS as three words, not one word.
 func (s *Suite) Test_MkLineChecker_CheckVartype_CFLAGS(c *check.C) {
+       s.Init(c)
        G.globalData.InitVartypes()
        mklines := s.NewMkLines("Makefile",
                mkrcsid,
@@ -249,7 +265,7 @@ func (s *Suite) Test_MkLineChecker_Check
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: Makefile:2: Unknown compiler flag \"-bs\".\n"+
-               "WARN: Makefile:2: Compiler flag \"%s\\\\\\\"\" should start with a hyphen.\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:2: Unknown compiler flag \"-bs\".",
+               "WARN: Makefile:2: Compiler flag \"%s\\\\\\\"\" should start with a hyphen.")
 }

Index: pkgsrc/pkgtools/pkglint/files/mkline.go
diff -u pkgsrc/pkgtools/pkglint/files/mkline.go:1.21 pkgsrc/pkgtools/pkglint/files/mkline.go:1.22
--- pkgsrc/pkgtools/pkglint/files/mkline.go:1.21        Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/mkline.go     Sun Jan 29 14:27:48 2017
@@ -4,13 +4,59 @@ package main
 
 import (
        "fmt"
+       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
        "strings"
 )
 
-type MkLine struct {
-       Line
+type MkLine interface {
+       line.Line
+
+       IsVarassign() bool
+       Varname() string
+       Varcanon() string
+       Varparam() string
+       Op() MkOperator
+       ValueAlign() string
+       Value() string
+       VarassignComment() string
+
+       IsShellcmd() bool
+       Shellcmd() string
+
+       IsComment() bool
+
+       IsEmpty() bool
+
+       IsCond() bool
+       Indent() string
+       Directive() string
+       Args() string
+
+       IsInclude() bool
+       IsSysinclude() bool
+       // Indent() works here, too.
+       MustExist() bool
+       Includefile() string
+       ConditionVars() string
+       SetConditionVars(varnames string) // Initialized lazily
+
+       IsDependency() bool
+       Targets() string
+       Sources() string
+
+       VariableType(varname string) *Vartype
+       ResolveVarsInRelativePath(relpath string, adjustDepth bool) string
+       ExtractUsedVariables(value string) []string
+       WithoutMakeVariables(value string) string
+       VariableNeedsQuoting(varname string, vartype *Vartype, vuc *VarUseContext) NeedsQuoting
+       DetermineUsedVariables() []string
+       ExplainRelativeDirs()
+}
+
+type MkLineImpl struct {
+       line.Line
        data interface{} // One of the following mkLine* types
 }
 type mkLineAssign struct {
@@ -44,8 +90,8 @@ type mkLineDependency struct {
        sources string
 }
 
-func NewMkLine(line Line) (mkline *MkLine) {
-       mkline = &MkLine{Line: line}
+func NewMkLine(line line.Line) (mkline *MkLineImpl) {
+       mkline = &MkLineImpl{Line: line}
 
        text := line.Text()
 
@@ -141,51 +187,58 @@ func NewMkLine(line Line) (mkline *MkLin
        return mkline
 }
 
-func (mkline *MkLine) String() string {
-       return fmt.Sprintf("%s:%s", mkline.Line.Filename(), mkline.Line.Linenos())
+func (mkline *MkLineImpl) String() string {
+       return fmt.Sprintf("%s:%s", mkline.Filename(), mkline.Linenos())
 }
-func (mkline *MkLine) IsVarassign() bool { _, ok := mkline.data.(mkLineAssign); return ok }
-func (mkline *MkLine) IsShellcmd() bool  { _, ok := mkline.data.(mkLineShell); return ok }
-func (mkline *MkLine) IsComment() bool   { _, ok := mkline.data.(mkLineComment); return ok }
-func (mkline *MkLine) IsEmpty() bool     { _, ok := mkline.data.(mkLineEmpty); return ok }
-func (mkline *MkLine) IsCond() bool      { _, ok := mkline.data.(mkLineConditional); return ok }
-func (mkline *MkLine) IsInclude() bool {
+func (mkline *MkLineImpl) IsVarassign() bool { _, ok := mkline.data.(mkLineAssign); return ok }
+func (mkline *MkLineImpl) IsShellcmd() bool  { _, ok := mkline.data.(mkLineShell); return ok }
+func (mkline *MkLineImpl) IsComment() bool   { _, ok := mkline.data.(mkLineComment); return ok }
+func (mkline *MkLineImpl) IsEmpty() bool     { _, ok := mkline.data.(mkLineEmpty); return ok }
+func (mkline *MkLineImpl) IsCond() bool      { _, ok := mkline.data.(mkLineConditional); return ok }
+func (mkline *MkLineImpl) IsInclude() bool {
        incl, ok := mkline.data.(mkLineInclude)
        return ok && !incl.sys
 }
-func (mkline *MkLine) IsSysinclude() bool {
+func (mkline *MkLineImpl) IsSysinclude() bool {
        incl, ok := mkline.data.(mkLineInclude)
        return ok && incl.sys
 }
-func (mkline *MkLine) IsDependency() bool       { _, ok := mkline.data.(mkLineDependency); return ok }
-func (mkline *MkLine) Varname() string          { return mkline.data.(mkLineAssign).varname }
-func (mkline *MkLine) Varcanon() string         { return mkline.data.(mkLineAssign).varcanon }
-func (mkline *MkLine) Varparam() string         { return mkline.data.(mkLineAssign).varparam }
-func (mkline *MkLine) Op() MkOperator           { return mkline.data.(mkLineAssign).op }
-func (mkline *MkLine) ValueAlign() string       { return mkline.data.(mkLineAssign).valueAlign }
-func (mkline *MkLine) Value() string            { return mkline.data.(mkLineAssign).value }
-func (mkline *MkLine) VarassignComment() string { return mkline.data.(mkLineAssign).comment }
-func (mkline *MkLine) Shellcmd() string         { return mkline.data.(mkLineShell).command }
-func (mkline *MkLine) Indent() string {
+func (mkline *MkLineImpl) IsDependency() bool       { _, ok := mkline.data.(mkLineDependency); return ok }
+func (mkline *MkLineImpl) Varname() string          { return mkline.data.(mkLineAssign).varname }
+func (mkline *MkLineImpl) Varcanon() string         { return mkline.data.(mkLineAssign).varcanon }
+func (mkline *MkLineImpl) Varparam() string         { return mkline.data.(mkLineAssign).varparam }
+func (mkline *MkLineImpl) Op() MkOperator           { return mkline.data.(mkLineAssign).op }
+func (mkline *MkLineImpl) ValueAlign() string       { return mkline.data.(mkLineAssign).valueAlign }
+func (mkline *MkLineImpl) Value() string            { return mkline.data.(mkLineAssign).value }
+func (mkline *MkLineImpl) VarassignComment() string { return mkline.data.(mkLineAssign).comment }
+func (mkline *MkLineImpl) Shellcmd() string         { return mkline.data.(mkLineShell).command }
+func (mkline *MkLineImpl) Indent() string {
        if mkline.IsCond() {
                return mkline.data.(mkLineConditional).indent
        } else {
                return mkline.data.(mkLineInclude).indent
        }
 }
-func (mkline *MkLine) Directive() string   { return mkline.data.(mkLineConditional).directive }
-func (mkline *MkLine) Args() string        { return mkline.data.(mkLineConditional).args }
-func (mkline *MkLine) MustExist() bool     { return mkline.data.(mkLineInclude).mustexist }
-func (mkline *MkLine) Includefile() string { return mkline.data.(mkLineInclude).includeFile }
-func (mkline *MkLine) Targets() string     { return mkline.data.(mkLineDependency).targets }
-func (mkline *MkLine) Sources() string     { return mkline.data.(mkLineDependency).sources }
+func (mkline *MkLineImpl) Directive() string   { return mkline.data.(mkLineConditional).directive }
+func (mkline *MkLineImpl) Args() string        { return mkline.data.(mkLineConditional).args }
+func (mkline *MkLineImpl) MustExist() bool     { return mkline.data.(mkLineInclude).mustexist }
+func (mkline *MkLineImpl) Includefile() string { return mkline.data.(mkLineInclude).includeFile }
+func (mkline *MkLineImpl) Targets() string     { return mkline.data.(mkLineDependency).targets }
+func (mkline *MkLineImpl) Sources() string     { return mkline.data.(mkLineDependency).sources }
+
+func (mkline *MkLineImpl) ConditionVars() string { return mkline.data.(mkLineInclude).conditionVars }
+func (mkline *MkLineImpl) SetConditionVars(varnames string) {
+       include := mkline.data.(mkLineInclude)
+       include.conditionVars = varnames
+       mkline.data = include
+}
 
-func (mkline *MkLine) Tokenize(s string) []*MkToken {
+func (mkline *MkLineImpl) Tokenize(s string) []*MkToken {
        if trace.Tracing {
                defer trace.Call(mkline, s)()
        }
 
-       p := NewMkParser(mkline.Line, s, true)
+       p := NewMkParser(mkline, s, true)
        tokens := p.MkTokens()
        if p.Rest() != "" {
                mkline.Warnf("Pkglint parse error in MkLine.Tokenize at %q.", p.Rest())
@@ -193,7 +246,7 @@ func (mkline *MkLine) Tokenize(s string)
        return tokens
 }
 
-func (mkline *MkLine) withoutMakeVariables(value string) string {
+func (mkline *MkLineImpl) WithoutMakeVariables(value string) string {
        valueNovar := value
        for {
                var m []string
@@ -204,7 +257,7 @@ func (mkline *MkLine) withoutMakeVariabl
        }
 }
 
-func (mkline *MkLine) resolveVarsInRelativePath(relpath string, adjustDepth bool) string {
+func (mkline *MkLineImpl) ResolveVarsInRelativePath(relpath string, adjustDepth bool) string {
        tmp := relpath
        tmp = strings.Replace(tmp, "${PKGSRCDIR}", G.CurPkgsrcdir, -1)
        tmp = strings.Replace(tmp, "${.CURDIR}", ".", -1)
@@ -242,23 +295,18 @@ func (mkline *MkLine) resolveVarsInRelat
        return tmp
 }
 
-func (mkline *MkLine) rememberUsedVariables(cond *Tree) {
-       if G.Mk == nil {
-               return
-       }
-
-       indentation := &G.Mk.indentation
+func (ind *Indentation) RememberUsedVariables(cond *Tree) {
        arg0varname := func(node *Tree) {
                varname := node.args[0].(string)
-               indentation.AddVar(varname)
+               ind.AddVar(varname)
        }
        arg0varuse := func(node *Tree) {
                varuse := node.args[0].(MkVarUse)
-               indentation.AddVar(varuse.varname)
+               ind.AddVar(varuse.varname)
        }
        arg2varuse := func(node *Tree) {
                varuse := node.args[2].(MkVarUse)
-               indentation.AddVar(varuse.varname)
+               ind.AddVar(varuse.varname)
        }
        cond.Visit("defined", arg0varname)
        cond.Visit("empty", arg0varuse)
@@ -268,7 +316,7 @@ func (mkline *MkLine) rememberUsedVariab
        cond.Visit("compareVarVar", arg2varuse)
 }
 
-func (mkline *MkLine) explainRelativeDirs() {
+func (mkline *MkLineImpl) ExplainRelativeDirs() {
        Explain(
                "Directories in the form \"../../category/package\" make it easier to",
                "move a package around in pkgsrc, for example from pkgsrc-wip to the",
@@ -334,7 +382,7 @@ func (nq NeedsQuoting) String() string {
        return [...]string{"no", "yes", "doesn't matter", "don't know"}[nq]
 }
 
-func (mkline *MkLine) variableNeedsQuoting(varname string, vartype *Vartype, vuc *VarUseContext) (needsQuoting NeedsQuoting) {
+func (mkline *MkLineImpl) VariableNeedsQuoting(varname string, vartype *Vartype, vuc *VarUseContext) (needsQuoting NeedsQuoting) {
        if trace.Tracing {
                defer trace.Call(varname, vartype, vuc, "=>", &needsQuoting)()
        }
@@ -443,7 +491,7 @@ func (mkline *MkLine) variableNeedsQuoti
 
 // Returns the type of the variable (maybe guessed based on the variable name),
 // or nil if the type cannot even be guessed.
-func (mkline *MkLine) getVariableType(varname string) *Vartype {
+func (mkline *MkLineImpl) VariableType(varname string) *Vartype {
        if trace.Tracing {
                defer trace.Call1(varname)()
        }
@@ -522,7 +570,7 @@ func (mkline *MkLine) getVariableType(va
 }
 
 // TODO: merge with determineUsedVariables
-func (mkline *MkLine) extractUsedVariables(text string) []string {
+func (mkline *MkLineImpl) ExtractUsedVariables(text string) []string {
        re := regex.Compile(`^(?:[^\$]+|\$[\$*<>?@]|\$\{([.0-9A-Z_a-z]+)(?::(?:[^\${}]|\$[^{])+)?\})`)
        rest := text
        var result []string
@@ -544,8 +592,8 @@ func (mkline *MkLine) extractUsedVariabl
        return result
 }
 
-func (mkline *MkLine) determineUsedVariables() (varnames []string) {
-       rest := mkline.Line.Text()
+func (mkline *MkLineImpl) DetermineUsedVariables() (varnames []string) {
+       rest := mkline.Text()
 
        if strings.HasPrefix(rest, "#") {
                return
Index: pkgsrc/pkgtools/pkglint/files/vardefs.go
diff -u pkgsrc/pkgtools/pkglint/files/vardefs.go:1.21 pkgsrc/pkgtools/pkglint/files/vardefs.go:1.22
--- pkgsrc/pkgtools/pkglint/files/vardefs.go:1.21       Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/vardefs.go    Sun Jan 29 14:27:48 2017
@@ -135,7 +135,7 @@ func (gd *GlobalData) InitVartypes() {
        usr("LOCALPATCHES", lkNone, BtPathname)
 
        // The remaining variables from mk/defaults/mk.conf follow the
-       // naming conventions from MkLine.getVariableType, furthermore
+       // naming conventions from MkLine.VariableType, furthermore
        // they may be redefined by packages. Therefore they cannot be
        // defined as user-defined.
        if false {

Index: pkgsrc/pkgtools/pkglint/files/mkline_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mkline_test.go:1.22 pkgsrc/pkgtools/pkglint/files/mkline_test.go:1.23
--- pkgsrc/pkgtools/pkglint/files/mkline_test.go:1.22   Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/mkline_test.go        Sun Jan 29 14:27:48 2017
@@ -75,10 +75,10 @@ func (s *Suite) Test_VaralignBlock_Check
        }
        varalign.Finish()
 
-       c.Check(s.Output(), equals, ""+
-               "NOTE: file.mk:1: Variable values should be aligned with tabs, not spaces.\n"+
-               "NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 9.\n"+
-               "NOTE: file.mk:3: This variable value should be aligned to column 9.\n")
+       s.CheckOutputLines(
+               "NOTE: file.mk:1: Variable values should be aligned with tabs, not spaces.",
+               "NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 9.",
+               "NOTE: file.mk:3: This variable value should be aligned to column 9.")
 }
 
 func (s *Suite) Test_VaralignBlock_Check_longest_line_no_space(c *check.C) {
@@ -96,11 +96,11 @@ func (s *Suite) Test_VaralignBlock_Check
        }
        varalign.Finish()
 
-       c.Check(s.Output(), equals, ""+
-               "NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 33.\n"+
-               "NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 33.\n"+
-               "NOTE: file.mk:3: This variable value should be aligned with tabs, not spaces, to column 33.\n"+
-               "NOTE: file.mk:4: This variable value should be aligned to column 33.\n")
+       s.CheckOutputLines(
+               "NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 33.",
+               "NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 33.",
+               "NOTE: file.mk:3: This variable value should be aligned with tabs, not spaces, to column 33.",
+               "NOTE: file.mk:4: This variable value should be aligned to column 33.")
 }
 
 func (s *Suite) Test_VaralignBlock_Check_only_spaces(c *check.C) {
@@ -118,11 +118,11 @@ func (s *Suite) Test_VaralignBlock_Check
        }
        varalign.Finish()
 
-       c.Check(s.Output(), equals, ""+
-               "NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 33.\n"+
-               "NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 33.\n"+
-               "NOTE: file.mk:3: This variable value should be aligned with tabs, not spaces, to column 33.\n"+
-               "NOTE: file.mk:4: This variable value should be aligned with tabs, not spaces, to column 33.\n")
+       s.CheckOutputLines(
+               "NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 33.",
+               "NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 33.",
+               "NOTE: file.mk:3: This variable value should be aligned with tabs, not spaces, to column 33.",
+               "NOTE: file.mk:4: This variable value should be aligned with tabs, not spaces, to column 33.")
 }
 
 func (s *Suite) Test_NewMkLine(c *check.C) {
@@ -180,7 +180,8 @@ func (s *Suite) Test_NewMkLine(c *check.
        c.Check(ln[9].Varcanon(), equals, "VARNAME")
        c.Check(ln[9].Varparam(), equals, "")
 
-       c.Check(s.Output(), equals, "WARN: test.mk:9: Space before colon in dependency line.\n")
+       s.CheckOutputLines(
+               "WARN: test.mk:9: Space before colon in dependency line.")
 }
 
 func (s *Suite) Test_NewMkLine__autofix_space_after_varname(c *check.C) {
@@ -195,19 +196,19 @@ func (s *Suite) Test_NewMkLine__autofix_
 
        CheckfileMk(fname)
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: ~/Makefile:2: Unnecessary space after variable name \"VARNAME\".\n"+
-               "WARN: ~/Makefile:4: Unnecessary space after variable name \"VARNAME+\".\n")
+       s.CheckOutputLines(
+               "WARN: ~/Makefile:2: Unnecessary space after variable name \"VARNAME\".",
+               "WARN: ~/Makefile:4: Unnecessary space after variable name \"VARNAME+\".")
 
        s.UseCommandLine("-Wspace", "--autofix")
 
        CheckfileMk(fname)
 
-       c.Check(s.Output(), equals, ""+
-               "AUTOFIX: ~/Makefile:2: Replacing \"VARNAME +=\" with \"VARNAME+=\".\n"+
-               "AUTOFIX: ~/Makefile:4: Replacing \"VARNAME+ +=\" with \"VARNAME++=\".\n"+
-               "AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.\n"+
-               "AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.\n")
+       s.CheckOutputLines(
+               "AUTOFIX: ~/Makefile:2: Replacing \"VARNAME +=\" with \"VARNAME+=\".",
+               "AUTOFIX: ~/Makefile:4: Replacing \"VARNAME+ +=\" with \"VARNAME++=\".",
+               "AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.",
+               "AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.")
        c.Check(s.LoadTmpFile("Makefile"), equals, ""+
                mkrcsid+"\n"+
                "VARNAME+=\t${VARNAME}\n"+
@@ -216,16 +217,16 @@ func (s *Suite) Test_NewMkLine__autofix_
                "pkgbase := pkglint\n")
 }
 
-func (s *Suite) Test_MkLine_getVariableType_varparam(c *check.C) {
+func (s *Suite) Test_MkLine_VariableType_varparam(c *check.C) {
        mkline := NewMkLine(NewLine("fname", 1, "# dummy", nil))
        G.globalData.InitVartypes()
 
-       t1 := mkline.getVariableType("FONT_DIRS")
+       t1 := mkline.VariableType("FONT_DIRS")
 
        c.Assert(t1, check.NotNil)
        c.Check(t1.String(), equals, "ShellList of Pathmask")
 
-       t2 := mkline.getVariableType("FONT_DIRS.ttf")
+       t2 := mkline.VariableType("FONT_DIRS.ttf")
 
        c.Assert(t2, check.NotNil)
        c.Check(t2.String(), equals, "ShellList of Pathmask")
@@ -234,7 +235,7 @@ func (s *Suite) Test_MkLine_getVariableT
 func (s *Suite) Test_VarUseContext_String(c *check.C) {
        G.globalData.InitVartypes()
        mkline := NewMkLine(NewLine("fname", 1, "# dummy", nil))
-       vartype := mkline.getVariableType("PKGNAME")
+       vartype := mkline.VariableType("PKGNAME")
        vuc := &VarUseContext{vartype, vucTimeUnknown, vucQuotBackt, false}
 
        c.Check(vuc.String(), equals, "(PkgName time:unknown quoting:backt wordpart:false)")
@@ -244,6 +245,7 @@ func (s *Suite) Test_VarUseContext_Strin
 // it is escaped by a backslash. In shell commands, on the other hand, it
 // is interpreted literally.
 func (s *Suite) Test_NewMkLine_numbersign(c *check.C) {
+       s.Init(c)
        mklineVarassignEscaped := NewMkLine(NewLine("fname", 1, "SED_CMD=\t's,\\#,hash,g'", nil))
 
        c.Check(mklineVarassignEscaped.Varname(), equals, "SED_CMD")
@@ -257,18 +259,21 @@ func (s *Suite) Test_NewMkLine_numbersig
        mklineCommandUnescaped := NewMkLine(NewLine("fname", 1, "\t# $ sha1 patches/patch-ac", nil))
 
        c.Check(mklineCommandUnescaped.Shellcmd(), equals, "# $ sha1 patches/patch-ac")
-       c.Check(s.Output(), equals, "") // No warning about parsing the lonely dollar sign.
+       s.CheckOutputEmpty() // No warning about parsing the lonely dollar sign.
 
        mklineVarassignUnescaped := NewMkLine(NewLine("fname", 1, "SED_CMD=\t's,#,hash,'", nil))
 
        c.Check(mklineVarassignUnescaped.Value(), equals, "'s,")
-       c.Check(s.Output(), equals, "WARN: fname:1: The # character starts a comment.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: The # character starts a comment.")
 }
 
 func (s *Suite) Test_NewMkLine_leading_space(c *check.C) {
+       s.Init(c)
        _ = NewMkLine(NewLine("rubyversion.mk", 427, " _RUBYVER=\t2.15", nil))
 
-       c.Check(s.Output(), equals, "WARN: rubyversion.mk:427: Makefile lines should not start with space characters.\n")
+       s.CheckOutputLines(
+               "WARN: rubyversion.mk:427: Makefile lines should not start with space characters.")
 }
 
 func (s *Suite) Test_MkLines_Check__extra(c *check.C) {
@@ -290,13 +295,13 @@ func (s *Suite) Test_MkLines_Check__extr
 
        G.Mk.Check()
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: options.mk:3: The values for PYTHON_VERSIONS_ACCEPTED should be in decreasing order.\n"+
-               "NOTE: options.mk:4: Please .include \"../../meta-pkgs/kde3/kde3.mk\" instead of this line.\n"+
-               "NOTE: options.mk:5: Please use \"# empty\", \"# none\" or \"yes\" instead of \"# defined\".\n"+
-               "WARN: options.mk:7: Please include \"../../mk/bsd.prefs.mk\" before using \"?=\".\n"+
-               "WARN: options.mk:10: Building the package should take place entirely inside ${WRKSRC}, not \"${WRKSRC}/..\".\n"+
-               "NOTE: options.mk:10: You can use \"../build\" instead of \"${WRKSRC}/../build\".\n")
+       s.CheckOutputLines(
+               "WARN: options.mk:3: The values for PYTHON_VERSIONS_ACCEPTED should be in decreasing order.",
+               "NOTE: options.mk:4: Please .include \"../../meta-pkgs/kde3/kde3.mk\" instead of this line.",
+               "NOTE: options.mk:5: Please use \"# empty\", \"# none\" or \"yes\" instead of \"# defined\".",
+               "WARN: options.mk:7: Please include \"../../mk/bsd.prefs.mk\" before using \"?=\".",
+               "WARN: options.mk:10: Building the package should take place entirely inside ${WRKSRC}, not \"${WRKSRC}/..\".",
+               "NOTE: options.mk:10: You can use \"../build\" instead of \"${WRKSRC}/../build\".")
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__unknown_rhs(c *check.C) {
@@ -304,7 +309,7 @@ func (s *Suite) Test_MkLine_variableNeed
        G.globalData.InitVartypes()
 
        vuc := &VarUseContext{G.globalData.vartypes["PKGNAME"], vucTimeParse, vucQuotUnknown, false}
-       nq := mkline.variableNeedsQuoting("UNKNOWN", nil, vuc)
+       nq := mkline.VariableNeedsQuoting("UNKNOWN", nil, vuc)
 
        c.Check(nq, equals, nqDontKnow)
 }
@@ -317,13 +322,13 @@ func (s *Suite) Test_MkLine_variableNeed
        mkline := NewMkLine(NewLine("Makefile", 95, "MASTER_SITES=\t${HOMEPAGE}", nil))
 
        vuc := &VarUseContext{G.globalData.vartypes["MASTER_SITES"], vucTimeRun, vucQuotPlain, false}
-       nq := mkline.variableNeedsQuoting("HOMEPAGE", G.globalData.vartypes["HOMEPAGE"], vuc)
+       nq := mkline.VariableNeedsQuoting("HOMEPAGE", G.globalData.vartypes["HOMEPAGE"], vuc)
 
        c.Check(nq, equals, nqNo)
 
        MkLineChecker{mkline}.checkVarassign()
 
-       c.Check(s.Output(), equals, "") // Up to pkglint 5.3.6, it warned about a missing :Q here, which was wrong.
+       s.CheckOutputEmpty() // Up to pkglint 5.3.6, it warned about a missing :Q here, which was wrong.
 }
 
 // Assigning lists to lists is ok.
@@ -336,7 +341,7 @@ func (s *Suite) Test_MkLine_variableNeed
 
        MkLineChecker{mkline}.checkVarassign()
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__eval_shell(c *check.C) {
@@ -347,9 +352,9 @@ func (s *Suite) Test_MkLine_variableNeed
 
        MkLineChecker{mkline}.checkVarassign()
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: builtin.mk:3: PKG_ADMIN should not be evaluated at load time.\n"+
-               "NOTE: builtin.mk:3: The :Q operator isn't necessary for ${BUILTIN_PKG.Xfixes} here.\n")
+       s.CheckOutputLines(
+               "WARN: builtin.mk:3: PKG_ADMIN should not be evaluated at load time.",
+               "NOTE: builtin.mk:3: The :Q operator isn't necessary for ${BUILTIN_PKG.Xfixes} here.")
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_single_quotes(c *check.C) {
@@ -360,7 +365,8 @@ func (s *Suite) Test_MkLine_variableNeed
 
        MkLineChecker{mkline}.checkVarassign()
 
-       c.Check(s.Output(), equals, "WARN: Makefile:3: Please use ${INSTALL:Q} instead of ${INSTALL} and make sure the variable appears outside of any quoting characters.\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:3: Please use ${INSTALL:Q} instead of ${INSTALL} and make sure the variable appears outside of any quoting characters.")
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_command(c *check.C) {
@@ -374,11 +380,11 @@ func (s *Suite) Test_MkLine_variableNeed
                mkrcsid,
                "GENERATE_PLIST= cd ${DESTDIR}${PREFIX}; ${FIND} * \\( -type f -or -type l \\) | ${SORT};")
 
-       G.Mk.determineDefinedVariables()
+       G.Mk.DetermineDefinedVariables()
        MkLineChecker{G.Mk.mklines[1]}.Check()
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: Makefile:2: The exitcode of the left-hand-side command of the pipe operator is ignored.\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:2: The exitcode of the left-hand-side command of the pipe operator is ignored.")
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__word_as_part_of_word(c *check.C) {
@@ -391,7 +397,7 @@ func (s *Suite) Test_MkLine_variableNeed
 
        MkLineChecker{G.Mk.mklines[1]}.Check()
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
 
 // As an argument to ${ECHO}, the :Q modifier should be used, but pkglint
@@ -414,9 +420,9 @@ func (s *Suite) Test_MkLine_variableNeed
        MkLineChecker{G.Mk.mklines[1]}.Check()
        MkLineChecker{G.Mk.mklines[2]}.Check()
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: Makefile:2: The exitcode of the left-hand-side command of the pipe operator is ignored.\n"+
-               "WARN: Makefile:3: The exitcode of the left-hand-side command of the pipe operator is ignored.\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:2: The exitcode of the left-hand-side command of the pipe operator is ignored.",
+               "WARN: Makefile:3: The exitcode of the left-hand-side command of the pipe operator is ignored.")
 }
 
 // Based on mail/mailfront/Makefile.
@@ -430,7 +436,7 @@ func (s *Suite) Test_MkLine_variableNeed
 
        MkLineChecker{G.Mk.mklines[1]}.Check()
 
-       c.Check(s.Output(), equals, "") // Don't suggest to use ${HOMEPAGE:Q}.
+       s.CheckOutputEmpty() // Don't suggest to use ${HOMEPAGE:Q}.
 }
 
 // Pkglint currently does not parse $$(subshell) commands very well. As
@@ -452,7 +458,8 @@ func (s *Suite) Test_MkLine_variableNeed
        MkLineChecker{G.Mk.mklines[1]}.Check()
        MkLineChecker{G.Mk.mklines[2]}.Check()
 
-       c.Check(s.Output(), equals, "WARN: xpi.mk:2: Invoking subshells via $(...) is not portable enough.\n") // Don't suggest to use ${AWK:Q}.
+       s.CheckOutputLines(
+               "WARN: xpi.mk:2: Invoking subshells via $(...) is not portable enough.") // Don't suggest to use ${AWK:Q}.
 }
 
 // LDFLAGS (and even more so CPPFLAGS and CFLAGS) may contain special
@@ -470,7 +477,8 @@ func (s *Suite) Test_MkLine_variableNeed
        MkLineChecker{G.Mk.mklines[1]}.Check()
        MkLineChecker{G.Mk.mklines[2]}.Check()
 
-       c.Check(s.Output(), equals, "WARN: x11/mlterm/Makefile:2: Please move ${LDFLAGS:M*:Q} outside of any quoting characters.\n")
+       s.CheckOutputLines(
+               "WARN: x11/mlterm/Makefile:2: Please move ${LDFLAGS:M*:Q} outside of any quoting characters.")
 }
 
 func (s *Suite) Test_MkLines_Check__MASTER_SITE_in_HOMEPAGE(c *check.C) {
@@ -487,11 +495,11 @@ func (s *Suite) Test_MkLines_Check__MAST
 
        G.Mk.Check()
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: devel/catch/Makefile:2: HOMEPAGE should not be defined in terms of MASTER_SITEs. Use https://github.com/philsquared/Catch/ directly.\n"+
-               "WARN: devel/catch/Makefile:3: HOMEPAGE should not be defined in terms of MASTER_SITEs. Use https://github.com/ directly.\n"+
-               "WARN: devel/catch/Makefile:4: HOMEPAGE should not be defined in terms of MASTER_SITEs.\n"+
-               "WARN: devel/catch/Makefile:5: HOMEPAGE should not be defined in terms of MASTER_SITEs.\n")
+       s.CheckOutputLines(
+               "WARN: devel/catch/Makefile:2: HOMEPAGE should not be defined in terms of MASTER_SITEs. Use https://github.com/philsquared/Catch/ directly.",
+               "WARN: devel/catch/Makefile:3: HOMEPAGE should not be defined in terms of MASTER_SITEs. Use https://github.com/ directly.",
+               "WARN: devel/catch/Makefile:4: HOMEPAGE should not be defined in terms of MASTER_SITEs.",
+               "WARN: devel/catch/Makefile:5: HOMEPAGE should not be defined in terms of MASTER_SITEs.")
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__tool_in_quotes_in_subshell_in_shellwords(c *check.C) {
@@ -506,7 +514,7 @@ func (s *Suite) Test_MkLine_variableNeed
 
        MkLineChecker{G.Mk.mklines[1]}.Check()
 
-       c.Check(s.Output(), equals, "") // Don't suggest ${ECHO:Q} here.
+       s.CheckOutputEmpty() // Don't suggest ${ECHO:Q} here.
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__LDADD_in_BUILDLINK_TRANSFORM(c *check.C) {
@@ -519,7 +527,8 @@ func (s *Suite) Test_MkLine_variableNeed
        MkLineChecker{G.Mk.mklines[0]}.Check()
 
        // Note: The :M* modifier is not necessary, since this is not a GNU Configure package.
-       c.Check(s.Output(), equals, "WARN: x11/qt5-qtbase/Makefile.common:1: Please use ${BUILDLINK_LDADD.dl:Q} instead of ${BUILDLINK_LDADD.dl:M*}.\n")
+       s.CheckOutputLines(
+               "WARN: x11/qt5-qtbase/Makefile.common:1: Please use ${BUILDLINK_LDADD.dl:Q} instead of ${BUILDLINK_LDADD.dl:M*}.")
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_message(c *check.C) {
@@ -531,7 +540,7 @@ func (s *Suite) Test_MkLine_variableNeed
 
        MkLineChecker{G.Mk.mklines[0]}.Check()
 
-       c.Check(s.Output(), equals, "") // Don't suggest ${REPLACE_PERL:Q}.
+       s.CheckOutputEmpty() // Don't suggest ${REPLACE_PERL:Q}.
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__guessed_list_variable_in_quotes(c *check.C) {
@@ -545,7 +554,8 @@ func (s *Suite) Test_MkLine_variableNeed
 
        G.Mk.Check()
 
-       c.Check(s.Output(), equals, "WARN: audio/jack-rack/Makefile:3: The list variable LADSPA_PLUGIN_PATH should not be embedded in a word.\n")
+       s.CheckOutputLines(
+               "WARN: audio/jack-rack/Makefile:3: The list variable LADSPA_PLUGIN_PATH should not be embedded in a word.")
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__list_in_list(c *check.C) {
@@ -558,7 +568,7 @@ func (s *Suite) Test_MkLine_variableNeed
 
        G.Mk.Check()
 
-       c.Check(s.Output(), equals, "") // Don't warn about missing :Q modifiers.
+       s.CheckOutputEmpty() // Don't warn about missing :Q modifiers.
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__PKGNAME_and_URL_list_in_URL_list(c *check.C) {
@@ -572,7 +582,7 @@ func (s *Suite) Test_MkLine_variableNeed
 
        MkLineChecker{G.Mk.mklines[1]}.checkVarassignVaruse()
 
-       c.Check(s.Output(), equals, "") // Don't warn about missing :Q modifiers.
+       s.CheckOutputEmpty() // Don't warn about missing :Q modifiers.
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__tool_in_CONFIGURE_ENV(c *check.C) {
@@ -591,7 +601,8 @@ func (s *Suite) Test_MkLine_variableNeed
 
        // The TOOLS_* variables only contain the path to the tool,
        // without any additional arguments that might be necessary.
-       c.Check(s.Output(), equals, "NOTE: Makefile:3: The :Q operator isn't necessary for ${TOOLS_TAR} here.\n")
+       s.CheckOutputLines(
+               "NOTE: Makefile:3: The :Q operator isn't necessary for ${TOOLS_TAR} here.")
 }
 
 func (s *Suite) Test_MkLine_Pkgmandir(c *check.C) {
@@ -605,7 +616,8 @@ func (s *Suite) Test_MkLine_Pkgmandir(c 
 
        G.Mk.Check()
 
-       c.Check(s.Output(), equals, "WARN: chat/ircII/Makefile:2: Please use ${PKGMANDIR} instead of \"man\".\n")
+       s.CheckOutputLines(
+               "WARN: chat/ircII/Makefile:2: Please use ${PKGMANDIR} instead of \"man\".")
 }
 
 func (s *Suite) Test_MkLines_Check__VERSION_as_wordpart_in_MASTER_SITES(c *check.C) {
@@ -632,9 +644,9 @@ func (s *Suite) Test_MkLines_Check__shel
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: x11/lablgtk1/Makefile:2: Please use ${CC:Q} instead of ${CC}.\n"+
-               "WARN: x11/lablgtk1/Makefile:2: Please use ${CC:Q} instead of ${CC}.\n")
+       s.CheckOutputLines(
+               "WARN: x11/lablgtk1/Makefile:2: Please use ${CC:Q} instead of ${CC}.",
+               "WARN: x11/lablgtk1/Makefile:2: Please use ${CC:Q} instead of ${CC}.")
 }
 
 func (s *Suite) Test_MkLine_shell_varuse_in_backt_dquot(c *check.C) {
@@ -648,20 +660,22 @@ func (s *Suite) Test_MkLine_shell_varuse
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, "WARN: x11/motif/Makefile:3: Unknown shell command \"${GREP}\".\n") // No parse errors.
+       s.CheckOutputLines(
+               "WARN: x11/motif/Makefile:3: Unknown shell command \"${GREP}\".") // No parse errors.
 }
 
 // See PR 46570, Ctrl+F "3. In lang/perl5".
-func (s *Suite) Test_MkLine_getVariableType(c *check.C) {
+func (s *Suite) Test_MkLine_VariableType(c *check.C) {
        mkline := NewMkLine(dummyLine)
 
-       c.Check(mkline.getVariableType("_PERL5_PACKLIST_AWK_STRIP_DESTDIR"), check.IsNil)
-       c.Check(mkline.getVariableType("SOME_DIR").guessed, equals, true)
-       c.Check(mkline.getVariableType("SOMEDIR").guessed, equals, true)
+       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)
 }
 
 // PR 51696, security/py-pbkdf2/Makefile, r1.2
 func (s *Suite) Test_MkLine__comment_in_comment(c *check.C) {
+       s.Init(c)
        G.globalData.InitVartypes()
        mklines := s.NewMkLines("Makefile",
                mkrcsid,
@@ -669,10 +683,23 @@ func (s *Suite) Test_MkLine__comment_in_
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, "WARN: Makefile:2: The # character starts a comment.\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:2: The # character starts a comment.")
+}
+
+func (s *Suite) Test_MkLine_ConditionVars(c *check.C) {
+       s.Init(c)
+       var mkline MkLine = NewMkLine(NewLine("Makefile", 45, ".include \"../../category/package/buildlink3.mk\"", nil))
+
+       c.Check(mkline.ConditionVars(), equals, "")
+
+       mkline.SetConditionVars("OPSYS")
+
+       c.Check(mkline.ConditionVars(), equals, "OPSYS")
 }
 
 func (s *Suite) Test_MatchVarassign(c *check.C) {
+       s.Init(c)
        checkVarassign := func(text string, ck check.Checker, varname, spaceAfterVarname, op, align, value, spaceAfterValue, comment string) {
                type va struct {
                        varname, spaceAfterVarname, op, align, value, spaceAfterValue, comment string

Index: pkgsrc/pkgtools/pkglint/files/mkparser_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mkparser_test.go:1.4 pkgsrc/pkgtools/pkglint/files/mkparser_test.go:1.5
--- pkgsrc/pkgtools/pkglint/files/mkparser_test.go:1.4  Sat Dec 17 13:35:32 2016
+++ pkgsrc/pkgtools/pkglint/files/mkparser_test.go      Sun Jan 29 14:27:48 2017
@@ -5,6 +5,7 @@ import (
 )
 
 func (s *Suite) Test_MkParser_MkTokens(c *check.C) {
+       s.Init(c)
        checkRest := func(input string, expectedTokens []*MkToken, expectedRest string) {
                p := NewMkParser(dummyLine, input, true)
                actualTokens := p.MkTokens()
@@ -106,15 +107,17 @@ func (s *Suite) Test_MkParser_MkTokens(c
        check("${VAR:ts\\124}", varuse("VAR", "ts\\124"))       // Or even decimal.
 
        check("$(GNUSTEP_USER_ROOT)", varuseText("$(GNUSTEP_USER_ROOT)", "GNUSTEP_USER_ROOT"))
-       c.Check(s.Output(), equals, "WARN: Please use curly braces {} instead of round parentheses () for GNUSTEP_USER_ROOT.\n")
+       s.CheckOutputLines(
+               "WARN: Please use curly braces {} instead of round parentheses () for GNUSTEP_USER_ROOT.")
 
        checkRest("${VAR)", nil, "${VAR)") // Opening brace, closing parenthesis
        checkRest("$(VAR}", nil, "$(VAR}") // Opening parenthesis, closing brace
-       c.Check(s.Output(), equals, "")    // Warnings are only printed for balanced expressions.
+       s.CheckOutputEmpty()               // Warnings are only printed for balanced expressions.
 
        check("${PLIST_SUBST_VARS:@var@${var}=${${var}:Q}@}", varuse("PLIST_SUBST_VARS", "@var@${var}=${${var}:Q}@"))
        check("${PLIST_SUBST_VARS:@var@${var}=${${var}:Q}}", varuse("PLIST_SUBST_VARS", "@var@${var}=${${var}:Q}")) // Missing @ at the end
-       c.Check(s.Output(), equals, "WARN: Modifier ${PLIST_SUBST_VARS:@var@...@} is missing the final \"@\".\n")
+       s.CheckOutputLines(
+               "WARN: Modifier ${PLIST_SUBST_VARS:@var@...@} is missing the final \"@\".")
 
        checkRest("hello, ${W:L:tl}orld", []*MkToken{
                literal("hello, "),
@@ -221,11 +224,11 @@ func (s *Suite) Test_MkParser__varuse_pa
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, ""+
-               "AUTOFIX: ~/Makefile:2: Replacing \"$(P1)\" with \"${P1}\".\n"+
-               "AUTOFIX: ~/Makefile:2: Replacing \"$(P2)\" with \"${P2}\".\n"+
-               "AUTOFIX: ~/Makefile:2: Replacing \"$(P3:Q)\" with \"${P3:Q}\".\n"+
-               "AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.\n")
+       s.CheckOutputLines(
+               "AUTOFIX: ~/Makefile:2: Replacing \"$(P1)\" with \"${P1}\".",
+               "AUTOFIX: ~/Makefile:2: Replacing \"$(P2)\" with \"${P2}\".",
+               "AUTOFIX: ~/Makefile:2: Replacing \"$(P3:Q)\" with \"${P3:Q}\".",
+               "AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.")
        c.Check(s.LoadTmpFile("Makefile"), equals, ""+
                mkrcsid+"\n"+
                "COMMENT=${P1} ${P2}) ${P3:Q} ${BRACES}\n")
Index: pkgsrc/pkgtools/pkglint/files/mkshparser.go
diff -u pkgsrc/pkgtools/pkglint/files/mkshparser.go:1.4 pkgsrc/pkgtools/pkglint/files/mkshparser.go:1.5
--- pkgsrc/pkgtools/pkglint/files/mkshparser.go:1.4     Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/mkshparser.go Sun Jan 29 14:27:48 2017
@@ -2,11 +2,12 @@ package main
 
 import (
        "fmt"
+       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/trace"
        "strconv"
 )
 
-func parseShellProgram(line Line, program string) (list *MkShList, err error) {
+func parseShellProgram(line line.Line, program string) (list *MkShList, err error) {
        if trace.Tracing {
                defer trace.Call(program)()
        }
Index: pkgsrc/pkgtools/pkglint/files/shtokenizer_test.go
diff -u pkgsrc/pkgtools/pkglint/files/shtokenizer_test.go:1.4 pkgsrc/pkgtools/pkglint/files/shtokenizer_test.go:1.5
--- pkgsrc/pkgtools/pkglint/files/shtokenizer_test.go:1.4       Sun Jan  1 15:15:47 2017
+++ pkgsrc/pkgtools/pkglint/files/shtokenizer_test.go   Sun Jan 29 14:27:48 2017
@@ -5,6 +5,7 @@ import (
 )
 
 func (s *Suite) Test_ShTokenizer_ShAtom(c *check.C) {
+       s.Init(c)
        checkRest := func(s string, expected ...*ShAtom) string {
                p := NewShTokenizer(dummyLine, s, false)
                q := shqPlain
@@ -17,7 +18,7 @@ func (s *Suite) Test_ShTokenizer_ShAtom(
        check := func(str string, expected ...*ShAtom) {
                rest := checkRest(str, expected...)
                c.Check(rest, equals, "")
-               c.Check(s.Output(), equals, "")
+               s.CheckOutputEmpty()
        }
 
        token := func(typ ShAtomType, text string, quoting ShQuoting) *ShAtom {
@@ -356,13 +357,14 @@ func (s *Suite) Test_Shtokenizer_ShAtom_
 }
 
 func (s *Suite) Test_ShTokenizer_ShToken(c *check.C) {
+       s.Init(c)
        check := func(str string, expected ...*ShToken) {
                p := NewShTokenizer(dummyLine, str, false)
                for _, exp := range expected {
                        c.Check(p.ShToken(), deepEquals, exp)
                }
                c.Check(p.Rest(), equals, "")
-               c.Check(s.Output(), equals, "")
+               s.CheckOutputEmpty()
        }
 
        check("",

Index: pkgsrc/pkgtools/pkglint/files/package.go
diff -u pkgsrc/pkgtools/pkglint/files/package.go:1.17 pkgsrc/pkgtools/pkglint/files/package.go:1.18
--- pkgsrc/pkgtools/pkglint/files/package.go:1.17       Wed Jan 18 23:05:43 2017
+++ pkgsrc/pkgtools/pkglint/files/package.go    Sun Jan 29 14:27:48 2017
@@ -2,6 +2,7 @@ package main
 
 import (
        "fmt"
+       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/pkgver"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
@@ -15,39 +16,39 @@ const rePkgname = `^([\w\-.+]+)-(\d(?:\w
 
 // Package contains data for the pkgsrc package that is currently checked.
 type Package struct {
-       Pkgpath              string  // e.g. "category/pkgdir"
-       Pkgdir               string  // PKGDIR from the package Makefile
-       Filesdir             string  // FILESDIR from the package Makefile
-       Patchdir             string  // PATCHDIR from the package Makefile
-       DistinfoFile         string  // DISTINFO_FILE from the package Makefile
-       EffectivePkgname     string  // PKGNAME or DISTNAME from the package Makefile, including nb13
-       EffectivePkgbase     string  // The effective PKGNAME without the version
-       EffectivePkgversion  string  // The version part of the effective PKGNAME, excluding nb13
-       EffectivePkgnameLine *MkLine // The origin of the three effective_* values
-       SeenBsdPrefsMk       bool    // Has bsd.prefs.mk already been included?
-
-       vardef                map[string]*MkLine // (varname, varcanon) => line
-       varuse                map[string]*MkLine // (varname, varcanon) => line
-       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.
-       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.
-       conditionalIncludes   map[string]*MkLine
-       unconditionalIncludes map[string]*MkLine
+       Pkgpath              string // e.g. "category/pkgdir"
+       Pkgdir               string // PKGDIR from the package Makefile
+       Filesdir             string // FILESDIR from the package Makefile
+       Patchdir             string // PATCHDIR from the package Makefile
+       DistinfoFile         string // DISTINFO_FILE from the package Makefile
+       EffectivePkgname     string // PKGNAME or DISTNAME from the package Makefile, including nb13
+       EffectivePkgbase     string // The effective PKGNAME without the version
+       EffectivePkgversion  string // The version part of the effective PKGNAME, excluding nb13
+       EffectivePkgnameLine MkLine // The origin of the three effective_* values
+       SeenBsdPrefsMk       bool   // Has bsd.prefs.mk already been included?
+
+       vardef                map[string]MkLine    // (varname, varcanon) => line
+       varuse                map[string]MkLine    // (varname, varcanon) => line
+       bl3                   map[string]line.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.
+       included              map[string]line.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.
+       conditionalIncludes   map[string]MkLine
+       unconditionalIncludes map[string]MkLine
 }
 
 func NewPackage(pkgpath string) *Package {
        pkg := &Package{
                Pkgpath:               pkgpath,
-               vardef:                make(map[string]*MkLine),
-               varuse:                make(map[string]*MkLine),
-               bl3:                   make(map[string]Line),
+               vardef:                make(map[string]MkLine),
+               varuse:                make(map[string]MkLine),
+               bl3:                   make(map[string]line.Line),
                plistSubstCond:        make(map[string]bool),
-               included:              make(map[string]Line),
+               included:              make(map[string]line.Line),
                loadTimeTools:         make(map[string]bool),
-               conditionalIncludes:   make(map[string]*MkLine),
-               unconditionalIncludes: make(map[string]*MkLine),
+               conditionalIncludes:   make(map[string]MkLine),
+               unconditionalIncludes: make(map[string]MkLine),
        }
        for varname, line := range G.globalData.UserDefinedVars {
                pkg.vardef[varname] = line
@@ -55,7 +56,7 @@ func NewPackage(pkgpath string) *Package
        return pkg
 }
 
-func (pkg *Package) defineVar(mkline *MkLine, varname string) {
+func (pkg *Package) defineVar(mkline MkLine, varname string) {
        if pkg.vardef[varname] == nil {
                pkg.vardef[varname] = mkline
        }
@@ -110,7 +111,7 @@ func (pkg *Package) checkPossibleDowngra
        if change.Action == "Updated" {
                changeVersion := regex.Compile(`nb\d+$`).ReplaceAllString(change.Version, "")
                if pkgver.Compare(pkgversion, changeVersion) < 0 {
-                       mkline.Warnf("The package is being downgraded from %s (see %s) to %s", change.Version, change.Line.ReferenceFrom(mkline.Line), pkgversion)
+                       mkline.Warnf("The package is being downgraded from %s (see %s) to %s", change.Version, change.Line.ReferenceFrom(mkline), pkgversion)
                        Explain(
                                "The files in doc/CHANGES-*, in which all version changes are",
                                "recorded, have a higher version number than what the package says.",
@@ -126,7 +127,7 @@ func (pkg *Package) checklinesBuildlink3
        }
 
        // Collect all the included buildlink3.mk files from the file.
-       includedFiles := make(map[string]*MkLine)
+       includedFiles := make(map[string]MkLine)
        for _, mkline := range mklines.mklines {
                if mkline.IsInclude() {
                        file := mkline.Includefile()
@@ -276,22 +277,21 @@ func (pkg *Package) readMakefile(fname s
        isMainMakefile := len(mainLines.mklines) == 0
 
        for _, mkline := range fileMklines.mklines {
-               line := mkline.Line
 
                if isMainMakefile {
                        mainLines.mklines = append(mainLines.mklines, mkline)
-                       mainLines.lines = append(mainLines.lines, line)
+                       mainLines.lines = append(mainLines.lines, mkline)
                }
                allLines.mklines = append(allLines.mklines, mkline)
-               allLines.lines = append(allLines.lines, line)
+               allLines.lines = append(allLines.lines, mkline)
 
                var includeFile, incDir, incBase string
                if mkline.IsInclude() {
                        inc := mkline.Includefile()
-                       includeFile = resolveVariableRefs(mkline.resolveVarsInRelativePath(inc, true))
+                       includeFile = resolveVariableRefs(mkline.ResolveVarsInRelativePath(inc, true))
                        if containsVarRef(includeFile) {
                                if !contains(fname, "/mk/") {
-                                       line.Notef("Skipping include file %q. This may result in false warnings.", includeFile)
+                                       mkline.Notef("Skipping include file %q. This may result in false warnings.", includeFile)
                                }
                                includeFile = ""
                        }
@@ -301,7 +301,7 @@ func (pkg *Package) readMakefile(fname s
                if includeFile != "" {
                        if path.Base(fname) != "buildlink3.mk" {
                                if m, bl3File := match1(includeFile, `^\.\./\.\./(.*)/buildlink3\.mk$`); m {
-                                       G.Pkg.bl3[bl3File] = line
+                                       G.Pkg.bl3[bl3File] = mkline
                                        if trace.Tracing {
                                                trace.Step1("Buildlink3 file in package: %q", bl3File)
                                        }
@@ -310,11 +310,11 @@ func (pkg *Package) readMakefile(fname s
                }
 
                if includeFile != "" && G.Pkg.included[includeFile] == nil {
-                       G.Pkg.included[includeFile] = line
+                       G.Pkg.included[includeFile] = mkline
 
                        if matches(includeFile, `^\.\./[^./][^/]*/[^/]+`) {
                                mkline.Warnf("References to other packages should look like \"../../category/package\", not \"../package\".")
-                               mkline.explainRelativeDirs()
+                               mkline.ExplainRelativeDirs()
                        }
 
                        if path.Base(fname) == "Makefile" && !hasPrefix(incDir, "../../mk/") && incBase != "buildlink3.mk" && incBase != "builtin.mk" && incBase != "options.mk" {
@@ -336,7 +336,7 @@ func (pkg *Package) readMakefile(fname s
                                        if dirname != G.CurrentDir { // Prevent unnecessary syscalls
                                                dirname = G.CurrentDir
                                                if !fileExists(dirname + "/" + includeFile) {
-                                                       line.Errorf("Cannot read %q.", dirname+"/"+includeFile)
+                                                       mkline.Errorf("Cannot read %q.", dirname+"/"+includeFile)
                                                        return false
                                                }
                                        }
@@ -396,7 +396,7 @@ func (pkg *Package) checkfilePackageMake
        }
 
        if perlLine, noconfLine := vardef["REPLACE_PERL"], vardef["NO_CONFIGURE"]; perlLine != nil && noconfLine != nil {
-               perlLine.Warnf("REPLACE_PERL is ignored when NO_CONFIGURE is set (in %s)", noconfLine.ReferenceFrom(perlLine.Line))
+               perlLine.Warnf("REPLACE_PERL is ignored when NO_CONFIGURE is set (in %s)", noconfLine.ReferenceFrom(perlLine))
        }
 
        if vardef["LICENSE"] == nil && vardef["META_PACKAGE"] == nil {
@@ -411,7 +411,7 @@ func (pkg *Package) checkfilePackageMake
 
                } else if !matches(useLine.Value(), `(?:^|\s+)(?:c|c99|objc)(?:\s+|$)`) {
                        gnuLine.Warnf("GNU_CONFIGURE almost always needs a C compiler, but \"c\" is not added to USE_LANGUAGES in %s.",
-                               useLine.Line.ReferenceFrom(gnuLine.Line))
+                               useLine.ReferenceFrom(gnuLine))
                }
        }
 
@@ -423,8 +423,8 @@ func (pkg *Package) checkfilePackageMake
        }
 
        if imake, x11 := vardef["USE_IMAKE"], vardef["USE_X11"]; imake != nil && x11 != nil {
-               if !hasSuffix(x11.Line.Filename(), "/mk/x11.buildlink3.mk") {
-                       imake.Line.Notef("USE_IMAKE makes USE_X11 in %s superfluous.", x11.Line.ReferenceFrom(imake.Line))
+               if !hasSuffix(x11.Filename(), "/mk/x11.buildlink3.mk") {
+                       imake.Notef("USE_IMAKE makes USE_X11 in %s superfluous.", x11.ReferenceFrom(imake))
                }
        }
 
@@ -542,7 +542,7 @@ func (pkg *Package) expandVariableWithDe
        }
 
        value := mkline.Value()
-       value = mkline.resolveVarsInRelativePath(value, true)
+       value = mkline.ResolveVarsInRelativePath(value, true)
        if containsVarRef(value) {
                value = resolveVariableRefs(value)
        }
@@ -856,10 +856,11 @@ func (pkg *Package) checkLocallyModified
        }
 }
 
-func (pkg *Package) CheckInclude(mkline *MkLine, indentation *Indentation) {
-       if includeLine := mkline.data.(mkLineInclude); includeLine.conditionVars == "" {
-               includeLine.conditionVars = indentation.Varnames()
-               mkline.data = includeLine
+func (pkg *Package) CheckInclude(mkline MkLine, indentation *Indentation) {
+       conditionVars := mkline.ConditionVars()
+       if conditionVars == "" {
+               conditionVars = indentation.Varnames()
+               mkline.SetConditionVars(conditionVars)
        }
 
        if path.Dir(abspath(mkline.Filename())) == abspath(G.CurrentDir) {
@@ -868,16 +869,14 @@ func (pkg *Package) CheckInclude(mkline 
                if indentation.IsConditional() {
                        pkg.conditionalIncludes[includefile] = mkline
                        if other := pkg.unconditionalIncludes[includefile]; other != nil {
-                               dependingOn := mkline.data.(mkLineInclude).conditionVars
                                mkline.Warnf("%q is included conditionally here (depending on %s) and unconditionally in %s.",
-                                       cleanpath(includefile), dependingOn, other.ReferenceFrom(mkline.Line))
+                                       cleanpath(includefile), mkline.ConditionVars(), other.ReferenceFrom(mkline))
                        }
                } else {
                        pkg.unconditionalIncludes[includefile] = mkline
                        if other := pkg.conditionalIncludes[includefile]; other != nil {
-                               dependingOn := other.data.(mkLineInclude).conditionVars
                                mkline.Warnf("%q is included unconditionally here and conditionally in %s (depending on %s).",
-                                       cleanpath(includefile), other.ReferenceFrom(mkline.Line), dependingOn)
+                                       cleanpath(includefile), other.ReferenceFrom(mkline), other.ConditionVars())
                        }
                }
        }
Index: pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go
diff -u pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go:1.17 pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go:1.18
--- pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go:1.17     Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go  Sun Jan 29 14:27:48 2017
@@ -7,27 +7,33 @@ import (
 )
 
 func (s *Suite) Test_VartypeCheck_AwkCommand(c *check.C) {
+       s.Init(c)
        runVartypeChecks("PLIST_AWK", opAssignAppend, (*VartypeCheck).AwkCommand,
                "{print $0}",
                "{print $$0}")
 
-       c.Check(s.Output(), equals, "WARN: fname:1: $0 is ambiguous. Use ${0} if you mean a Makefile variable or $$0 if you mean a shell variable.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: $0 is ambiguous. Use ${0} if you mean a Makefile variable or $$0 if you mean a shell variable.")
 }
 
 func (s *Suite) Test_VartypeCheck_BasicRegularExpression(c *check.C) {
+       s.Init(c)
        runVartypeChecks("REPLACE_FILES.pl", opAssign, (*VartypeCheck).BasicRegularExpression,
                ".*\\.pl$",
                ".*\\.pl$$")
 
-       c.Check(s.Output(), equals, "WARN: fname:1: Pkglint parse error in MkLine.Tokenize at \"$\".\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: Pkglint parse error in MkLine.Tokenize at \"$\".")
 }
 
 func (s *Suite) Test_VartypeCheck_BuildlinkDepmethod(c *check.C) {
+       s.Init(c)
        runVartypeChecks("BUILDLINK_DEPMETHOD.libc", opAssignDefault, (*VartypeCheck).BuildlinkDepmethod,
                "full",
                "unknown")
 
-       c.Check(s.Output(), equals, "WARN: fname:2: Invalid dependency method \"unknown\". Valid methods are \"build\" or \"full\".\n")
+       s.CheckOutputLines(
+               "WARN: fname:2: Invalid dependency method \"unknown\". Valid methods are \"build\" or \"full\".")
 }
 
 func (s *Suite) Test_VartypeCheck_Category(c *check.C) {
@@ -43,12 +49,13 @@ func (s *Suite) Test_VartypeCheck_Catego
                "filesyscategory",
                "wip")
 
-       c.Check(s.Output(), equals, ""+
-               "ERROR: fname:2: Invalid category \"arabic\".\n"+
-               "ERROR: fname:4: Invalid category \"wip\".\n")
+       s.CheckOutputLines(
+               "ERROR: fname:2: Invalid category \"arabic\".",
+               "ERROR: fname:4: Invalid category \"wip\".")
 }
 
 func (s *Suite) Test_VartypeCheck_CFlag(c *check.C) {
+       s.Init(c)
        runVartypeChecks("CFLAGS", opAssignAppend, (*VartypeCheck).CFlag,
                "-Wall",
                "/W3",
@@ -57,13 +64,14 @@ func (s *Suite) Test_VartypeCheck_CFlag(
                "-XX:+PrintClassHistogramAfterFullGC",
                "`pkg-config pidgin --cflags`")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:2: Compiler flag \"/W3\" should start with a hyphen.\n"+
-               "WARN: fname:3: Compiler flag \"target:sparc64\" should start with a hyphen.\n"+
-               "WARN: fname:5: Unknown compiler flag \"-XX:+PrintClassHistogramAfterFullGC\".\n")
+       s.CheckOutputLines(
+               "WARN: fname:2: Compiler flag \"/W3\" should start with a hyphen.",
+               "WARN: fname:3: Compiler flag \"target:sparc64\" should start with a hyphen.",
+               "WARN: fname:5: Unknown compiler flag \"-XX:+PrintClassHistogramAfterFullGC\".")
 }
 
 func (s *Suite) Test_VartypeCheck_Comment(c *check.C) {
+       s.Init(c)
        runVartypeChecks("COMMENT", opAssign, (*VartypeCheck).Comment,
                "Versatile Programming Language",
                "TODO: Short description of the package",
@@ -72,17 +80,18 @@ func (s *Suite) Test_VartypeCheck_Commen
                "\"Quoting the comment is wrong\"",
                "'Quoting the comment is wrong'")
 
-       c.Check(s.Output(), equals, ""+
-               "ERROR: fname:2: COMMENT must be set.\n"+
-               "WARN: fname:3: COMMENT should not begin with \"A\".\n"+
-               "WARN: fname:3: COMMENT should not end with a period.\n"+
-               "WARN: fname:4: COMMENT should start with a capital letter.\n"+
-               "WARN: fname:4: COMMENT should not be longer than 70 characters.\n"+
-               "WARN: fname:5: COMMENT should not be enclosed in quotes.\n"+
-               "WARN: fname:6: COMMENT should not be enclosed in quotes.\n")
+       s.CheckOutputLines(
+               "ERROR: fname:2: COMMENT must be set.",
+               "WARN: fname:3: COMMENT should not begin with \"A\".",
+               "WARN: fname:3: COMMENT should not end with a period.",
+               "WARN: fname:4: COMMENT should start with a capital letter.",
+               "WARN: fname:4: COMMENT should not be longer than 70 characters.",
+               "WARN: fname:5: COMMENT should not be enclosed in quotes.",
+               "WARN: fname:6: COMMENT should not be enclosed in quotes.")
 }
 
 func (s *Suite) Test_VartypeCheck_ConfFiles(c *check.C) {
+       s.Init(c)
        runVartypeChecks("CONF_FILES", opAssignAppend, (*VartypeCheck).ConfFiles,
                "single/file",
                "share/etc/config ${PKG_SYSCONFDIR}/etc/config",
@@ -90,11 +99,11 @@ func (s *Suite) Test_VartypeCheck_ConfFi
                "share/etc/config ${PREFIX}/etc/config share/etc/config2 ${VARBASE}/config2",
                "share/etc/bootrc /etc/bootrc")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: Values for CONF_FILES should always be pairs of paths.\n"+
-               "WARN: fname:3: Values for CONF_FILES should always be pairs of paths.\n"+
-               "WARN: fname:5: Found absolute pathname: /etc/bootrc\n"+
-               "WARN: fname:5: The destination file \"/etc/bootrc\" should start with a variable reference.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: Values for CONF_FILES should always be pairs of paths.",
+               "WARN: fname:3: Values for CONF_FILES should always be pairs of paths.",
+               "WARN: fname:5: Found absolute pathname: /etc/bootrc",
+               "WARN: fname:5: The destination file \"/etc/bootrc\" should start with a variable reference.")
 }
 
 func (s *Suite) Test_VartypeCheck_Dependency(c *check.C) {
@@ -173,36 +182,42 @@ func (s *Suite) Test_VartypeCheck_Depend
 }
 
 func (s *Suite) Test_VartypeCheck_DistSuffix(c *check.C) {
+       s.Init(c)
        runVartypeChecks("EXTRACT_SUFX", opAssign, (*VartypeCheck).DistSuffix,
                ".tar.gz",
                ".tar.bz2")
 
-       c.Check(s.Output(), equals, "NOTE: fname:1: EXTRACT_SUFX is \".tar.gz\" by default, so this definition may be redundant.\n")
+       s.CheckOutputLines(
+               "NOTE: fname:1: EXTRACT_SUFX is \".tar.gz\" by default, so this definition may be redundant.")
 }
 
 func (s *Suite) Test_VartypeCheck_EmulPlatform(c *check.C) {
+       s.Init(c)
        runVartypeChecks("EMUL_PLATFORM", opAssign, (*VartypeCheck).EmulPlatform,
                "linux-i386",
                "nextbsd-8087",
                "${LINUX}")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:2: \"nextbsd\" is not valid for the operating system part of EMUL_PLATFORM. Use one of { bitrig bsdos cygwin darwin dragonfly freebsd haiku hpux interix irix linux mirbsd 
netbsd openbsd osf1 solaris sunos } instead.\n"+
-               "WARN: fname:2: \"8087\" is not valid for the hardware architecture part of EMUL_PLATFORM. Use one of { aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex 
dreamcast earm earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 
m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } instead.\n"+
-               "WARN: fname:3: \"${LINUX}\" is not a valid emulation platform.\n")
+       s.CheckOutputLines(
+               "WARN: fname:2: \"nextbsd\" is not valid for the operating system part of EMUL_PLATFORM. Use one of { bitrig bsdos cygwin darwin dragonfly freebsd haiku hpux interix irix linux mirbsd 
netbsd openbsd osf1 solaris sunos } instead.",
+               "WARN: fname:2: \"8087\" is not valid for the hardware architecture part of EMUL_PLATFORM. Use one of { aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex 
dreamcast earm earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 
m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } instead.",
+               "WARN: fname:3: \"${LINUX}\" is not a valid emulation platform.")
 }
 
 func (s *Suite) Test_VartypeCheck_Enum(c *check.C) {
+       s.Init(c)
        runVartypeMatchChecks("JDK", enum("jdk1 jdk2 jdk4").checker,
                "*",
                "jdk*",
                "sun-jdk*",
                "${JDKNAME}")
 
-       c.Check(s.Output(), equals, "WARN: fname:3: The pattern \"sun-jdk*\" cannot match any of { jdk1 jdk2 jdk4 } for JDK.\n")
+       s.CheckOutputLines(
+               "WARN: fname:3: The pattern \"sun-jdk*\" cannot match any of { jdk1 jdk2 jdk4 } for JDK.")
 }
 
 func (s *Suite) Test_VartypeCheck_FetchURL(c *check.C) {
+       s.Init(c)
        s.RegisterMasterSite("MASTER_SITE_GNU", "http://ftp.gnu.org/pub/gnu/";)
        s.RegisterMasterSite("MASTER_SITE_GITHUB", "https://github.com/";)
 
@@ -212,90 +227,101 @@ func (s *Suite) Test_VartypeCheck_FetchU
                "${MASTER_SITE_GNU:=bison}",
                "${MASTER_SITE_INVALID:=subdir/}")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: Please use ${MASTER_SITE_GITHUB:=example/} instead of \"https://github.com/example/project/\"; and run \""+confMake+" help topic=github\" for further tips.\n"+
-               "WARN: fname:2: Please use ${MASTER_SITE_GNU:=bison} instead of \"http://ftp.gnu.org/pub/gnu/bison\".\n"+
-               "ERROR: fname:3: The subdirectory in MASTER_SITE_GNU must end with a slash.\n"+
-               "ERROR: fname:4: The site MASTER_SITE_INVALID does not exist.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: Please use ${MASTER_SITE_GITHUB:=example/} instead of \"https://github.com/example/project/\"; and run \""+confMake+" help topic=github\" for further tips.",
+               "WARN: fname:2: Please use ${MASTER_SITE_GNU:=bison} instead of \"http://ftp.gnu.org/pub/gnu/bison\".";,
+               "ERROR: fname:3: The subdirectory in MASTER_SITE_GNU must end with a slash.",
+               "ERROR: fname:4: The site MASTER_SITE_INVALID does not exist.")
 
        // PR 46570, keyword gimp-fix-ca
        runVartypeChecks("MASTER_SITES", opAssign, (*VartypeCheck).FetchURL,
                "https://example.org/download.cgi?fname=fname&sha1=12341234";)
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 
        runVartypeChecks("MASTER_SITES", opAssign, (*VartypeCheck).FetchURL,
                "http://example.org/distfiles/";,
                "http://example.org/download?fname=distfile;version=1.0";,
                "http://example.org/download?fname=<distfile>;version=<version>")
 
-       c.Check(s.Output(), equals, "WARN: fname:3: \"http://example.org/download?fname=<distfile>;version=<version>\" is not a valid URL.\n")
+       s.CheckOutputLines(
+               "WARN: fname:3: \"http://example.org/download?fname=<distfile>;version=<version>\" is not a valid URL.")
 }
 
 func (s *Suite) Test_VartypeCheck_Filename(c *check.C) {
+       s.Init(c)
        runVartypeChecks("FNAME", opAssign, (*VartypeCheck).Filename,
                "Filename with spaces.docx",
                "OS/2-manual.txt")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: \"Filename with spaces.docx\" is not a valid filename.\n"+
-               "WARN: fname:2: A filename should not contain a slash.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: \"Filename with spaces.docx\" is not a valid filename.",
+               "WARN: fname:2: A filename should not contain a slash.")
 }
 
 func (s *Suite) Test_VartypeCheck_LdFlag(c *check.C) {
+       s.Init(c)
        runVartypeChecks("LDFLAGS", opAssignAppend, (*VartypeCheck).LdFlag,
                "-lc",
                "-L/usr/lib64",
                "`pkg-config pidgin --ldflags`",
                "-unknown")
 
-       c.Check(s.Output(), equals, "WARN: fname:4: Unknown linker flag \"-unknown\".\n")
+       s.CheckOutputLines(
+               "WARN: fname:4: Unknown linker flag \"-unknown\".")
 }
 
 func (s *Suite) Test_VartypeCheck_License(c *check.C) {
+       s.Init(c)
        runVartypeChecks("LICENSE", opAssign, (*VartypeCheck).License,
                "gnu-gpl-v2",
                "AND mit")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: License file /licenses/gnu-gpl-v2 does not exist.\n"+
-               "ERROR: fname:2: Parse error for license condition \"AND mit\".\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: License file /licenses/gnu-gpl-v2 does not exist.",
+               "ERROR: fname:2: Parse error for license condition \"AND mit\".")
 
        runVartypeChecks("LICENSE", opAssignAppend, (*VartypeCheck).License,
                "gnu-gpl-v2",
                "AND mit")
 
-       c.Check(s.Output(), equals, ""+
-               "ERROR: fname:1: Parse error for appended license condition \"gnu-gpl-v2\".\n"+
-               "WARN: fname:2: License file /licenses/mit does not exist.\n")
+       s.CheckOutputLines(
+               "ERROR: fname:1: Parse error for appended license condition \"gnu-gpl-v2\".",
+               "WARN: fname:2: License file /licenses/mit does not exist.")
 }
 
 func (s *Suite) Test_VartypeCheck_MachineGnuPlatform(c *check.C) {
+       s.Init(c)
        runVartypeMatchChecks("MACHINE_GNU_PLATFORM", (*VartypeCheck).MachineGnuPlatform,
                "x86_64-pc-cygwin",
                "Cygwin-*-amd64")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:2: The pattern \"Cygwin\" cannot match any of { aarch64 aarch64_be alpha amd64 arc arm armeb armv4 armv4eb armv6 armv6eb armv7 armv7eb cobalt convex dreamcast hpcmips 
hpcsh hppa hppa64 i386 i486 ia64 m5407 m68010 m68k m88k mips mips64 mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh shle sparc sparc64 vax x86_64 } for the 
hardware architecture part of MACHINE_GNU_PLATFORM.\n"+
-               "WARN: fname:2: The pattern \"amd64\" cannot match any of { bitrig bsdos cygwin darwin dragonfly freebsd haiku hpux interix irix linux mirbsd netbsd openbsd osf1 solaris sunos } for 
the operating system part of MACHINE_GNU_PLATFORM.\n")
+       s.CheckOutputLines(
+               "WARN: fname:2: The pattern \"Cygwin\" cannot match any of { aarch64 aarch64_be alpha amd64 arc arm armeb armv4 armv4eb armv6 armv6eb armv7 armv7eb cobalt convex dreamcast hpcmips 
hpcsh hppa hppa64 i386 i486 ia64 m5407 m68010 m68k m88k mips mips64 mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh shle sparc sparc64 vax x86_64 } for the 
hardware architecture part of MACHINE_GNU_PLATFORM.",
+               "WARN: fname:2: The pattern \"amd64\" cannot match any of { bitrig bsdos cygwin darwin dragonfly freebsd haiku hpux interix irix linux mirbsd netbsd openbsd osf1 solaris sunos } for 
the operating system part of MACHINE_GNU_PLATFORM.")
 }
 
 func (s *Suite) Test_VartypeCheck_MailAddress(c *check.C) {
+       s.Init(c)
        runVartypeChecks("MAINTAINER", opAssign, (*VartypeCheck).MailAddress,
                "pkgsrc-users%netbsd.org@localhost")
 
-       c.Check(s.Output(), equals, "WARN: fname:1: Please write \"NetBSD.org\" instead of \"netbsd.org\".\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: Please write \"NetBSD.org\" instead of \"netbsd.org\".")
 }
 
 func (s *Suite) Test_VartypeCheck_Message(c *check.C) {
+       s.Init(c)
        runVartypeChecks("SUBST_MESSAGE.id", opAssign, (*VartypeCheck).Message,
                "\"Correct paths\"",
                "Correct paths")
 
-       c.Check(s.Output(), equals, "WARN: fname:1: SUBST_MESSAGE.id should not be quoted.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: SUBST_MESSAGE.id should not be quoted.")
 }
 
 func (s *Suite) Test_VartypeCheck_Option(c *check.C) {
+       s.Init(c)
        G.globalData.PkgOptions = map[string]string{
                "documented":   "Option description",
                "undocumented": "",
@@ -306,50 +332,58 @@ func (s *Suite) Test_VartypeCheck_Option
                "undocumented",
                "unknown")
 
-       c.Check(s.Output(), equals, "WARN: fname:3: Unknown option \"unknown\".\n")
+       s.CheckOutputLines(
+               "WARN: fname:3: Unknown option \"unknown\".")
 }
 
 func (s *Suite) Test_VartypeCheck_Pathlist(c *check.C) {
+       s.Init(c)
        runVartypeChecks("PATH", opAssign, (*VartypeCheck).Pathlist,
                "/usr/bin:/usr/sbin:.:${LOCALBASE}/bin")
 
-       c.Check(s.Output(), equals, "WARN: fname:1: All components of PATH (in this case \".\") should be absolute paths.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: All components of PATH (in this case \".\") should be absolute paths.")
 }
 
 func (s *Suite) Test_VartypeCheck_Perms(c *check.C) {
+       s.Init(c)
        runVartypeChecks("CONF_FILES_PERMS", opAssignAppend, (*VartypeCheck).Perms,
                "root",
                "${ROOT_USER}",
                "ROOT_USER",
                "${REAL_ROOT_USER}")
 
-       c.Check(s.Output(), equals, "ERROR: fname:2: ROOT_USER must not be used in permission definitions. Use REAL_ROOT_USER instead.\n")
+       s.CheckOutputLines(
+               "ERROR: fname:2: ROOT_USER must not be used in permission definitions. Use REAL_ROOT_USER instead.")
 }
 
 func (s *Suite) Test_VartypeCheck_PkgOptionsVar(c *check.C) {
+       s.Init(c)
        runVartypeChecks("PKG_OPTIONS_VAR.screen", opAssign, (*VartypeCheck).PkgOptionsVar,
                "PKG_OPTIONS.${PKGBASE}",
                "PKG_OPTIONS.anypkgbase")
 
-       c.Check(s.Output(), equals, ""+
-               "ERROR: fname:1: PKGBASE must not be used in PKG_OPTIONS_VAR.\n")
+       s.CheckOutputLines(
+               "ERROR: fname:1: PKGBASE must not be used in PKG_OPTIONS_VAR.")
 }
 
 func (s *Suite) Test_VartypeCheck_PkgRevision(c *check.C) {
+       s.Init(c)
        runVartypeChecks("PKGREVISION", opAssign, (*VartypeCheck).PkgRevision,
                "3a")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: PKGREVISION must be a positive integer number.\n"+
-               "ERROR: fname:1: PKGREVISION only makes sense directly in the package Makefile.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: PKGREVISION must be a positive integer number.",
+               "ERROR: fname:1: PKGREVISION only makes sense directly in the package Makefile.")
 
        runVartypeChecksFname("Makefile", "PKGREVISION", opAssign, (*VartypeCheck).PkgRevision,
                "3")
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_VartypeCheck_MachinePlatformPattern(c *check.C) {
+       s.Init(c)
        runVartypeMatchChecks("ONLY_FOR_PLATFORM", (*VartypeCheck).MachinePlatformPattern,
                "linux-i386",
                "nextbsd-5.0-8087",
@@ -359,74 +393,85 @@ func (s *Suite) Test_VartypeCheck_Machin
                "FreeBSD-*",
                "${LINUX}")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: \"linux-i386\" is not a valid platform pattern.\n"+
-               "WARN: fname:2: The pattern \"nextbsd\" cannot match any of { AIX BSDOS Bitrig Cygwin Darwin DragonFly FreeBSD FreeMiNT GNUkFreeBSD HPUX Haiku IRIX Interix Linux Minix MirBSD NetBSD 
OSF1 OpenBSD QNX SCO_SV SunOS UnixWare } for the operating system part of ONLY_FOR_PLATFORM.\n"+
-               "WARN: fname:2: The pattern \"8087\" cannot match any of { aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast earm earmeb earmhf earmhfeb earmv4 
earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 m68000 m68k m88k mips mips64 mips64eb mips64el 
mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } for the hardware architecture part of ONLY_FOR_PLATFORM.\n"+
-               "WARN: fname:3: The pattern \"netbsd\" cannot match any of { AIX BSDOS Bitrig Cygwin Darwin DragonFly FreeBSD FreeMiNT GNUkFreeBSD HPUX Haiku IRIX Interix Linux Minix MirBSD NetBSD 
OSF1 OpenBSD QNX SCO_SV SunOS UnixWare } for the operating system part of ONLY_FOR_PLATFORM.\n"+
-               "WARN: fname:3: The pattern \"l*\" cannot match any of { aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast earm earmeb earmhf earmhfeb earmv4 earmv4eb 
earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 m68000 m68k m88k mips mips64 mips64eb mips64el mipseb 
mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } for the hardware architecture part of ONLY_FOR_PLATFORM.\n"+
-               "WARN: fname:5: \"FreeBSD*\" is not a valid platform pattern.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: \"linux-i386\" is not a valid platform pattern.",
+               "WARN: fname:2: The pattern \"nextbsd\" cannot match any of { AIX BSDOS Bitrig Cygwin Darwin DragonFly FreeBSD FreeMiNT GNUkFreeBSD HPUX Haiku IRIX Interix Linux Minix MirBSD NetBSD 
OSF1 OpenBSD QNX SCO_SV SunOS UnixWare } for the operating system part of ONLY_FOR_PLATFORM.",
+               "WARN: fname:2: The pattern \"8087\" cannot match any of { aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast earm earmeb earmhf earmhfeb earmv4 
earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 m68000 m68k m88k mips mips64 mips64eb mips64el 
mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } for the hardware architecture part of ONLY_FOR_PLATFORM.",
+               "WARN: fname:3: The pattern \"netbsd\" cannot match any of { AIX BSDOS Bitrig Cygwin Darwin DragonFly FreeBSD FreeMiNT GNUkFreeBSD HPUX Haiku IRIX Interix Linux Minix MirBSD NetBSD 
OSF1 OpenBSD QNX SCO_SV SunOS UnixWare } for the operating system part of ONLY_FOR_PLATFORM.",
+               "WARN: fname:3: The pattern \"l*\" cannot match any of { aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast earm earmeb earmhf earmhfeb earmv4 earmv4eb 
earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 m68000 m68k m88k mips mips64 mips64eb mips64el mipseb 
mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } for the hardware architecture part of ONLY_FOR_PLATFORM.",
+               "WARN: fname:5: \"FreeBSD*\" is not a valid platform pattern.")
 }
 
 func (s *Suite) Test_VartypeCheck_PythonDependency(c *check.C) {
+       s.Init(c)
        runVartypeChecks("PYTHON_VERSIONED_DEPENDENCIES", opAssign, (*VartypeCheck).PythonDependency,
                "cairo",
                "${PYDEP}",
                "cairo,X")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:2: Python dependencies should not contain variables.\n"+
-               "WARN: fname:3: Invalid Python dependency \"cairo,X\".\n")
+       s.CheckOutputLines(
+               "WARN: fname:2: Python dependencies should not contain variables.",
+               "WARN: fname:3: Invalid Python dependency \"cairo,X\".")
 }
 
 func (s *Suite) Test_VartypeCheck_Restricted(c *check.C) {
+       s.Init(c)
        runVartypeChecks("NO_BIN_ON_CDROM", opAssign, (*VartypeCheck).Restricted,
                "May only be distributed free of charge")
 
-       c.Check(s.Output(), equals, "WARN: fname:1: The only valid value for NO_BIN_ON_CDROM is ${RESTRICTED}.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: The only valid value for NO_BIN_ON_CDROM is ${RESTRICTED}.")
 }
 
 func (s *Suite) Test_VartypeCheck_SedCommands(c *check.C) {
+       s.Init(c)
        runVartypeChecks("SUBST_SED.dummy", opAssign, (*VartypeCheck).SedCommands,
                "s,@COMPILER@,gcc,g",
                "-e s,a,b, -e a,b,c,",
                "-e \"s,#,comment ,\"",
                "-e \"s,\\#,comment ,\"")
 
-       c.Check(s.Output(), equals, ""+
-               "NOTE: fname:1: Please always use \"-e\" in sed commands, even if there is only one substitution.\n"+
-               "NOTE: fname:2: Each sed command should appear in an assignment of its own.\n"+
-               "WARN: fname:3: The # character starts a comment.\n")
+       s.CheckOutputLines(
+               "NOTE: fname:1: Please always use \"-e\" in sed commands, even if there is only one substitution.",
+               "NOTE: fname:2: Each sed command should appear in an assignment of its own.",
+               "WARN: fname:3: The # character starts a comment.")
 }
 
 func (s *Suite) Test_VartypeCheck_ShellCommands(c *check.C) {
+       s.Init(c)
        runVartypeChecks("GENERATE_PLIST", opAssign, (*VartypeCheck).ShellCommands,
                "echo bin/program",
                "echo bin/program;")
 
-       c.Check(s.Output(), equals, "WARN: fname:1: This shell command list should end with a semicolon.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: This shell command list should end with a semicolon.")
 }
 
 func (s *Suite) Test_VartypeCheck_Stage(c *check.C) {
+       s.Init(c)
        runVartypeChecks("SUBST_STAGE.dummy", opAssign, (*VartypeCheck).Stage,
                "post-patch",
                "post-modern",
                "pre-test")
 
-       c.Check(s.Output(), equals, "WARN: fname:2: Invalid stage name \"post-modern\". Use one of {pre,do,post}-{extract,patch,configure,build,test,install}.\n")
+       s.CheckOutputLines(
+               "WARN: fname:2: Invalid stage name \"post-modern\". Use one of {pre,do,post}-{extract,patch,configure,build,test,install}.")
 }
 
 func (s *Suite) Test_VartypeCheck_VariableName(c *check.C) {
+       s.Init(c)
        runVartypeChecks("BUILD_DEFS", opAssign, (*VartypeCheck).VariableName,
                "VARBASE",
                "VarBase",
                "PKG_OPTIONS_VAR.pkgbase",
                "${INDIRECT}")
 
-       c.Check(s.Output(), equals, "WARN: fname:2: \"VarBase\" is not a valid variable name.\n")
+       s.CheckOutputLines(
+               "WARN: fname:2: \"VarBase\" is not a valid variable name.")
 }
 
 func (s *Suite) Test_VartypeCheck_Version(c *check.C) {
+       s.Init(c)
        runVartypeChecks("PERL5_REQD", opAssignAppend, (*VartypeCheck).Version,
                "0",
                "1.2.3.4.5.6",
@@ -434,51 +479,55 @@ func (s *Suite) Test_VartypeCheck_Versio
                "4.1-SNAPSHOT",
                "4pre7")
 
-       c.Check(s.Output(), equals, "WARN: fname:4: Invalid version number \"4.1-SNAPSHOT\".\n")
+       s.CheckOutputLines(
+               "WARN: fname:4: Invalid version number \"4.1-SNAPSHOT\".")
 }
 
 func (s *Suite) Test_VartypeCheck_Yes(c *check.C) {
+       s.Init(c)
        runVartypeChecks("APACHE_MODULE", opAssign, (*VartypeCheck).Yes,
                "yes",
                "no",
                "${YESVAR}")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:2: APACHE_MODULE should be set to YES or yes.\n"+
-               "WARN: fname:3: APACHE_MODULE should be set to YES or yes.\n")
+       s.CheckOutputLines(
+               "WARN: fname:2: APACHE_MODULE should be set to YES or yes.",
+               "WARN: fname:3: APACHE_MODULE should be set to YES or yes.")
 
        runVartypeMatchChecks("PKG_DEVELOPER", (*VartypeCheck).Yes,
                "yes",
                "no",
                "${YESVAR}")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: PKG_DEVELOPER should only be used in a \".if defined(...)\" conditional.\n"+
-               "WARN: fname:2: PKG_DEVELOPER should only be used in a \".if defined(...)\" conditional.\n"+
-               "WARN: fname:3: PKG_DEVELOPER should only be used in a \".if defined(...)\" conditional.\n")
+       s.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.")
 }
 
 func (s *Suite) Test_VartypeCheck_YesNo(c *check.C) {
+       s.Init(c)
        runVartypeChecks("GNU_CONFIGURE", opAssign, (*VartypeCheck).YesNo,
                "yes",
                "no",
                "ja",
                "${YESVAR}")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:3: GNU_CONFIGURE should be set to YES, yes, NO, or no.\n"+
-               "WARN: fname:4: GNU_CONFIGURE should be set to YES, yes, NO, or no.\n")
+       s.CheckOutputLines(
+               "WARN: fname:3: GNU_CONFIGURE should be set to YES, yes, NO, or no.",
+               "WARN: fname:4: GNU_CONFIGURE should be set to YES, yes, NO, or no.")
 }
 
 func (s *Suite) Test_VartypeCheck_YesNoIndirectly(c *check.C) {
+       s.Init(c)
        runVartypeChecks("GNU_CONFIGURE", opAssign, (*VartypeCheck).YesNoIndirectly,
                "yes",
                "no",
                "ja",
                "${YESVAR}")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:3: GNU_CONFIGURE should be set to YES, yes, NO, or no.\n")
+       s.CheckOutputLines(
+               "WARN: fname:3: GNU_CONFIGURE should be set to YES, yes, NO, or no.")
 }
 
 func runVartypeChecks(varname string, op MkOperator, checker func(*VartypeCheck), values ...string) {
@@ -487,8 +536,8 @@ func runVartypeChecks(varname string, op
        }
        for i, value := range values {
                mkline := NewMkLine(NewLine("fname", i+1, varname+op.String()+value, nil))
-               valueNovar := mkline.withoutMakeVariables(mkline.Value())
-               vc := &VartypeCheck{mkline, mkline.Line, mkline.Varname(), mkline.Op(), mkline.Value(), valueNovar, "", false}
+               valueNovar := mkline.WithoutMakeVariables(mkline.Value())
+               vc := &VartypeCheck{mkline, mkline, mkline.Varname(), mkline.Op(), mkline.Value(), valueNovar, "", false}
                checker(vc)
        }
 }
@@ -497,8 +546,8 @@ func runVartypeMatchChecks(varname strin
        for i, value := range values {
                text := fmt.Sprintf(".if ${%s:M%s} == \"\"", varname, value)
                mkline := NewMkLine(NewLine("fname", i+1, text, nil))
-               valueNovar := mkline.withoutMakeVariables(value)
-               vc := &VartypeCheck{mkline, mkline.Line, varname, opUseMatch, value, valueNovar, "", false}
+               valueNovar := mkline.WithoutMakeVariables(value)
+               vc := &VartypeCheck{mkline, mkline, varname, opUseMatch, value, valueNovar, "", false}
                checker(vc)
        }
 }
@@ -506,8 +555,8 @@ func runVartypeMatchChecks(varname strin
 func runVartypeChecksFname(fname, varname string, op MkOperator, checker func(*VartypeCheck), values ...string) {
        for i, value := range values {
                mkline := NewMkLine(NewLine(fname, i+1, varname+op.String()+value, nil))
-               valueNovar := mkline.withoutMakeVariables(value)
-               vc := &VartypeCheck{mkline, mkline.Line, varname, op, value, valueNovar, "", false}
+               valueNovar := mkline.WithoutMakeVariables(value)
+               vc := &VartypeCheck{mkline, mkline, varname, op, value, valueNovar, "", false}
                checker(vc)
        }
 }

Index: pkgsrc/pkgtools/pkglint/files/package_test.go
diff -u pkgsrc/pkgtools/pkglint/files/package_test.go:1.13 pkgsrc/pkgtools/pkglint/files/package_test.go:1.14
--- pkgsrc/pkgtools/pkglint/files/package_test.go:1.13  Wed Jan 18 23:05:43 2017
+++ pkgsrc/pkgtools/pkglint/files/package_test.go       Sun Jan 29 14:27:48 2017
@@ -5,6 +5,7 @@ import (
 )
 
 func (s *Suite) Test_Package_pkgnameFromDistname(c *check.C) {
+       s.Init(c)
        pkg := NewPackage("dummy")
        pkg.vardef["PKGNAME"] = NewMkLine(NewLine("Makefile", 5, "PKGNAME=dummy", nil))
 
@@ -18,7 +19,7 @@ func (s *Suite) Test_Package_pkgnameFrom
        c.Check(pkg.pkgnameFromDistname("${DISTNAME:C/beta/.0./}", "fspanel-0.8beta1"), equals, "${DISTNAME:C/beta/.0./}")
        c.Check(pkg.pkgnameFromDistname("${DISTNAME:S/-0$/.0/1}", "aspell-af-0.50-0"), equals, "aspell-af-0.50.0")
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_Package_ChecklinesPackageMakefileVarorder(c *check.C) {
@@ -32,7 +33,7 @@ func (s *Suite) Test_Package_ChecklinesP
                "DISTNAME=9term",
                "CATEGORIES=x11"))
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 
        pkg.ChecklinesPackageMakefileVarorder(s.NewMkLines("Makefile",
                mkrcsid,
@@ -42,9 +43,9 @@ func (s *Suite) Test_Package_ChecklinesP
                "",
                ".include \"../../mk/bsd.pkg.mk\""))
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: Makefile:6: The canonical position for the required variable COMMENT is here.\n"+
-               "WARN: Makefile:6: The canonical position for the required variable LICENSE is here.\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:6: The canonical position for the required variable COMMENT is here.",
+               "WARN: Makefile:6: The canonical position for the required variable LICENSE is here.")
 }
 
 // https://mail-index.netbsd.org/tech-pkg/2017/01/18/msg017698.html
@@ -61,7 +62,7 @@ func (s *Suite) Test_Package_ChecklinesP
                "MASTER_SITES=\thttp://example.org/";,
                "MASTER_SITES+=\thttp://mirror.example.org/";))
 
-       c.Check(s.Output(), equals, "") // No warning that "MASTER_SITES appears too late"
+       s.CheckOutputEmpty() // No warning that "MASTER_SITES appears too late"
 }
 
 func (s *Suite) Test_Package_getNbpart(c *check.C) {
@@ -93,6 +94,7 @@ func (s *Suite) Test_Package_determineEf
 }
 
 func (s *Suite) Test_Package_checkPossibleDowngrade(c *check.C) {
+       s.Init(c)
        G.Pkg = NewPackage("category/pkgbase")
        G.CurPkgsrcdir = "../.."
        G.Pkg.EffectivePkgname = "package-1.0nb15"
@@ -107,13 +109,14 @@ func (s *Suite) Test_Package_checkPossib
 
        G.Pkg.checkPossibleDowngrade()
 
-       c.Check(s.Output(), equals, "WARN: category/pkgbase/Makefile:5: The package is being downgraded from 1.8 (see ../../doc/CHANGES:116) to 1.0nb15\n")
+       s.CheckOutputLines(
+               "WARN: category/pkgbase/Makefile:5: The package is being downgraded from 1.8 (see ../../doc/CHANGES:116) to 1.0nb15")
 
        G.globalData.LastChange["category/pkgbase"].Version = "1.0nb22"
 
        G.Pkg.checkPossibleDowngrade()
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_checkdirPackage(c *check.C) {
@@ -124,11 +127,11 @@ func (s *Suite) Test_checkdirPackage(c *
 
        checkdirPackage(s.tmpdir)
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: ~/Makefile: Neither PLIST nor PLIST.common exist, and PLIST_SRC is unset. Are you sure PLIST handling is ok?\n"+
-               "WARN: ~/distinfo: File not found. Please run \"@BMAKE@ makesum\".\n"+
-               "ERROR: ~/Makefile: Each package must define its LICENSE.\n"+
-               "WARN: ~/Makefile: No COMMENT given.\n")
+       s.CheckOutputLines(
+               "WARN: ~/Makefile: Neither PLIST nor PLIST.common exist, and PLIST_SRC is unset. Are you sure PLIST handling is ok?",
+               "WARN: ~/distinfo: File not found. Please run \"@BMAKE@ makesum\".",
+               "ERROR: ~/Makefile: Each package must define its LICENSE.",
+               "WARN: ~/Makefile: No COMMENT given.")
 }
 
 func (s *Suite) Test_checkdirPackage__meta_package_without_license(c *check.C) {
@@ -142,7 +145,8 @@ func (s *Suite) Test_checkdirPackage__me
 
        checkdirPackage(s.TmpDir())
 
-       c.Check(s.Output(), equals, "WARN: ~/Makefile: No COMMENT given.\n") // No error about missing LICENSE.
+       s.CheckOutputLines(
+               "WARN: ~/Makefile: No COMMENT given.") // No error about missing LICENSE.
 }
 
 func (s *Suite) Test_Package__varuse_at_load_time(c *check.C) {
@@ -201,11 +205,11 @@ func (s *Suite) Test_Package__varuse_at_
 
        (&Pkglint{}).Main("pkglint", "-q", "-Wperm", s.tmpdir+"/category/pkgbase")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: ~/category/pkgbase/Makefile:8: To use the tool \"FALSE\" at load time, bsd.prefs.mk has to be included before.\n"+
-               "WARN: ~/category/pkgbase/Makefile:9: To use the tool \"NICE\" at load time, bsd.prefs.mk has to be included before.\n"+
-               "WARN: ~/category/pkgbase/Makefile:10: To use the tool \"TRUE\" at load time, bsd.prefs.mk has to be included before.\n"+
-               "WARN: ~/category/pkgbase/Makefile:16: To use the tool \"NICE\" at load time, it has to be added to USE_TOOLS before including bsd.prefs.mk.\n")
+       s.CheckOutputLines(
+               "WARN: ~/category/pkgbase/Makefile:8: To use the tool \"FALSE\" at load time, bsd.prefs.mk has to be included before.",
+               "WARN: ~/category/pkgbase/Makefile:9: To use the tool \"NICE\" at load time, bsd.prefs.mk has to be included before.",
+               "WARN: ~/category/pkgbase/Makefile:10: To use the tool \"TRUE\" at load time, bsd.prefs.mk has to be included before.",
+               "WARN: ~/category/pkgbase/Makefile:16: To use the tool \"NICE\" at load time, it has to be added to USE_TOOLS before including bsd.prefs.mk.")
 }
 
 func (s *Suite) Test_Package_loadPackageMakefile(c *check.C) {
@@ -223,7 +227,7 @@ func (s *Suite) Test_Package_loadPackage
 
        pkg.loadPackageMakefile(makefile)
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_Package_conditionalAndUnconditionalInclude(c *check.C) {
@@ -265,8 +269,8 @@ func (s *Suite) Test_Package_conditional
 
        checkdirPackage("category/package")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: ~/category/package/options.mk:3: Unknown option \"zlib\".\n"+
-               "WARN: ~/category/package/options.mk:4: \"../../devel/zlib/buildlink3.mk\" is included conditionally here (depending on PKG_OPTIONS) and unconditionally in Makefile:5.\n"+
-               "WARN: ~/category/package/options.mk:6: \"../../sysutils/coreutils/buildlink3.mk\" is included unconditionally here and conditionally in Makefile:7 (depending on OPSYS).\n")
+       s.CheckOutputLines(
+               "WARN: ~/category/package/options.mk:3: Unknown option \"zlib\".",
+               "WARN: ~/category/package/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 included unconditionally here and conditionally in Makefile:7 (depending on OPSYS).")
 }
Index: pkgsrc/pkgtools/pkglint/files/patches.go
diff -u pkgsrc/pkgtools/pkglint/files/patches.go:1.13 pkgsrc/pkgtools/pkglint/files/patches.go:1.14
--- pkgsrc/pkgtools/pkglint/files/patches.go:1.13       Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/patches.go    Sun Jan 29 14:27:48 2017
@@ -3,22 +3,24 @@ package main
 // Checks for patch files.
 
 import (
+       "netbsd.org/pkglint/line"
+       "netbsd.org/pkglint/textproc"
        "netbsd.org/pkglint/trace"
        "path"
        "strings"
 )
 
-func ChecklinesPatch(lines []Line) {
+func ChecklinesPatch(lines []line.Line) {
        if trace.Tracing {
                defer trace.Call1(lines[0].Filename())()
        }
 
-       (&PatchChecker{lines, NewExpecter(lines), false, false}).Check()
+       (&PatchChecker{lines, textproc.NewExpecter(lines), false, false}).Check()
 }
 
 type PatchChecker struct {
-       lines             []Line
-       exp               *Expecter
+       lines             []line.Line
+       exp               *textproc.Expecter
        seenDocumentation bool
        previousLineEmpty bool
 }
@@ -37,7 +39,7 @@ func (ck *PatchChecker) Check() {
        if (LineChecker{ck.lines[0]}).CheckRcsid(``, "") {
                ck.exp.Advance()
        }
-       ck.previousLineEmpty = ck.exp.ExpectEmptyLine()
+       ck.previousLineEmpty = ck.exp.ExpectEmptyLine(G.opts.WarnSpace)
 
        patchedFiles := 0
        for !ck.exp.EOF() {
@@ -45,7 +47,7 @@ func (ck *PatchChecker) Check() {
                if ck.exp.AdvanceIfMatches(rePatchUniFileDel) {
                        if ck.exp.AdvanceIfMatches(rePatchUniFileAdd) {
                                ck.checkBeginDiff(line, patchedFiles)
-                               ck.checkUnifiedDiff(ck.exp.m[1])
+                               ck.checkUnifiedDiff(ck.exp.Group(1))
                                patchedFiles++
                                continue
                        }
@@ -54,7 +56,7 @@ func (ck *PatchChecker) Check() {
                }
 
                if ck.exp.AdvanceIfMatches(rePatchUniFileAdd) {
-                       patchedFile := ck.exp.m[1]
+                       patchedFile := ck.exp.Group(1)
                        if ck.exp.AdvanceIfMatches(rePatchUniFileDel) {
                                ck.checkBeginDiff(line, patchedFiles)
                                ck.exp.PreviousLine().Warnf("Unified diff headers should be first ---, then +++.")
@@ -107,8 +109,8 @@ func (ck *PatchChecker) checkUnifiedDiff
        hasHunks := false
        for ck.exp.AdvanceIfMatches(rePatchUniHunk) {
                hasHunks = true
-               linesToDel := toInt(ck.exp.m[2], 1)
-               linesToAdd := toInt(ck.exp.m[4], 1)
+               linesToDel := toInt(ck.exp.Group(2), 1)
+               linesToAdd := toInt(ck.exp.Group(4), 1)
                if trace.Tracing {
                        trace.Stepf("hunk -%d +%d", linesToDel, linesToAdd)
                }
@@ -154,7 +156,7 @@ func (ck *PatchChecker) checkUnifiedDiff
        }
 }
 
-func (ck *PatchChecker) checkBeginDiff(line Line, patchedFiles int) {
+func (ck *PatchChecker) checkBeginDiff(line line.Line, patchedFiles int) {
        if trace.Tracing {
                defer trace.Call0()()
        }
@@ -283,7 +285,7 @@ func (ft FileType) String() string {
 }
 
 // This is used to select the proper subroutine for detecting absolute pathnames.
-func guessFileType(line Line, fname string) (fileType FileType) {
+func guessFileType(line line.Line, fname string) (fileType FileType) {
        if trace.Tracing {
                defer trace.Call(fname, "=>", &fileType)()
        }
@@ -316,7 +318,7 @@ func guessFileType(line Line, fname stri
        return ftUnknown
 }
 
-func checkwordAbsolutePathname(line Line, word string) {
+func checkwordAbsolutePathname(line line.Line, word string) {
        if trace.Tracing {
                defer trace.Call1(word)()
        }
@@ -345,7 +347,7 @@ func checkwordAbsolutePathname(line Line
 }
 
 // Looks for strings like "/dev/cd0" appearing in source code
-func checklineSourceAbsolutePathname(line Line, text string) {
+func checklineSourceAbsolutePathname(line line.Line, text string) {
        if !strings.ContainsAny(text, "\"'") {
                return
        }
@@ -367,7 +369,7 @@ func checklineSourceAbsolutePathname(lin
        }
 }
 
-func checklineOtherAbsolutePathname(line Line, text string) {
+func checklineOtherAbsolutePathname(line line.Line, text string) {
        if trace.Tracing {
                defer trace.Call1(text)()
        }
Index: pkgsrc/pkgtools/pkglint/files/util.go
diff -u pkgsrc/pkgtools/pkglint/files/util.go:1.13 pkgsrc/pkgtools/pkglint/files/util.go:1.14
--- pkgsrc/pkgtools/pkglint/files/util.go:1.13  Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/util.go       Sun Jan 29 14:27:48 2017
@@ -3,6 +3,7 @@ package main
 import (
        "fmt"
        "io/ioutil"
+       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
        "os"
@@ -133,7 +134,7 @@ func isLocallyModified(fname string) boo
        return false
 }
 
-func loadCvsEntries(fname string) []Line {
+func loadCvsEntries(fname string) []line.Line {
        dir := path.Dir(fname)
        if dir == G.CvsEntriesDir {
                return G.CvsEntriesLines
@@ -184,7 +185,7 @@ func varnameParam(varname string) string
        return ""
 }
 
-func defineVar(mkline *MkLine, varname string) {
+func defineVar(mkline MkLine, varname string) {
        if G.Mk != nil {
                G.Mk.DefineVar(mkline, varname)
        }

Index: pkgsrc/pkgtools/pkglint/files/pkglint.go
diff -u pkgsrc/pkgtools/pkglint/files/pkglint.go:1.18 pkgsrc/pkgtools/pkglint/files/pkglint.go:1.19
--- pkgsrc/pkgtools/pkglint/files/pkglint.go:1.18       Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/pkglint.go    Sun Jan 29 14:27:48 2017
@@ -5,6 +5,7 @@ import (
        "io"
        "netbsd.org/pkglint/getopt"
        "netbsd.org/pkglint/histogram"
+       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
        "os"
@@ -272,7 +273,7 @@ func CheckfileExtra(fname string) {
        }
 }
 
-func ChecklinesDescr(lines []Line) {
+func ChecklinesDescr(lines []line.Line) {
        if trace.Tracing {
                defer trace.Call1(lines[0].Filename())()
        }
@@ -300,7 +301,7 @@ func ChecklinesDescr(lines []Line) {
        SaveAutofixChanges(lines)
 }
 
-func ChecklinesMessage(lines []Line) {
+func ChecklinesMessage(lines []line.Line) {
        if trace.Tracing {
                defer trace.Call1(lines[0].Filename())()
        }
@@ -486,7 +487,7 @@ func Checkfile(fname string) {
        }
 }
 
-func ChecklinesTrailingEmptyLines(lines []Line) {
+func ChecklinesTrailingEmptyLines(lines []line.Line) {
        max := len(lines)
        last := max
        for last > 1 && lines[last-1].Text() == "" {

Index: pkgsrc/pkgtools/pkglint/files/shell.go
diff -u pkgsrc/pkgtools/pkglint/files/shell.go:1.15 pkgsrc/pkgtools/pkglint/files/shell.go:1.16
--- pkgsrc/pkgtools/pkglint/files/shell.go:1.15 Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/shell.go      Sun Jan 29 14:27:48 2017
@@ -3,6 +3,7 @@ package main
 // Parsing and checking shell commands embedded in Makefiles
 
 import (
+       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/textproc"
        "netbsd.org/pkglint/trace"
        "path"
@@ -17,12 +18,11 @@ const (
 )
 
 type ShellLine struct {
-       line   Line
-       mkline *MkLine
+       mkline MkLine
 }
 
-func NewShellLine(mkline *MkLine) *ShellLine {
-       return &ShellLine{mkline.Line, mkline}
+func NewShellLine(mkline MkLine) *ShellLine {
+       return &ShellLine{mkline}
 }
 
 var shellcommandsContextType = &Vartype{lkNone, BtShellCommands, []AclEntry{{"*", aclpAllRuntime}}, false}
@@ -37,7 +37,7 @@ func (shline *ShellLine) CheckWord(token
                return
        }
 
-       line := shline.line
+       var line line.Line = shline.mkline
 
        p := NewMkParser(line, token, false)
        if varuse := p.VarUse(); varuse != nil && p.EOF() {
@@ -184,7 +184,7 @@ func (shline *ShellLine) checkVaruseToke
        varname := varuse.varname
 
        if varname == "@" {
-               shline.line.Warnf("Please use \"${.TARGET}\" instead of \"$@\".")
+               shline.mkline.Warnf("Please use \"${.TARGET}\" instead of \"$@\".")
                Explain(
                        "The variable $@ can easily be confused with the shell variable of",
                        "the same name, which has a completely different meaning.")
@@ -200,7 +200,7 @@ func (shline *ShellLine) checkVaruseToke
        case (quoting == shqSquot || quoting == shqDquot) && matches(varname, `^(?:.*DIR|.*FILE|.*PATH|.*_VAR|PREFIX|.*BASE|PKGNAME)$`):
                // This is ok if we don't allow these variables to have embedded [\$\\\"\'\`].
        case quoting == shqDquot && varuse.IsQ():
-               shline.line.Warnf("Please don't use the :Q operator in double quotes.")
+               shline.mkline.Warnf("Please don't use the :Q operator in double quotes.")
                Explain(
                        "Either remove the :Q or the double quotes.  In most cases, it is",
                        "more appropriate to remove the double quotes.")
@@ -224,7 +224,7 @@ func (shline *ShellLine) unescapeBacktic
                defer trace.Call(shellword, quoting, "=>", trace.Ref(&unescaped))()
        }
 
-       line := shline.line
+       var line line.Line = shline.mkline
        for !repl.EOF() {
                switch {
                case repl.AdvanceStr("`"):
@@ -276,7 +276,7 @@ func (shline *ShellLine) CheckShellComma
                defer trace.Call1(shelltext)()
        }
 
-       line := shline.line
+       var line line.Line = shline.mkline
 
        if contains(shelltext, "${SED}") && contains(shelltext, "${MV}") {
                line.Notef("Please use the SUBST framework instead of ${SED} and ${MV}.")
@@ -325,13 +325,14 @@ func (shline *ShellLine) CheckShellComma
                defer trace.Call()()
        }
 
-       program, err := parseShellProgram(shline.line, shellcmd)
+       var line line.Line = shline.mkline
+       program, err := parseShellProgram(line, shellcmd)
        if err != nil && contains(shellcmd, "$$(") { // Hack until the shell parser can handle subshells.
-               shline.line.Warnf("Invoking subshells via $(...) is not portable enough.")
+               line.Warnf("Invoking subshells via $(...) is not portable enough.")
                return
        }
        if err != nil {
-               shline.line.Warnf("Pkglint ShellLine.CheckShellCommand: %s", err)
+               line.Warnf("Pkglint ShellLine.CheckShellCommand: %s", err)
                return
        }
 
@@ -352,7 +353,7 @@ func (shline *ShellLine) CheckShellComma
                }
 
                if cmd, ok := node.(*MkShPipeline); ok {
-                       spc.checkPipeExitcode(shline.line, cmd)
+                       spc.checkPipeExitcode(line, cmd)
                }
 
                if word, ok := node.(*ShToken); ok {
@@ -365,7 +366,7 @@ func (shline *ShellLine) CheckShellComma
        setE := true
        shline.CheckShellCommand(shellcmds, &setE)
        if !hasSuffix(shellcmds, ";") {
-               shline.line.Warnf("This shell command list should end with a semicolon.")
+               shline.mkline.Warnf("This shell command list should end with a semicolon.")
        }
 }
 
@@ -385,7 +386,7 @@ func (shline *ShellLine) checkHiddenAndS
                // Shell comments may be hidden, since they cannot have side effects.
 
        default:
-               tokens, _ := splitIntoShellTokens(shline.line, rest)
+               tokens, _ := splitIntoShellTokens(shline.mkline, rest)
                if len(tokens) > 0 {
                        cmd := tokens[0]
                        switch cmd {
@@ -398,7 +399,7 @@ func (shline *ShellLine) checkHiddenAndS
                                "${WARNING_CAT}", "${WARNING_MSG}":
                                break
                        default:
-                               shline.line.Warnf("The shell command %q should not be hidden.", cmd)
+                               shline.mkline.Warnf("The shell command %q should not be hidden.", cmd)
                                Explain(
                                        "Hidden shell commands do not appear on the terminal or in the log",
                                        "file when they are executed.  When they fail, the error message",
@@ -412,7 +413,7 @@ func (shline *ShellLine) checkHiddenAndS
        }
 
        if contains(hiddenAndSuppress, "-") {
-               shline.line.Warnf("Using a leading \"-\" to suppress errors is deprecated.")
+               shline.mkline.Warnf("Using a leading \"-\" to suppress errors is deprecated.")
                Explain(
                        "If you really want to ignore any errors from this command, append",
                        "\"|| ${TRUE}\" to the command.")
@@ -461,7 +462,7 @@ func (scc *SimpleCommandChecker) checkCo
        case scc.handleComment():
        default:
                if G.opts.WarnExtra && !(G.Mk != nil && G.Mk.indentation.DependsOn("OPSYS")) {
-                       scc.shline.line.Warnf("Unknown shell command %q.", shellword)
+                       scc.shline.mkline.Warnf("Unknown shell command %q.", shellword)
                        Explain(
                                "If you want your package to be portable to all platforms that pkgsrc",
                                "supports, you should only use shell commands that are covered by the",
@@ -485,11 +486,11 @@ func (scc *SimpleCommandChecker) handleT
        }
 
        if !localTool && !G.Mk.tools[shellword] && !G.Mk.tools["g"+shellword] {
-               scc.shline.line.Warnf("The %q tool is used but not added to USE_TOOLS.", shellword)
+               scc.shline.mkline.Warnf("The %q tool is used but not added to USE_TOOLS.", shellword)
        }
 
        if tool.MustUseVarForm {
-               scc.shline.line.Warnf("Please use \"${%s}\" instead of %q.", tool.Varname, shellword)
+               scc.shline.mkline.Warnf("Please use \"${%s}\" instead of %q.", tool.Varname, shellword)
        }
 
        scc.shline.checkCommandUse(shellword)
@@ -504,7 +505,7 @@ func (scc *SimpleCommandChecker) handleF
        shellword := scc.strcmd.Name
        switch path.Base(shellword) {
        case "ktrace", "mktexlsr", "strace", "texconfig", "truss":
-               scc.shline.line.Errorf("%q must not be used in Makefiles.", shellword)
+               scc.shline.mkline.Errorf("%q must not be used in Makefiles.", shellword)
                Explain(
                        "This command must appear in INSTALL scripts, not in the package",
                        "Makefile, so that the package also works if it is installed as a binary",
@@ -524,13 +525,13 @@ func (scc *SimpleCommandChecker) handleC
 
                if tool := G.globalData.Tools.byVarname[varname]; tool != nil {
                        if !G.Mk.tools[tool.Name] {
-                               scc.shline.line.Warnf("The %q tool is used but not added to USE_TOOLS.", tool.Name)
+                               scc.shline.mkline.Warnf("The %q tool is used but not added to USE_TOOLS.", tool.Name)
                        }
                        scc.shline.checkCommandUse(shellword)
                        return true
                }
 
-               if vartype := scc.shline.mkline.getVariableType(varname); vartype != nil && vartype.basicType.name == "ShellCommand" {
+               if vartype := scc.shline.mkline.VariableType(varname); vartype != nil && vartype.basicType.name == "ShellCommand" {
                        scc.shline.checkCommandUse(shellword)
                        return true
                }
@@ -559,13 +560,13 @@ func (scc *SimpleCommandChecker) handleC
        }
 
        semicolon := contains(shellword, ";")
-       multiline := scc.shline.line.IsMultiline()
+       multiline := scc.shline.mkline.IsMultiline()
 
        if semicolon {
-               scc.shline.line.Warnf("A shell comment should not contain semicolons.")
+               scc.shline.mkline.Warnf("A shell comment should not contain semicolons.")
        }
        if multiline {
-               scc.shline.line.Warnf("A shell comment does not stop at the end of line.")
+               scc.shline.mkline.Warnf("A shell comment does not stop at the end of line.")
        }
 
        if semicolon || multiline {
@@ -595,10 +596,10 @@ func (scc *SimpleCommandChecker) checkAb
        isSubst := false
        for _, arg := range scc.strcmd.Args {
                if !isSubst {
-                       LineChecker{scc.shline.line}.CheckAbsolutePathname(arg)
+                       LineChecker{scc.shline.mkline}.CheckAbsolutePathname(arg)
                }
                if false && isSubst && !matches(arg, `"^[\"\'].*[\"\']$`) {
-                       scc.shline.line.Warnf("Substitution commands like %q should always be quoted.", arg)
+                       scc.shline.mkline.Warnf("Substitution commands like %q should always be quoted.", arg)
                        Explain(
                                "Usually these substitution commands contain characters like '*' or",
                                "other shell metacharacters that might lead to lookup of matching",
@@ -628,7 +629,7 @@ func (scc *SimpleCommandChecker) checkAu
        for _, arg := range scc.strcmd.Args {
                if !contains(arg, "$$") && !matches(arg, `\$\{[_.]*[a-z]`) {
                        if m, dirname := match1(arg, `^(?:\$\{DESTDIR\})?\$\{PREFIX(?:|:Q)\}/(.*)`); m {
-                               scc.shline.line.Notef("You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= %s\" instead of %q.", dirname, cmdname)
+                               scc.shline.mkline.Notef("You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= %s\" instead of %q.", dirname, cmdname)
                                Explain(
                                        "Many packages include a list of all needed directories in their",
                                        "PLIST file.  In such a case, you can just set AUTO_MKDIRS=yes and",
@@ -662,7 +663,7 @@ func (scc *SimpleCommandChecker) checkIn
                                break
                        default:
                                if prevdir != "" {
-                                       scc.shline.line.Warnf("The INSTALL_*_DIR commands can only handle one directory at a time.")
+                                       scc.shline.mkline.Warnf("The INSTALL_*_DIR commands can only handle one directory at a time.")
                                        Explain(
                                                "Many implementations of install(1) can handle more, but pkgsrc aims",
                                                "at maximum portability.")
@@ -680,7 +681,7 @@ func (scc *SimpleCommandChecker) checkPa
        }
 
        if scc.strcmd.Name == "${PAX}" && scc.strcmd.HasOption("-pe") {
-               scc.shline.line.Warnf("Please use the -pp option to pax(1) instead of -pe.")
+               scc.shline.mkline.Warnf("Please use the -pp option to pax(1) instead of -pe.")
                Explain(
                        "The -pe option tells pax to preserve the ownership of the files, which",
                        "means that the installed files will belong to the user that has built",
@@ -694,7 +695,7 @@ func (scc *SimpleCommandChecker) checkEc
        }
 
        if scc.strcmd.Name == "${ECHO}" && scc.strcmd.HasOption("-n") {
-               scc.shline.line.Warnf("Please use ${ECHO_N} instead of \"echo -n\".")
+               scc.shline.mkline.Warnf("Please use ${ECHO_N} instead of \"echo -n\".")
        }
 }
 
@@ -720,7 +721,7 @@ func (spc *ShellProgramChecker) checkCon
 
        checkConditionalCd := func(cmd *MkShSimpleCommand) {
                if NewStrCommand(cmd).Name == "cd" {
-                       spc.shline.line.Errorf("The Solaris /bin/sh cannot handle \"cd\" inside conditionals.")
+                       spc.shline.mkline.Errorf("The Solaris /bin/sh cannot handle \"cd\" inside conditionals.")
                        Explain(
                                "When the Solaris shell is in \"set -e\" mode and \"cd\" fails, the",
                                "shell will exit, no matter if it is protected by an \"if\" or the",
@@ -762,7 +763,7 @@ func (spc *ShellProgramChecker) checkWor
        spc.shline.CheckWord(word.MkText, checkQuoting)
 }
 
-func (scc *ShellProgramChecker) checkPipeExitcode(line Line, pipeline *MkShPipeline) {
+func (scc *ShellProgramChecker) checkPipeExitcode(line line.Line, pipeline *MkShPipeline) {
        if trace.Tracing {
                defer trace.Call()()
        }
@@ -786,7 +787,7 @@ func (scc *ShellProgramChecker) checkSet
        // Disabled until the shell parser can recognize "command || exit 1" reliably.
        if false && G.opts.WarnExtra && !*eflag && "the current token" == ";" {
                *eflag = true
-               scc.shline.line.Warnf("Please switch to \"set -e\" mode before using a semicolon (the one after %q) to separate commands.", "previous token")
+               scc.shline.mkline.Warnf("Please switch to \"set -e\" mode before using a semicolon (the one after %q) to separate commands.", "previous token")
                Explain(
                        "Normally, when a shell command fails (returns non-zero), the",
                        "remaining commands are still executed.  For example, the following",
@@ -813,7 +814,7 @@ func (shline *ShellLine) checkCommandUse
                return
        }
 
-       line := shline.line
+       var line line.Line = shline.mkline
        switch shellcmd {
        case "${INSTALL}",
                "${INSTALL_DATA}", "${INSTALL_DATA_DIR}",
@@ -848,7 +849,7 @@ func (shline *ShellLine) checkCommandUse
 }
 
 // Example: "word1 word2;;;" => "word1", "word2", ";;", ";"
-func splitIntoShellTokens(line Line, text string) (tokens []string, rest string) {
+func splitIntoShellTokens(line line.Line, text string) (tokens []string, rest string) {
        if trace.Tracing {
                defer trace.Call(line, text)()
        }
@@ -880,7 +881,7 @@ func splitIntoShellTokens(line Line, tex
 
 // Example: "word1 word2;;;" => "word1", "word2;;;"
 // Compare devel/bmake/files/str.c, function brk_string.
-func splitIntoMkWords(line Line, text string) (words []string, rest string) {
+func splitIntoMkWords(line line.Line, text string) (words []string, rest string) {
        if trace.Tracing {
                defer trace.Call(line, text)()
        }
Index: pkgsrc/pkgtools/pkglint/files/shell_test.go
diff -u pkgsrc/pkgtools/pkglint/files/shell_test.go:1.15 pkgsrc/pkgtools/pkglint/files/shell_test.go:1.16
--- pkgsrc/pkgtools/pkglint/files/shell_test.go:1.15    Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/shell_test.go Sun Jan 29 14:27:48 2017
@@ -6,12 +6,14 @@ import (
 )
 
 func (s *Suite) Test_splitIntoShellTokens__line_continuation(c *check.C) {
+       s.Init(c)
        words, rest := splitIntoShellTokens(dummyLine, "if true; then \\")
 
        c.Check(words, check.DeepEquals, []string{"if", "true", ";", "then"})
        c.Check(rest, equals, "\\")
 
-       c.Check(s.Output(), equals, "WARN: Pkglint parse error in ShTokenizer.ShAtom at \"\\\\\" (quoting=plain)\n")
+       s.CheckOutputLines(
+               "WARN: Pkglint parse error in ShTokenizer.ShAtom at \"\\\\\" (quoting=plain)")
 }
 
 func (s *Suite) Test_splitIntoShellTokens__dollar_slash(c *check.C) {
@@ -111,14 +113,14 @@ func (s *Suite) Test_ShellLine_CheckShel
 
        shline.CheckShellCommandLine("@# Comment")
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 
        shline.CheckShellCommandLine("uname=`uname`; echo $$uname; echo")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: Unknown shell command \"uname\".\n"+
-               "WARN: fname:1: Unknown shell command \"echo\".\n"+
-               "WARN: fname:1: Unknown shell command \"echo\".\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: Unknown shell command \"uname\".",
+               "WARN: fname:1: Unknown shell command \"echo\".",
+               "WARN: fname:1: Unknown shell command \"echo\".")
 
        s.RegisterTool(&Tool{Name: "echo", Predefined: true})
        G.Mk = s.NewMkLines("fname",
@@ -127,58 +129,59 @@ func (s *Suite) Test_ShellLine_CheckShel
 
        shline.CheckShellCommandLine("echo ${PKGNAME:Q}") // vucQuotPlain
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: PKGNAME may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.\n"+
-               "NOTE: fname:1: The :Q operator isn't necessary for ${PKGNAME} here.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: PKGNAME may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.",
+               "NOTE: fname:1: The :Q operator isn't necessary for ${PKGNAME} here.")
 
        shline.CheckShellCommandLine("echo \"${CFLAGS:Q}\"") // vucQuotDquot
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: Please don't use the :Q operator in double quotes.\n"+
-               "WARN: fname:1: CFLAGS may not be used in this file; it would be ok in Makefile, Makefile.common, options.mk, *.mk.\n"+
-               "WARN: fname:1: Please use ${CFLAGS:M*:Q} instead of ${CFLAGS:Q} and make sure the variable appears outside of any quoting characters.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: Please don't use the :Q operator in double quotes.",
+               "WARN: fname:1: CFLAGS may not be used in this file; it would be ok in Makefile, Makefile.common, options.mk, *.mk.",
+               "WARN: fname:1: Please use ${CFLAGS:M*:Q} instead of ${CFLAGS:Q} and make sure the variable appears outside of any quoting characters.")
 
        shline.CheckShellCommandLine("echo '${COMMENT:Q}'") // vucQuotSquot
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: COMMENT may not be used in any file; it is a write-only variable.\n"+
-               "WARN: fname:1: Please move ${COMMENT:Q} outside of any quoting characters.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: COMMENT may not be used in any file; it is a write-only variable.",
+               "WARN: fname:1: Please move ${COMMENT:Q} outside of any quoting characters.")
 
        shline.CheckShellCommandLine("echo target=$@ exitcode=$$? '$$' \"\\$$\"")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: Please use \"${.TARGET}\" instead of \"$@\".\n"+
-               "WARN: fname:1: The $? shell variable is often not available in \"set -e\" mode.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: Please use \"${.TARGET}\" instead of \"$@\".",
+               "WARN: fname:1: The $? shell variable is often not available in \"set -e\" mode.")
 
        shline.CheckShellCommandLine("echo $$@")
 
-       c.Check(s.Output(), equals, "WARN: fname:1: The $@ shell variable should only be used in double quotes.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: The $@ shell variable should only be used in double quotes.")
 
        shline.CheckShellCommandLine("echo \"$$\"") // As seen by make(1); the shell sees: echo "$"
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: Pkglint parse error in ShTokenizer.ShAtom at \"$$\\\"\" (quoting=d)\n"+
-               "WARN: fname:1: Pkglint ShellLine.CheckShellCommand: parse error at [\"]\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: Pkglint parse error in ShTokenizer.ShAtom at \"$$\\\"\" (quoting=d)",
+               "WARN: fname:1: Pkglint ShellLine.CheckShellCommand: parse error at [\"]")
 
        shline.CheckShellCommandLine("echo \"\\n\"")
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 
        shline.CheckShellCommandLine("${RUN} for f in *.c; do echo $${f%.c}; done")
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 
        shline.CheckShellCommandLine("${RUN} echo $${variable+set}")
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 
        // Based on mail/thunderbird/Makefile, rev. 1.159
        shline.CheckShellCommandLine("${RUN} subdir=\"`unzip -c \"$$e\" install.rdf | awk '/re/ { print \"hello\" }'`\"")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: The exitcode of the left-hand-side command of the pipe operator is ignored.\n"+
-               "WARN: fname:1: Unknown shell command \"unzip\".\n"+
-               "WARN: fname:1: Unknown shell command \"awk\".\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: The exitcode of the left-hand-side command of the pipe operator is ignored.",
+               "WARN: fname:1: Unknown shell command \"unzip\".",
+               "WARN: fname:1: Unknown shell command \"awk\".")
 
        // From mail/thunderbird/Makefile, rev. 1.159
        shline.CheckShellCommandLine("" +
@@ -189,14 +192,14 @@ func (s *Suite) Test_ShellLine_CheckShel
                "  ${UNZIP_CMD} -aqo $$e; " +
                "done")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: XPI_FILES is used but not defined. Spelling mistake?\n"+
-               "WARN: fname:1: The exitcode of the left-hand-side command of the pipe operator is ignored.\n"+
-               "WARN: fname:1: UNZIP_CMD is used but not defined. Spelling mistake?\n"+
-               "WARN: fname:1: Unknown shell command \"awk\".\n"+
-               "WARN: fname:1: Unknown shell command \"${MKDIR}\".\n"+
-               "WARN: fname:1: MKDIR is used but not defined. Spelling mistake?\n"+
-               "WARN: fname:1: UNZIP_CMD is used but not defined. Spelling mistake?\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: XPI_FILES is used but not defined. Spelling mistake?",
+               "WARN: fname:1: The exitcode of the left-hand-side command of the pipe operator is ignored.",
+               "WARN: fname:1: UNZIP_CMD is used but not defined. Spelling mistake?",
+               "WARN: fname:1: Unknown shell command \"awk\".",
+               "WARN: fname:1: Unknown shell command \"${MKDIR}\".",
+               "WARN: fname:1: MKDIR is used but not defined. Spelling mistake?",
+               "WARN: fname:1: UNZIP_CMD is used but not defined. Spelling mistake?")
 
        // From x11/wxGTK28/Makefile
        shline.CheckShellCommandLine("" +
@@ -206,27 +209,27 @@ func (s *Suite) Test_ShellLine_CheckShel
                "  ${TOOLS_PATH.msgfmt} -c -o \"$${lang%.po}.mo\" \"$${lang}\"; " +
                "done")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: WRKSRC may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.\n"+
-               "WARN: fname:1: Unknown shell command \"[\".\n"+
-               "WARN: fname:1: Unknown shell command \"${TOOLS_PATH.msgfmt}\".\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: WRKSRC may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.",
+               "WARN: fname:1: Unknown shell command \"[\".",
+               "WARN: fname:1: Unknown shell command \"${TOOLS_PATH.msgfmt}\".")
 
        shline.CheckShellCommandLine("@cp from to")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: The shell command \"cp\" should not be hidden.\n"+
-               "WARN: fname:1: Unknown shell command \"cp\".\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: The shell command \"cp\" should not be hidden.",
+               "WARN: fname:1: Unknown shell command \"cp\".")
 
        shline.CheckShellCommandLine("${RUN} ${INSTALL_DATA_DIR} share/pkgbase ${PREFIX}/share/pkgbase")
 
-       c.Check(s.Output(), equals, ""+
-               "NOTE: fname:1: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= share/pkgbase\" instead of \"${INSTALL_DATA_DIR}\".\n"+
-               "WARN: fname:1: The INSTALL_*_DIR commands can only handle one directory at a time.\n")
+       s.CheckOutputLines(
+               "NOTE: fname:1: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= share/pkgbase\" instead of \"${INSTALL_DATA_DIR}\".",
+               "WARN: fname:1: The INSTALL_*_DIR commands can only handle one directory at a time.")
 
        // See PR 46570, item "1. It does not"
        shline.CheckShellCommandLine("for x in 1 2 3; do echo \"$$x\" || exit 1; done")
 
-       c.Check(s.Output(), equals, "") // No warning about missing error checking.
+       s.CheckOutputEmpty() // No warning about missing error checking.
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__nofix(c *check.C) {
@@ -240,8 +243,8 @@ func (s *Suite) Test_ShellLine_CheckShel
 
        shline.CheckShellCommandLine("echo ${PKGNAME:Q}")
 
-       c.Check(s.Output(), equals, ""+
-               "NOTE: Makefile:1: The :Q operator isn't necessary for ${PKGNAME} here.\n")
+       s.CheckOutputLines(
+               "NOTE: Makefile:1: The :Q operator isn't necessary for ${PKGNAME} here.")
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__show_autofix(c *check.C) {
@@ -255,9 +258,9 @@ func (s *Suite) Test_ShellLine_CheckShel
 
        shline.CheckShellCommandLine("echo ${PKGNAME:Q}")
 
-       c.Check(s.Output(), equals, ""+
-               "NOTE: Makefile:1: The :Q operator isn't necessary for ${PKGNAME} here.\n"+
-               "AUTOFIX: Makefile:1: Replacing \"${PKGNAME:Q}\" with \"${PKGNAME}\".\n")
+       s.CheckOutputLines(
+               "NOTE: Makefile:1: The :Q operator isn't necessary for ${PKGNAME} here.",
+               "AUTOFIX: Makefile:1: Replacing \"${PKGNAME:Q}\" with \"${PKGNAME}\".")
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__autofix(c *check.C) {
@@ -271,8 +274,8 @@ func (s *Suite) Test_ShellLine_CheckShel
 
        shline.CheckShellCommandLine("echo ${PKGNAME:Q}")
 
-       c.Check(s.Output(), equals, ""+
-               "AUTOFIX: Makefile:1: Replacing \"${PKGNAME:Q}\" with \"${PKGNAME}\".\n")
+       s.CheckOutputLines(
+               "AUTOFIX: Makefile:1: Replacing \"${PKGNAME:Q}\" with \"${PKGNAME}\".")
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__implementation(c *check.C) {
@@ -293,7 +296,8 @@ func (s *Suite) Test_ShellLine_CheckShel
 
        shline.CheckWord(text, false)
 
-       c.Check(s.Output(), equals, "WARN: fname:1: Unknown shell command \"echo\".\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: Unknown shell command \"echo\".")
 
        shline.CheckShellCommandLine(text)
 
@@ -302,6 +306,7 @@ func (s *Suite) Test_ShellLine_CheckShel
 }
 
 func (s *Suite) Test_ShellLine_CheckShelltext__dollar_without_variable(c *check.C) {
+       s.Init(c)
        G.globalData.InitVartypes()
        G.Mk = s.NewMkLines("fname",
                "# dummy")
@@ -311,7 +316,7 @@ func (s *Suite) Test_ShellLine_CheckShel
 
        shline.CheckShellCommandLine("pax -rwpp -s /.*~$$//g . ${DESTDIR}${PREFIX}")
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_ShellLine_CheckWord(c *check.C) {
@@ -322,47 +327,50 @@ func (s *Suite) Test_ShellLine_CheckWord
 
        shline.CheckWord("${${list}}", false)
 
-       c.Check(s.Output(), equals, "") // No warning for variables that are completely indirect.
+       s.CheckOutputEmpty() // No warning for variables that are completely indirect.
 
        shline.CheckWord("${SED_FILE.${id}}", false)
 
-       c.Check(s.Output(), equals, "") // No warning for variables that are partly indirect.
+       s.CheckOutputEmpty() // No warning for variables that are partly indirect.
 
        shline.CheckWord("\"$@\"", false)
 
-       c.Check(s.Output(), equals, "WARN: fname:1: Please use \"${.TARGET}\" instead of \"$@\".\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: Please use \"${.TARGET}\" instead of \"$@\".")
 
        shline.CheckWord("${COMMENT:Q}", true)
 
-       c.Check(s.Output(), equals, "WARN: fname:1: COMMENT may not be used in any file; it is a write-only variable.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: COMMENT may not be used in any file; it is a write-only variable.")
 
        shline.CheckWord("\"${DISTINFO_FILE:Q}\"", true)
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: DISTINFO_FILE may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.\n"+
-               "NOTE: fname:1: The :Q operator isn't necessary for ${DISTINFO_FILE} here.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: DISTINFO_FILE may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.",
+               "NOTE: fname:1: The :Q operator isn't necessary for ${DISTINFO_FILE} here.")
 
        shline.CheckWord("embed${DISTINFO_FILE:Q}ded", true)
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: DISTINFO_FILE may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.\n"+
-               "NOTE: fname:1: The :Q operator isn't necessary for ${DISTINFO_FILE} here.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: DISTINFO_FILE may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.",
+               "NOTE: fname:1: The :Q operator isn't necessary for ${DISTINFO_FILE} here.")
 
        shline.CheckWord("s,\\.,,", true)
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 
        shline.CheckWord("\"s,\\.,,\"", true)
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_ShellLine_CheckWord__dollar_without_variable(c *check.C) {
+       s.Init(c)
        shline := NewShellLine(NewMkLine(NewLine("fname", 1, "# dummy", nil)))
 
        shline.CheckWord("/.*~$$//g", false) // Typical argument to pax(1).
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__echo(c *check.C) {
@@ -375,37 +383,41 @@ func (s *Suite) Test_ShellLine_CheckShel
 
        MkLineChecker{mkline}.checkText("echo \"hello, world\"")
 
-       c.Check(s.Output(), equals, "")
+       s.CheckOutputEmpty()
 
        NewShellLine(mkline).CheckShellCommandLine("echo \"hello, world\"")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:3: Please use \"${ECHO}\" instead of \"echo\".\n")
+       s.CheckOutputLines(
+               "WARN: fname:3: Please use \"${ECHO}\" instead of \"echo\".")
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__shell_variables(c *check.C) {
+       s.Init(c)
        text := "\tfor f in *.pl; do ${SED} s,@PREFIX@,${PREFIX}, < $f > $f.tmp && ${MV} $f.tmp $f; done"
 
        shline := NewShellLine(NewMkLine(NewLine("Makefile", 3, text, nil)))
        shline.CheckShellCommandLine(text)
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.\n"+
-               "WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.\n"+
-               "WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.\n"+
-               "WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.\n"+
-               "NOTE: Makefile:3: Please use the SUBST framework instead of ${SED} and ${MV}.\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.",
+               "WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.",
+               "WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.",
+               "WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.",
+               "NOTE: Makefile:3: Please use the SUBST framework instead of ${SED} and ${MV}.")
 
        shline.CheckShellCommandLine("install -c manpage.1 ${PREFIX}/man/man1/manpage.1")
 
-       c.Check(s.Output(), equals, "WARN: Makefile:3: Please use ${PKGMANDIR} instead of \"man\".\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:3: Please use ${PKGMANDIR} instead of \"man\".")
 
        shline.CheckShellCommandLine("cp init-script ${PREFIX}/etc/rc.d/service")
 
-       c.Check(s.Output(), equals, "WARN: Makefile:3: Please use the RCD_SCRIPTS mechanism to install rc.d scripts automatically to ${RCD_SCRIPTS_EXAMPLEDIR}.\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:3: Please use the RCD_SCRIPTS mechanism to install rc.d scripts automatically to ${RCD_SCRIPTS_EXAMPLEDIR}.")
 }
 
 func (s *Suite) Test_ShellLine_checkCommandUse(c *check.C) {
+       s.Init(c)
        G.Mk = s.NewMkLines("fname",
                "# dummy")
        G.Mk.target = "do-install"
@@ -414,11 +426,13 @@ func (s *Suite) Test_ShellLine_checkComm
 
        shline.checkCommandUse("sed")
 
-       c.Check(s.Output(), equals, "WARN: fname:1: The shell command \"sed\" should not be used in the install phase.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: The shell command \"sed\" should not be used in the install phase.")
 
        shline.checkCommandUse("cp")
 
-       c.Check(s.Output(), equals, "WARN: fname:1: ${CP} should not be used to install files.\n")
+       s.CheckOutputLines(
+               "WARN: fname:1: ${CP} should not be used to install files.")
 }
 
 func (s *Suite) Test_splitIntoMkWords(c *check.C) {
@@ -441,53 +455,59 @@ func (s *Suite) Test_splitIntoMkWords(c 
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__sed_and_mv(c *check.C) {
+       s.Init(c)
        shline := NewShellLine(NewMkLine(NewLine("Makefile", 85, "\t${RUN} ${SED} 's,#,// comment:,g' fname > fname.tmp; ${MV} fname.tmp fname", nil)))
 
        shline.CheckShellCommandLine(shline.mkline.Shellcmd())
 
-       c.Check(s.Output(), equals, "NOTE: Makefile:85: Please use the SUBST framework instead of ${SED} and ${MV}.\n")
+       s.CheckOutputLines(
+               "NOTE: Makefile:85: Please use the SUBST framework instead of ${SED} and ${MV}.")
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__subshell(c *check.C) {
+       s.Init(c)
        shline := NewShellLine(NewMkLine(NewLine("Makefile", 85, "\t${RUN} uname=$$(uname)", nil)))
 
        shline.CheckShellCommandLine(shline.mkline.Shellcmd())
 
-       c.Check(s.Output(), equals, "WARN: Makefile:85: Invoking subshells via $(...) is not portable enough.\n")
+       s.CheckOutputLines(
+               "WARN: Makefile:85: Invoking subshells via $(...) is not portable enough.")
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__install_dir(c *check.C) {
+       s.Init(c)
        shline := NewShellLine(NewMkLine(NewLine("Makefile", 85, "\t${RUN} ${INSTALL_DATA_DIR} ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2", nil)))
 
        shline.CheckShellCommandLine(shline.mkline.Shellcmd())
 
-       c.Check(s.Output(), equals, ""+
-               "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL_DATA_DIR}\".\n"+
-               "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL_DATA_DIR}\".\n"+
-               "WARN: Makefile:85: The INSTALL_*_DIR commands can only handle one directory at a time.\n")
+       s.CheckOutputLines(
+               "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL_DATA_DIR}\".",
+               "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL_DATA_DIR}\".",
+               "WARN: Makefile:85: The INSTALL_*_DIR commands can only handle one directory at a time.")
 
        shline.CheckShellCommandLine("${INSTALL_DATA_DIR} -d -m 0755 ${DESTDIR}${PREFIX}/share/examples/gdchart")
 
        // No warning about multiple directories, since 0755 is an option, not an argument.
-       c.Check(s.Output(), equals, ""+
-               "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= share/examples/gdchart\" instead of \"${INSTALL_DATA_DIR}\".\n")
+       s.CheckOutputLines(
+               "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= share/examples/gdchart\" instead of \"${INSTALL_DATA_DIR}\".")
 
        shline.CheckShellCommandLine("${INSTALL_DATA_DIR} -d -m 0755 ${DESTDIR}${PREFIX}/dir1 ${PREFIX}/dir2")
 
-       c.Check(s.Output(), equals, ""+
-               "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL_DATA_DIR}\".\n"+
-               "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL_DATA_DIR}\".\n"+
-               "WARN: Makefile:85: The INSTALL_*_DIR commands can only handle one directory at a time.\n")
+       s.CheckOutputLines(
+               "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL_DATA_DIR}\".",
+               "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL_DATA_DIR}\".",
+               "WARN: Makefile:85: The INSTALL_*_DIR commands can only handle one directory at a time.")
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__install_option_d(c *check.C) {
+       s.Init(c)
        shline := NewShellLine(NewMkLine(NewLine("Makefile", 85, "\t${RUN} ${INSTALL} -d ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2", nil)))
 
        shline.CheckShellCommandLine(shline.mkline.Shellcmd())
 
-       c.Check(s.Output(), equals, ""+
-               "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL} -d\".\n"+
-               "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL} -d\".\n")
+       s.CheckOutputLines(
+               "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL} -d\".",
+               "NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL} -d\".")
 }
 
 func (s *Suite) Test_ShellLine__shell_comment_with_line_continuation(c *check.C) {
@@ -501,7 +521,8 @@ func (s *Suite) Test_ShellLine__shell_co
 
        NewMkLines(lines).Check()
 
-       c.Check(s.Output(), equals, "WARN: ~/Makefile:3--4: A shell comment does not stop at the end of line.\n")
+       s.CheckOutputLines(
+               "WARN: ~/Makefile:3--4: A shell comment does not stop at the end of line.")
 }
 
 func (s *Suite) Test_ShellLine_unescapeBackticks(c *check.C) {

Index: pkgsrc/pkgtools/pkglint/files/substcontext.go
diff -u pkgsrc/pkgtools/pkglint/files/substcontext.go:1.8 pkgsrc/pkgtools/pkglint/files/substcontext.go:1.9
--- pkgsrc/pkgtools/pkglint/files/substcontext.go:1.8   Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/substcontext.go       Sun Jan 29 14:27:48 2017
@@ -12,7 +12,7 @@ type SubstContext struct {
        filterCmd string
 }
 
-func (ctx *SubstContext) Varassign(mkline *MkLine) {
+func (ctx *SubstContext) Varassign(mkline MkLine) {
        if !G.opts.WarnExtra {
                return
        }
@@ -85,7 +85,7 @@ func (ctx *SubstContext) IsComplete() bo
                (len(ctx.sed) != 0 || len(ctx.vars) != 0 || ctx.filterCmd != "")
 }
 
-func (ctx *SubstContext) Finish(mkline *MkLine) {
+func (ctx *SubstContext) Finish(mkline MkLine) {
        if ctx.id == "" || !G.opts.WarnExtra {
                return
        }
@@ -116,14 +116,14 @@ func (ctx *SubstContext) varname(varbase
        }
 }
 
-func (ctx *SubstContext) dup(mkline *MkLine, pstr *string, varname, value string) {
+func (ctx *SubstContext) dup(mkline MkLine, pstr *string, varname, value string) {
        if *pstr != "" {
                mkline.Warnf("Duplicate definition of %q.", varname)
        }
        *pstr = value
 }
 
-func (ctx *SubstContext) duplist(mkline *MkLine, plist *[]string, varname string, op MkOperator, value string) {
+func (ctx *SubstContext) duplist(mkline MkLine, plist *[]string, varname string, op MkOperator, value string) {
        if len(*plist) > 0 && op != opAssignAppend {
                mkline.Warnf("All but the first %q lines should use the \"+=\" operator.", varname)
        }

Index: pkgsrc/pkgtools/pkglint/files/vartypecheck.go
diff -u pkgsrc/pkgtools/pkglint/files/vartypecheck.go:1.24 pkgsrc/pkgtools/pkglint/files/vartypecheck.go:1.25
--- pkgsrc/pkgtools/pkglint/files/vartypecheck.go:1.24  Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/vartypecheck.go       Sun Jan 29 14:27:48 2017
@@ -1,6 +1,7 @@
 package main
 
 import (
+       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
        "path"
@@ -9,8 +10,8 @@ import (
 )
 
 type VartypeCheck struct {
-       MkLine     *MkLine
-       Line       Line
+       MkLine     MkLine
+       Line       line.Line
        Varname    string
        Op         MkOperator
        Value      string
@@ -23,7 +24,7 @@ type VartypeCheck struct {
 // fields except the value. This is typically used when checking parts
 // of composite types.
 func NewVartypeCheckValue(vc *VartypeCheck, value string) *VartypeCheck {
-       valueNoVar := vc.MkLine.withoutMakeVariables(value)
+       valueNoVar := vc.MkLine.WithoutMakeVariables(value)
 
        copy := *vc
        copy.Value = value
@@ -209,7 +210,7 @@ func (cv *VartypeCheck) Comment() {
 }
 
 func (cv *VartypeCheck) ConfFiles() {
-       words, _ := splitIntoMkWords(cv.MkLine.Line, cv.Value)
+       words, _ := splitIntoMkWords(cv.MkLine, cv.Value)
        if len(words)%2 != 0 {
                cv.Line.Warnf("Values for %s should always be pairs of paths.", cv.Varname)
        }
@@ -318,7 +319,7 @@ func (cv *VartypeCheck) DependencyWithPa
 
        if matches(value, `:\.\./[^/]+$`) {
                line.Warnf("Dependencies should have the form \"../../category/package\".")
-               cv.MkLine.explainRelativeDirs()
+               cv.MkLine.ExplainRelativeDirs()
                return
        }
 

Added files:

Index: pkgsrc/pkgtools/pkglint/files/line/line.go
diff -u /dev/null pkgsrc/pkgtools/pkglint/files/line/line.go:1.1
--- /dev/null   Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/line/line.go  Sun Jan 29 14:27:48 2017
@@ -0,0 +1,30 @@
+package line
+
+import (
+       "fmt"
+       "netbsd.org/pkglint/regex"
+)
+
+type Line interface {
+       fmt.Stringer
+
+       Filename() string
+       Linenos() string
+       Text() string
+       IsMultiline() bool
+       IsChanged() bool
+
+       Fatalf(fmt string, args ...interface{})
+       Errorf(fmt string, args ...interface{})
+       Warnf(fmt string, args ...interface{})
+       Notef(fmt string, args ...interface{})
+       ReferenceFrom(Line) string
+
+       AutofixReplace(from, to string) bool
+       AutofixReplaceRegexp(from regex.RegexPattern, to string) bool
+       AutofixInsertBefore(text string) bool
+       AutofixDelete() bool
+       AutofixMark(reason string)
+}
+
+var NewLineEOF func(filename string) Line

Index: pkgsrc/pkgtools/pkglint/files/textproc/expecter.go
diff -u /dev/null pkgsrc/pkgtools/pkglint/files/textproc/expecter.go:1.1
--- /dev/null   Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/textproc/expecter.go  Sun Jan 29 14:27:48 2017
@@ -0,0 +1,112 @@
+package textproc
+
+import (
+       "netbsd.org/pkglint/line"
+       "netbsd.org/pkglint/regex"
+       "netbsd.org/pkglint/trace"
+       "strings"
+)
+
+// Expecter records the state when checking a list of lines from top to bottom.
+type Expecter struct {
+       lines []line.Line
+       index int
+       m     []string
+}
+
+func NewExpecter(lines []line.Line) *Expecter {
+       return &Expecter{lines, 0, nil}
+}
+
+func (exp *Expecter) CurrentLine() line.Line {
+       if exp.index < len(exp.lines) {
+               return exp.lines[exp.index]
+       }
+
+       return line.NewLineEOF(exp.lines[0].Filename())
+}
+
+func (exp *Expecter) PreviousLine() line.Line {
+       return exp.lines[exp.index-1]
+}
+
+func (exp *Expecter) Index() int {
+       return exp.index
+}
+
+func (exp *Expecter) EOF() bool {
+       return !(exp.index < len(exp.lines))
+}
+
+func (exp *Expecter) Group(index int) string {
+       return exp.m[index]
+}
+
+func (exp *Expecter) Advance() bool {
+       exp.index++
+       exp.m = nil
+       return true
+}
+
+func (exp *Expecter) StepBack() {
+       exp.index--
+}
+
+func (exp *Expecter) AdvanceIfMatches(re regex.RegexPattern) bool {
+       if trace.Tracing {
+               defer trace.Call(exp.CurrentLine().Text(), re)()
+       }
+
+       if !exp.EOF() {
+               if m := regex.Match(exp.lines[exp.index].Text(), re); m != nil {
+                       exp.index++
+                       exp.m = m
+                       return true
+               }
+       }
+       return false
+}
+
+func (exp *Expecter) AdvanceIfPrefix(prefix string) bool {
+       if trace.Tracing {
+               defer trace.Call2(exp.CurrentLine().Text(), prefix)()
+       }
+
+       return !exp.EOF() && strings.HasPrefix(exp.lines[exp.index].Text(), prefix) && exp.Advance()
+}
+
+func (exp *Expecter) AdvanceIfEquals(text string) bool {
+       if trace.Tracing {
+               defer trace.Call2(exp.CurrentLine().Text(), text)()
+       }
+
+       return !exp.EOF() && exp.lines[exp.index].Text() == text && exp.Advance()
+}
+
+func (exp *Expecter) ExpectEmptyLine(warnSpace bool) bool {
+       if exp.AdvanceIfEquals("") {
+               return true
+       }
+
+       if warnSpace {
+               if !exp.CurrentLine().AutofixInsertBefore("") {
+                       exp.CurrentLine().Notef("Empty line expected.")
+               }
+       }
+       return false
+}
+
+func (exp *Expecter) ExpectText(text string) bool {
+       if !exp.EOF() && exp.lines[exp.index].Text() == text {
+               exp.index++
+               exp.m = nil
+               return true
+       }
+
+       exp.CurrentLine().Warnf("This line should contain the following text: %s", text)
+       return false
+}
+
+func (exp *Expecter) SkipToFooter() {
+       exp.index = len(exp.lines) - 2
+}



Home | Main Index | Thread Index | Old Index