pkgsrc-Changes archive

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

CVS commit: pkgsrc/pkgtools/pkglint



Module Name:    pkgsrc
Committed By:   rillig
Date:           Mon Jan  1 18:04:16 UTC 2018

Modified Files:
        pkgsrc/pkgtools/pkglint: Makefile
        pkgsrc/pkgtools/pkglint/files: buildlink3.go category.go check_test.go
            distinfo.go files.go files_test.go globaldata.go globalvars.go
            line.go line_test.go mkline.go mkline_test.go mklinechecker.go
            mklinechecker_test.go mklines.go mkparser.go mkshparser.go
            mkshtypes.go mkshwalker.go mktypes.go package.go parser.go
            patches.go patches_test.go pkglint.go plist.go shell.go
            shtokenizer.go toplevel.go util.go vardefs.go vartypecheck.go
            vartypecheck_test.go
        pkgsrc/pkgtools/pkglint/files/textproc: prefixreplacer.go
Added Files:
        pkgsrc/pkgtools/pkglint/files: expecter.go linechecker.go
            linechecker_test.go
Removed Files:
        pkgsrc/pkgtools/pkglint/files/line: line.go
        pkgsrc/pkgtools/pkglint/files/linechecks: linechecker.go
            linechecker_test.go
        pkgsrc/pkgtools/pkglint/files/textproc: expecter.go

Log Message:
Updated pkglint to 5.4.22.

Changes since 5.4.21:
* Refactoring: moved packages line and linechecks back into main
* Fixed panic when autofixing package Makefiles
* Removed apache22
* Added a bit of inline documentation


To generate a diff of this commit:
cvs rdiff -u -r1.518 -r1.519 pkgsrc/pkgtools/pkglint/Makefile
cvs rdiff -u -r1.10 -r1.11 pkgsrc/pkgtools/pkglint/files/buildlink3.go \
    pkgsrc/pkgtools/pkglint/files/files_test.go \
    pkgsrc/pkgtools/pkglint/files/line_test.go \
    pkgsrc/pkgtools/pkglint/files/patches_test.go
cvs rdiff -u -r1.8 -r1.9 pkgsrc/pkgtools/pkglint/files/category.go \
    pkgsrc/pkgtools/pkglint/files/parser.go
cvs rdiff -u -r1.13 -r1.14 pkgsrc/pkgtools/pkglint/files/check_test.go
cvs rdiff -u -r1.14 -r1.15 pkgsrc/pkgtools/pkglint/files/distinfo.go \
    pkgsrc/pkgtools/pkglint/files/mklines.go \
    pkgsrc/pkgtools/pkglint/files/plist.go
cvs rdiff -u -r0 -r1.9 pkgsrc/pkgtools/pkglint/files/expecter.go
cvs rdiff -u -r1.11 -r1.12 pkgsrc/pkgtools/pkglint/files/files.go
cvs rdiff -u -r1.21 -r1.22 pkgsrc/pkgtools/pkglint/files/globaldata.go \
    pkgsrc/pkgtools/pkglint/files/pkglint.go
cvs rdiff -u -r1.7 -r1.8 pkgsrc/pkgtools/pkglint/files/globalvars.go \
    pkgsrc/pkgtools/pkglint/files/toplevel.go
cvs rdiff -u -r1.16 -r1.17 pkgsrc/pkgtools/pkglint/files/line.go
cvs rdiff -u -r0 -r1.4 pkgsrc/pkgtools/pkglint/files/linechecker.go \
    pkgsrc/pkgtools/pkglint/files/linechecker_test.go
cvs rdiff -u -r1.22 -r1.23 pkgsrc/pkgtools/pkglint/files/mkline.go
cvs rdiff -u -r1.24 -r1.25 pkgsrc/pkgtools/pkglint/files/mkline_test.go
cvs rdiff -u -r1.3 -r1.4 pkgsrc/pkgtools/pkglint/files/mklinechecker.go
cvs rdiff -u -r1.2 -r1.3 pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go \
    pkgsrc/pkgtools/pkglint/files/mkshwalker.go \
    pkgsrc/pkgtools/pkglint/files/mktypes.go
cvs rdiff -u -r1.9 -r1.10 pkgsrc/pkgtools/pkglint/files/mkparser.go
cvs rdiff -u -r1.5 -r1.6 pkgsrc/pkgtools/pkglint/files/mkshparser.go
cvs rdiff -u -r1.6 -r1.7 pkgsrc/pkgtools/pkglint/files/mkshtypes.go \
    pkgsrc/pkgtools/pkglint/files/shtokenizer.go
cvs rdiff -u -r1.19 -r1.20 pkgsrc/pkgtools/pkglint/files/package.go
cvs rdiff -u -r1.15 -r1.16 pkgsrc/pkgtools/pkglint/files/patches.go \
    pkgsrc/pkgtools/pkglint/files/util.go
cvs rdiff -u -r1.17 -r1.18 pkgsrc/pkgtools/pkglint/files/shell.go
cvs rdiff -u -r1.31 -r1.32 pkgsrc/pkgtools/pkglint/files/vardefs.go
cvs rdiff -u -r1.26 -r1.27 pkgsrc/pkgtools/pkglint/files/vartypecheck.go
cvs rdiff -u -r1.18 -r1.19 pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go
cvs rdiff -u -r1.2 -r0 pkgsrc/pkgtools/pkglint/files/line/line.go
cvs rdiff -u -r1.1 -r0 \
    pkgsrc/pkgtools/pkglint/files/linechecks/linechecker.go \
    pkgsrc/pkgtools/pkglint/files/linechecks/linechecker_test.go
cvs rdiff -u -r1.2 -r0 pkgsrc/pkgtools/pkglint/files/textproc/expecter.go
cvs rdiff -u -r1.2 -r1.3 \
    pkgsrc/pkgtools/pkglint/files/textproc/prefixreplacer.go

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

Modified files:

Index: pkgsrc/pkgtools/pkglint/Makefile
diff -u pkgsrc/pkgtools/pkglint/Makefile:1.518 pkgsrc/pkgtools/pkglint/Makefile:1.519
--- pkgsrc/pkgtools/pkglint/Makefile:1.518      Sun Oct  8 22:31:13 2017
+++ pkgsrc/pkgtools/pkglint/Makefile    Mon Jan  1 18:04:15 2018
@@ -1,6 +1,6 @@
-# $NetBSD: Makefile,v 1.518 2017/10/08 22:31:13 rillig Exp $
+# $NetBSD: Makefile,v 1.519 2018/01/01 18:04:15 rillig Exp $
 
-PKGNAME=       pkglint-5.4.21
+PKGNAME=       pkglint-5.4.22
 DISTFILES=     # none
 CATEGORIES=    pkgtools
 

Index: pkgsrc/pkgtools/pkglint/files/buildlink3.go
diff -u pkgsrc/pkgtools/pkglint/files/buildlink3.go:1.10 pkgsrc/pkgtools/pkglint/files/buildlink3.go:1.11
--- pkgsrc/pkgtools/pkglint/files/buildlink3.go:1.10    Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/buildlink3.go Mon Jan  1 18:04:15 2018
@@ -1,26 +1,24 @@
 package main
 
 import (
-       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/pkgver"
-       "netbsd.org/pkglint/textproc"
        "netbsd.org/pkglint/trace"
        "strings"
 )
 
 func ChecklinesBuildlink3Mk(mklines *MkLines) {
        if trace.Tracing {
-               defer trace.Call1(mklines.lines[0].Filename())()
+               defer trace.Call1(mklines.lines[0].Filename)()
        }
 
        mklines.Check()
 
-       exp := textproc.NewExpecter(mklines.lines)
+       exp := NewExpecter(mklines.lines)
 
        for exp.AdvanceIfPrefix("#") {
                line := exp.PreviousLine()
                // See pkgtools/createbuildlink/files/createbuildlink
-               if hasPrefix(line.Text(), "# XXX This file was created automatically") {
+               if hasPrefix(line.Text, "# XXX This file was created automatically") {
                        line.Errorf("This comment indicates unfinished work (url2pkg).")
                }
        }
@@ -34,7 +32,7 @@ func ChecklinesBuildlink3Mk(mklines *MkL
        }
 
        pkgbaseLine, pkgbase := exp.CurrentLine(), ""
-       var abiLine, apiLine line.Line
+       var abiLine, apiLine Line
        var abi, api *DependencyPattern
 
        // First paragraph: Introduction of the package identifier
Index: pkgsrc/pkgtools/pkglint/files/files_test.go
diff -u pkgsrc/pkgtools/pkglint/files/files_test.go:1.10 pkgsrc/pkgtools/pkglint/files/files_test.go:1.11
--- pkgsrc/pkgtools/pkglint/files/files_test.go:1.10    Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/files_test.go Mon Jan  1 18:04:15 2018
@@ -70,7 +70,7 @@ func (s *Suite) Test_show_autofix(c *che
        }
        SaveAutofixChanges(lines)
 
-       c.Check(lines[1].(*LineImpl).raw[0].textnl, equals, "XXXXX\n")
+       c.Check(lines[1].raw[0].textnl, equals, "XXXXX\n")
        c.Check(s.LoadTmpFile("Makefile"), equals, "line1\nline2\nline3\n")
        s.CheckOutputLines(
                "WARN: ~/Makefile:2: Something's wrong here.",
@@ -96,3 +96,29 @@ func (s *Suite) Test_autofix(c *check.C)
                "AUTOFIX: ~/Makefile:2: Replacing regular expression \".\" with \"X\".",
                "AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.")
 }
+
+func (s *Suite) Test_autofix_MkLines(c *check.C) {
+       s.Init(c)
+       s.UseCommandLine("--autofix")
+       fname := s.CreateTmpFile("Makefile", ""+
+               "line1 := value1\n"+
+               "line2 := value2\n"+
+               "line3 := value3\n")
+       pkg := NewPackage("category/basename")
+       G.Pkg = pkg
+       mklines := pkg.loadPackageMakefile(fname)
+       G.Pkg = nil
+
+       if !mklines.mklines[1].AutofixReplaceRegexp(`.`, "X") {
+               mklines.mklines[1].Warnf("Something's wrong here.") // Prints the autofix NOTE afterwards
+       }
+       SaveAutofixChanges(mklines.lines)
+
+       c.Check(s.LoadTmpFile("Makefile"), equals, ""+
+               "line1 := value1\n"+
+               "XXXXXXXXXXXXXXX\n"+
+               "line3 := value3\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/line_test.go
diff -u pkgsrc/pkgtools/pkglint/files/line_test.go:1.10 pkgsrc/pkgtools/pkglint/files/line_test.go:1.11
--- pkgsrc/pkgtools/pkglint/files/line_test.go:1.10     Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/line_test.go  Mon Jan  1 18:04:15 2018
@@ -1,34 +1,34 @@
 package main
 
 import (
-       check "gopkg.in/check.v1"
+       "gopkg.in/check.v1"
 )
 
 func (s *Suite) Test_Line_modifications(c *check.C) {
        s.Init(c)
        s.UseCommandLine("--show-autofix")
 
-       line := NewLine("fname", 1, "dummy", s.NewRawLines(1, "original\n")).(*LineImpl)
+       line := NewLine("fname", 1, "dummy", s.NewRawLines(1, "original\n"))
 
-       c.Check(line.changed, equals, false)
+       c.Check(line.Changed, equals, false)
        c.Check(line.raw, check.DeepEquals, s.NewRawLines(1, "original\n"))
 
        line.AutofixReplaceRegexp(`(.)(.*)(.)`, "$3$2$1")
 
-       c.Check(line.changed, equals, true)
+       c.Check(line.Changed, equals, true)
        c.Check(line.raw, check.DeepEquals, s.NewRawLines(1, "original\n", "lriginao\n"))
 
-       line.changed = false
+       line.Changed = false
        line.AutofixReplace("i", "u")
 
-       c.Check(line.changed, equals, true)
+       c.Check(line.Changed, equals, true)
        c.Check(line.raw, check.DeepEquals, s.NewRawLines(1, "original\n", "lruginao\n"))
        c.Check(line.raw[0].textnl, equals, "lruginao\n")
 
-       line.changed = false
+       line.Changed = false
        line.AutofixReplace("lruginao", "middle")
 
-       c.Check(line.changed, equals, true)
+       c.Check(line.Changed, equals, true)
        c.Check(line.raw, check.DeepEquals, s.NewRawLines(1, "original\n", "middle\n"))
        c.Check(line.raw[0].textnl, equals, "middle\n")
 
Index: pkgsrc/pkgtools/pkglint/files/patches_test.go
diff -u pkgsrc/pkgtools/pkglint/files/patches_test.go:1.10 pkgsrc/pkgtools/pkglint/files/patches_test.go:1.11
--- pkgsrc/pkgtools/pkglint/files/patches_test.go:1.10  Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/patches_test.go       Mon Jan  1 18:04:15 2018
@@ -109,7 +109,7 @@ func (s *Suite) Test_checklineOtherAbsol
        s.Init(c)
        line := NewLine("patch-ag", 1, "+$install -s -c ./bin/rosegarden ${DESTDIR}$BINDIR", nil)
 
-       checklineOtherAbsolutePathname(line, line.Text())
+       checklineOtherAbsolutePathname(line, line.Text)
 
        s.CheckOutputEmpty()
 }

Index: pkgsrc/pkgtools/pkglint/files/category.go
diff -u pkgsrc/pkgtools/pkglint/files/category.go:1.8 pkgsrc/pkgtools/pkglint/files/category.go:1.9
--- pkgsrc/pkgtools/pkglint/files/category.go:1.8       Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/category.go   Mon Jan  1 18:04:15 2018
@@ -1,8 +1,6 @@
 package main
 
 import (
-       "netbsd.org/pkglint/line"
-       "netbsd.org/pkglint/textproc"
        "netbsd.org/pkglint/trace"
        "sort"
 )
@@ -20,7 +18,7 @@ func CheckdirCategory() {
        mklines := NewMkLines(lines)
        mklines.Check()
 
-       exp := textproc.NewExpecter(lines)
+       exp := NewExpecter(lines)
        for exp.AdvanceIfPrefix("#") {
        }
        exp.ExpectEmptyLine(G.opts.WarnSpace)
@@ -34,7 +32,7 @@ func CheckdirCategory() {
 
        type subdir struct {
                name   string
-               line   line.Line
+               line   Line
                active bool
        }
 
@@ -49,7 +47,7 @@ func CheckdirCategory() {
        prevSubdir := ""
        for !exp.EOF() {
                line := exp.CurrentLine()
-               text := line.Text()
+               text := line.Text
 
                if m, commentFlag, indentation, name, comment := match4(text, `^(#?)SUBDIR\+=(\s*)(\S+)\s*(?:#\s*(.*?)\s*|)$`); m {
                        commentedOut := commentFlag == "#"
@@ -74,7 +72,7 @@ func CheckdirCategory() {
                        exp.Advance()
 
                } else {
-                       if line.Text() != "" {
+                       if line.Text != "" {
                                line.Errorf("SUBDIR+= line or empty line expected.")
                        }
                        break
@@ -98,7 +96,7 @@ func CheckdirCategory() {
 
        var subdirs []string
 
-       var line line.Line
+       var line Line
        mActive := false
 
        for !(mAtend && fAtend) {
Index: pkgsrc/pkgtools/pkglint/files/parser.go
diff -u pkgsrc/pkgtools/pkglint/files/parser.go:1.8 pkgsrc/pkgtools/pkglint/files/parser.go:1.9
--- pkgsrc/pkgtools/pkglint/files/parser.go:1.8 Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/parser.go     Mon Jan  1 18:04:15 2018
@@ -1,18 +1,17 @@
 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.Line, s string, emitWarnings bool) *Parser {
+func NewParser(line Line, s string, emitWarnings bool) *Parser {
        return &Parser{line, textproc.NewPrefixReplacer(s), emitWarnings}
 }
 

Index: pkgsrc/pkgtools/pkglint/files/check_test.go
diff -u pkgsrc/pkgtools/pkglint/files/check_test.go:1.13 pkgsrc/pkgtools/pkglint/files/check_test.go:1.14
--- pkgsrc/pkgtools/pkglint/files/check_test.go:1.13    Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/check_test.go Mon Jan  1 18:04:15 2018
@@ -11,7 +11,6 @@ import (
        "testing"
 
        check "gopkg.in/check.v1"
-       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/textproc"
        "netbsd.org/pkglint/trace"
 )
@@ -37,7 +36,7 @@ func (s *Suite) Init(c *check.C) {
 
 func (s *Suite) c() *check.C {
        if s.checkC == nil {
-               panic("Must call Suite.Init before accessing check.C.")
+               panic("Suite.Init must be called before accessing check.C.")
        }
        return s.checkC
 }
@@ -94,8 +93,8 @@ func (s *Suite) NewRawLines(args ...inte
        return rawlines[:j]
 }
 
-func (s *Suite) NewLines(fname string, texts ...string) []line.Line {
-       result := make([]line.Line, len(texts))
+func (s *Suite) NewLines(fname string, texts ...string) []Line {
+       result := make([]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.14 pkgsrc/pkgtools/pkglint/files/distinfo.go:1.15
--- pkgsrc/pkgtools/pkglint/files/distinfo.go:1.14      Sun Oct  8 22:31:13 2017
+++ pkgsrc/pkgtools/pkglint/files/distinfo.go   Mon Jan  1 18:04:15 2018
@@ -5,18 +5,16 @@ import (
        "crypto/sha1"
        "fmt"
        "io/ioutil"
-       "netbsd.org/pkglint/line"
-       "netbsd.org/pkglint/linechecks"
        "netbsd.org/pkglint/trace"
        "strings"
 )
 
-func ChecklinesDistinfo(lines []line.Line) {
+func ChecklinesDistinfo(lines []Line) {
        if trace.Tracing {
-               defer trace.Call1(lines[0].Filename())()
+               defer trace.Call1(lines[0].Filename)()
        }
 
-       fname := lines[0].Filename()
+       fname := lines[0].Filename
        patchesDir := "patches"
        patchesDirSet := false
        if G.Pkg != nil && contains(fname, "lang/php") {
@@ -48,15 +46,15 @@ type distinfoLinesChecker struct {
        distinfoIsCommitted bool
 
        patches          map[string]bool // "patch-aa" => true
-       currentFirstLine line.Line
+       currentFirstLine Line
        currentFilename  string
        isPatch          bool
        algorithms       []string
 }
 
-func (ck *distinfoLinesChecker) checkLines(lines []line.Line) {
-       linechecks.CheckRcsid(lines[0], ``, "")
-       if 1 < len(lines) && lines[1].Text() != "" {
+func (ck *distinfoLinesChecker) checkLines(lines []Line) {
+       CheckLineRcsid(lines[0], ``, "")
+       if 1 < len(lines) && lines[1].Text != "" {
                lines[1].Notef("Empty line expected.")
        }
 
@@ -64,7 +62,7 @@ func (ck *distinfoLinesChecker) checkLin
                if i < 2 {
                        continue
                }
-               m, alg, filename, hash := match3(line.Text(), `^(\w+) \((\w[^)]*)\) = (.*)(?: bytes)?$`)
+               m, alg, filename, hash := match3(line.Text, `^(\w+) \((\w[^)]*)\) = (.*)(?: bytes)?$`)
                if !m {
                        line.Errorf("Invalid line.")
                        continue
@@ -81,7 +79,7 @@ func (ck *distinfoLinesChecker) checkLin
        ck.onFilenameChange(NewLineEOF(ck.distinfoFilename), "")
 }
 
-func (ck *distinfoLinesChecker) onFilenameChange(line line.Line, nextFname string) {
+func (ck *distinfoLinesChecker) onFilenameChange(line Line, nextFname string) {
        currentFname := ck.currentFilename
        if currentFname != "" {
                algorithms := strings.Join(ck.algorithms, ", ")
@@ -108,7 +106,7 @@ func (ck *distinfoLinesChecker) onFilena
        ck.algorithms = nil
 }
 
-func (ck *distinfoLinesChecker) checkPatchSha1(line line.Line, patchFname, distinfoSha1Hex string) {
+func (ck *distinfoLinesChecker) checkPatchSha1(line Line, patchFname, distinfoSha1Hex string) {
        patchBytes, err := ioutil.ReadFile(G.CurrentDir + "/" + patchFname)
        if err != nil {
                line.Errorf("%s does not exist.", patchFname)
@@ -148,7 +146,7 @@ func (ck *distinfoLinesChecker) checkUnr
 }
 
 // Inter-package check for differing distfile checksums.
-func (ck *distinfoLinesChecker) checkGlobalMismatch(line line.Line, fname, alg, hash string) {
+func (ck *distinfoLinesChecker) checkGlobalMismatch(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]
@@ -163,7 +161,7 @@ func (ck *distinfoLinesChecker) checkGlo
        }
 }
 
-func (ck *distinfoLinesChecker) checkUncommittedPatch(line line.Line, patchName, sha1Hash string) {
+func (ck *distinfoLinesChecker) checkUncommittedPatch(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.14 pkgsrc/pkgtools/pkglint/files/mklines.go:1.15
--- pkgsrc/pkgtools/pkglint/files/mklines.go:1.14       Sun Oct  8 22:31:13 2017
+++ pkgsrc/pkgtools/pkglint/files/mklines.go    Mon Jan  1 18:04:15 2018
@@ -1,8 +1,6 @@
 package main
 
 import (
-       "netbsd.org/pkglint/line"
-       "netbsd.org/pkglint/linechecks"
        "netbsd.org/pkglint/trace"
        "path"
        "strings"
@@ -11,7 +9,7 @@ import (
 // MkLines contains data for the Makefile (or *.mk) that is currently checked.
 type MkLines struct {
        mklines        []MkLine
-       lines          []line.Line
+       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
@@ -24,7 +22,7 @@ type MkLines struct {
        indentation    Indentation // Indentation depth of preprocessing directives
 }
 
-func NewMkLines(lines []line.Line) *MkLines {
+func NewMkLines(lines []Line) *MkLines {
        mklines := make([]MkLine, len(lines))
        for i, line := range lines {
                mklines[i] = NewMkLine(line)
@@ -80,7 +78,7 @@ func (mklines *MkLines) VarValue(varname
 
 func (mklines *MkLines) Check() {
        if trace.Tracing {
-               defer trace.Call1(mklines.lines[0].Filename())()
+               defer trace.Call1(mklines.lines[0].Filename)()
        }
 
        G.Mk = mklines
@@ -102,7 +100,7 @@ func (mklines *MkLines) Check() {
 
        // In the second pass, the actual checks are done.
 
-       linechecks.CheckRcsid(mklines.lines[0], `#\s+`, "# ")
+       CheckLineRcsid(mklines.lines[0], `#\s+`, "# ")
 
        var substcontext SubstContext
        var varalign VaralignBlock
@@ -212,7 +210,7 @@ func (mklines *MkLines) DetermineDefined
                        }
                }
 
-               mklines.toolRegistry.ParseToolLine(mkline)
+               mklines.toolRegistry.ParseToolLine(mkline.Line)
        }
 }
 
Index: pkgsrc/pkgtools/pkglint/files/plist.go
diff -u pkgsrc/pkgtools/pkglint/files/plist.go:1.14 pkgsrc/pkgtools/pkglint/files/plist.go:1.15
--- pkgsrc/pkgtools/pkglint/files/plist.go:1.14 Sun Oct  8 22:31:13 2017
+++ pkgsrc/pkgtools/pkglint/files/plist.go      Mon Jan  1 18:04:15 2018
@@ -1,8 +1,6 @@
 package main
 
 import (
-       "netbsd.org/pkglint/line"
-       "netbsd.org/pkglint/linechecks"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
        "path"
@@ -10,12 +8,12 @@ import (
        "strings"
 )
 
-func ChecklinesPlist(lines []line.Line) {
+func ChecklinesPlist(lines []Line) {
        if trace.Tracing {
-               defer trace.Call1(lines[0].Filename())()
+               defer trace.Call1(lines[0].Filename)()
        }
 
-       linechecks.CheckRcsid(lines[0], `@comment `, "@comment ")
+       CheckLineRcsid(lines[0], `@comment `, "@comment ")
 
        if len(lines) == 1 {
                lines[0].Warnf("PLIST files shouldn't be empty.")
@@ -47,16 +45,16 @@ 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.Line) {
+func (ck *PlistChecker) Check(plainLines []Line) {
        plines := ck.NewLines(plainLines)
        ck.collectFilesAndDirs(plines)
 
-       if fname := plines[0].line.Filename(); path.Base(fname) == "PLIST.common_end" {
+       if fname := plines[0].line.Filename; path.Base(fname) == "PLIST.common_end" {
                commonLines, err := readLines(strings.TrimSuffix(fname, "_end"), false)
                if err == nil {
                        ck.collectFilesAndDirs(ck.NewLines(commonLines))
@@ -80,10 +78,10 @@ func (ck *PlistChecker) Check(plainLines
        }
 }
 
-func (ck *PlistChecker) NewLines(lines []line.Line) []*PlistLine {
+func (ck *PlistChecker) NewLines(lines []Line) []*PlistLine {
        plines := make([]*PlistLine, len(lines))
        for i, line := range lines {
-               conditional, text := "", line.Text()
+               conditional, text := "", line.Text
                if hasPrefix(text, "${PLIST.") {
                        if m, cond, rest := match2(text, `^\$\{(PLIST\.[\w-.]+)\}(.*)`); m {
                                conditional, text = cond, rest
@@ -483,14 +481,14 @@ func (pline *PlistLine) warnImakeMannews
 type plistLineSorter struct {
        first     *PlistLine
        plines    []*PlistLine
-       lines     []line.Line
-       after     map[*PlistLine][]line.Line
+       lines     []Line
+       after     map[*PlistLine][]Line
        swapped   bool
        autofixed bool
 }
 
 func NewPlistLineSorter(plines []*PlistLine) *plistLineSorter {
-       s := &plistLineSorter{first: plines[0], after: make(map[*PlistLine][]line.Line)}
+       s := &plistLineSorter{first: plines[0], after: make(map[*PlistLine][]Line)}
        prev := plines[0]
        for _, pline := range plines[1:] {
                if hasPrefix(pline.text, "@") || contains(pline.text, "$") {
@@ -525,7 +523,7 @@ func (s *plistLineSorter) Sort() {
 
        firstLine := s.first.line
        firstLine.AutofixMark("Sorting the whole file.")
-       lines := []line.Line{firstLine}
+       lines := []Line{firstLine}
        lines = append(lines, s.after[s.first]...)
        for _, pline := range s.plines {
                lines = append(lines, pline.line)

Index: pkgsrc/pkgtools/pkglint/files/files.go
diff -u pkgsrc/pkgtools/pkglint/files/files.go:1.11 pkgsrc/pkgtools/pkglint/files/files.go:1.12
--- pkgsrc/pkgtools/pkglint/files/files.go:1.11 Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/files.go      Mon Jan  1 18:04:15 2018
@@ -2,12 +2,12 @@ package main
 
 import (
        "io/ioutil"
-       "netbsd.org/pkglint/line"
+       "netbsd.org/pkglint/trace"
        "os"
        "strings"
 )
 
-func LoadNonemptyLines(fname string, joinBackslashLines bool) []line.Line {
+func LoadNonemptyLines(fname string, joinBackslashLines bool) []Line {
        lines, err := readLines(fname, joinBackslashLines)
        if err != nil {
                NewLineWhole(fname).Errorf("Cannot be read.")
@@ -20,7 +20,7 @@ func LoadNonemptyLines(fname string, joi
        return lines
 }
 
-func LoadExistingLines(fname string, joinBackslashLines bool) []line.Line {
+func LoadExistingLines(fname string, joinBackslashLines bool) []Line {
        lines, err := readLines(fname, joinBackslashLines)
        if err != nil {
                NewLineWhole(fname).Fatalf("Cannot be read.")
@@ -31,7 +31,7 @@ func LoadExistingLines(fname string, joi
        return lines
 }
 
-func getLogicalLine(fname string, rawLines []*RawLine, pindex *int) line.Line {
+func getLogicalLine(fname string, rawLines []*RawLine, pindex *int) Line {
        { // Handle the common case efficiently
                index := *pindex
                rawLine := rawLines[index]
@@ -102,7 +102,7 @@ func splitRawLine(textnl string) (leadin
        return
 }
 
-func readLines(fname string, joinBackslashLines bool) ([]line.Line, error) {
+func readLines(fname string, joinBackslashLines bool) ([]Line, error) {
        rawText, err := ioutil.ReadFile(fname)
        if err != nil {
                return nil, err
@@ -111,7 +111,7 @@ func readLines(fname string, joinBacksla
        return convertToLogicalLines(fname, string(rawText), joinBackslashLines), nil
 }
 
-func convertToLogicalLines(fname string, rawText string, joinBackslashLines bool) []line.Line {
+func convertToLogicalLines(fname string, rawText string, joinBackslashLines bool) []Line {
        var rawLines []*RawLine
        for lineno, rawLine := range strings.SplitAfter(rawText, "\n") {
                if rawLine != "" {
@@ -119,7 +119,7 @@ func convertToLogicalLines(fname string,
                }
        }
 
-       var loglines []line.Line
+       var loglines []Line
        if joinBackslashLines {
                for lineno := 0; lineno < len(rawLines); {
                        loglines = append(loglines, getLogicalLine(fname, rawLines, &lineno))
@@ -139,10 +139,14 @@ func convertToLogicalLines(fname string,
        return loglines
 }
 
-func SaveAutofixChanges(lines []line.Line) (autofixed bool) {
+func SaveAutofixChanges(lines []Line) (autofixed bool) {
+       if trace.Tracing {
+               defer trace.Call0()()
+       }
+
        if !G.opts.Autofix {
                for _, line := range lines {
-                       if line.IsChanged() {
+                       if line.Changed {
                                G.autofixAvailable = true
                        }
                }
@@ -152,10 +156,10 @@ func SaveAutofixChanges(lines []line.Lin
        changes := make(map[string][]string)
        changed := make(map[string]bool)
        for _, line := range lines {
-               if line.IsChanged() {
-                       changed[line.Filename()] = true
+               if line.Changed {
+                       changed[line.Filename] = true
                }
-               changes[line.Filename()] = append(changes[line.Filename()], line.(*LineImpl).modifiedLines()...)
+               changes[line.Filename] = append(changes[line.Filename], line.modifiedLines()...)
        }
 
        for fname := range changed {

Index: pkgsrc/pkgtools/pkglint/files/globaldata.go
diff -u pkgsrc/pkgtools/pkglint/files/globaldata.go:1.21 pkgsrc/pkgtools/pkglint/files/globaldata.go:1.22
--- pkgsrc/pkgtools/pkglint/files/globaldata.go:1.21    Sun Oct  8 22:31:13 2017
+++ pkgsrc/pkgtools/pkglint/files/globaldata.go Mon Jan  1 18:04:15 2018
@@ -2,7 +2,6 @@ package main
 
 import (
        "io/ioutil"
-       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
        "path"
@@ -29,7 +28,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
@@ -39,7 +38,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
@@ -109,7 +108,7 @@ func (gd *GlobalData) loadDistSites() {
        name2url := make(map[string]string)
        url2name := make(map[string]string)
        for _, line := range lines {
-               if m, varname, _, _, _, urls, _, _ := MatchVarassign(line.Text()); m {
+               if m, varname, _, _, _, urls, _, _ := MatchVarassign(line.Text); m {
                        if hasPrefix(varname, "MASTER_SITE_") && varname != "MASTER_SITE_BACKUP" {
                                for _, url := range splitOnSpace(urls) {
                                        if matches(url, `^(?:http://|https://|ftp://)`) {
@@ -139,7 +138,7 @@ func (gd *GlobalData) loadPkgOptions() {
 
        gd.PkgOptions = make(map[string]string)
        for _, line := range lines {
-               if m, optname, optdescr := match2(line.Text(), `^([-0-9a-z_+]+)(?:\s+(.*))?$`); m {
+               if m, optname, optdescr := match2(line.Text, `^([-0-9a-z_+]+)(?:\s+(.*))?$`); m {
                        gd.PkgOptions[optname] = optdescr
                } else {
                        line.Fatalf("Unknown line format.")
@@ -153,7 +152,7 @@ func (gd *GlobalData) loadTools() {
                fname := G.globalData.Pkgsrcdir + "/mk/tools/bsd.tools.mk"
                lines := LoadExistingLines(fname, true)
                for _, line := range lines {
-                       if m, _, _, includefile := MatchMkInclude(line.Text()); m {
+                       if m, _, _, includefile := MatchMkInclude(line.Text); m {
                                if !contains(includefile, "/") {
                                        toolFiles = append(toolFiles, includefile)
                                }
@@ -187,7 +186,7 @@ func (gd *GlobalData) loadTools() {
 
                lines := LoadExistingLines(fname, true)
                for _, line := range lines {
-                       text := line.Text()
+                       text := line.Text
 
                        if m, varname, _, _, _, value, _, _ := MatchVarassign(text); m {
                                if varname == "USE_TOOLS" {
@@ -254,11 +253,11 @@ func loadSuggestedUpdates(fname string) 
        return parselinesSuggestedUpdates(lines)
 }
 
-func parselinesSuggestedUpdates(lines []line.Line) []SuggestedUpdate {
+func parselinesSuggestedUpdates(lines []Line) []SuggestedUpdate {
        var updates []SuggestedUpdate
        state := 0
        for _, line := range lines {
-               text := line.Text()
+               text := line.Text
 
                if state == 0 && text == "Suggested package updates" {
                        state = 1
@@ -295,8 +294,8 @@ func (gd *GlobalData) loadSuggestedUpdat
 func (gd *GlobalData) loadDocChangesFromFile(fname string) []*Change {
        lines := LoadExistingLines(fname, false)
 
-       parseChange := func(line line.Line) *Change {
-               text := line.Text()
+       parseChange := func(line Line) *Change {
+               text := line.Text
                if !hasPrefix(text, "\t") {
                        return nil
                }
@@ -330,7 +329,7 @@ func (gd *GlobalData) loadDocChangesFrom
        for _, line := range lines {
                if change := parseChange(line); change != nil {
                        changes = append(changes, change)
-               } else if text := line.Text(); len(text) >= 2 && text[0] == '\t' && 'A' <= text[1] && text[1] <= 'Z' {
+               } else if text := line.Text; len(text) >= 2 && text[0] == '\t' && 'A' <= text[1] && text[1] <= 'Z' {
                        line.Warnf("Unknown doc/CHANGES line: %q", text)
                        Explain("See mk/misc/developer.mk for the rules.")
                }
@@ -604,8 +603,8 @@ func (tr *ToolRegistry) Trace() {
        }
 }
 
-func (tr *ToolRegistry) ParseToolLine(line line.Line) {
-       if m, varname, _, _, _, value, _, _ := MatchVarassign(line.Text()); m {
+func (tr *ToolRegistry) ParseToolLine(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/pkglint.go
diff -u pkgsrc/pkgtools/pkglint/files/pkglint.go:1.21 pkgsrc/pkgtools/pkglint/files/pkglint.go:1.22
--- pkgsrc/pkgtools/pkglint/files/pkglint.go:1.21       Sun Oct  8 22:31:13 2017
+++ pkgsrc/pkgtools/pkglint/files/pkglint.go    Mon Jan  1 18:04:15 2018
@@ -5,8 +5,6 @@ import (
        "io"
        "netbsd.org/pkglint/getopt"
        "netbsd.org/pkglint/histogram"
-       "netbsd.org/pkglint/line"
-       "netbsd.org/pkglint/linechecks"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
        "os"
@@ -274,16 +272,16 @@ func CheckfileExtra(fname string) {
        }
 }
 
-func ChecklinesDescr(lines []line.Line) {
+func ChecklinesDescr(lines []Line) {
        if trace.Tracing {
-               defer trace.Call1(lines[0].Filename())()
+               defer trace.Call1(lines[0].Filename)()
        }
 
        for _, line := range lines {
-               linechecks.CheckLength(line, 80)
-               linechecks.CheckTrailingWhitespace(line)
-               linechecks.CheckValidCharacters(line, `[\t -~]`)
-               if contains(line.Text(), "${") {
+               CheckLineLength(line, 80)
+               CheckLineTrailingWhitespace(line)
+               CheckLineValidCharacters(line, `[\t -~]`)
+               if contains(line.Text, "${") {
                        line.Notef("Variables are not expanded in the DESCR file.")
                }
        }
@@ -302,9 +300,9 @@ func ChecklinesDescr(lines []line.Line) 
        SaveAutofixChanges(lines)
 }
 
-func ChecklinesMessage(lines []line.Line) {
+func ChecklinesMessage(lines []Line) {
        if trace.Tracing {
-               defer trace.Call1(lines[0].Filename())()
+               defer trace.Call1(lines[0].Filename)()
        }
 
        explainMessage := func() {
@@ -323,17 +321,17 @@ func ChecklinesMessage(lines []line.Line
        }
 
        hline := strings.Repeat("=", 75)
-       if line := lines[0]; line.Text() != hline {
+       if line := lines[0]; line.Text != hline {
                line.Warnf("Expected a line of exactly 75 \"=\" characters.")
                explainMessage()
        }
-       linechecks.CheckRcsid(lines[1], ``, "")
+       CheckLineRcsid(lines[1], ``, "")
        for _, line := range lines {
-               linechecks.CheckLength(line, 80)
-               linechecks.CheckTrailingWhitespace(line)
-               linechecks.CheckValidCharacters(line, `[\t -~]`)
+               CheckLineLength(line, 80)
+               CheckLineTrailingWhitespace(line)
+               CheckLineValidCharacters(line, `[\t -~]`)
        }
-       if lastLine := lines[len(lines)-1]; lastLine.Text() != hline {
+       if lastLine := lines[len(lines)-1]; lastLine.Text != hline {
                lastLine.Warnf("Expected a line of exactly 75 \"=\" characters.")
                explainMessage()
        }
@@ -488,10 +486,10 @@ func Checkfile(fname string) {
        }
 }
 
-func ChecklinesTrailingEmptyLines(lines []line.Line) {
+func ChecklinesTrailingEmptyLines(lines []Line) {
        max := len(lines)
        last := max
-       for last > 1 && lines[last-1].Text() == "" {
+       for last > 1 && lines[last-1].Text == "" {
                last--
        }
        if last != max {

Index: pkgsrc/pkgtools/pkglint/files/globalvars.go
diff -u pkgsrc/pkgtools/pkglint/files/globalvars.go:1.7 pkgsrc/pkgtools/pkglint/files/globalvars.go:1.8
--- pkgsrc/pkgtools/pkglint/files/globalvars.go:1.7     Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/globalvars.go Mon Jan  1 18:04:15 2018
@@ -3,7 +3,6 @@ package main
 import (
        "io"
        "netbsd.org/pkglint/histogram"
-       "netbsd.org/pkglint/line"
 )
 
 type GlobalVars struct {
@@ -20,7 +19,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.Line
+       CvsEntriesLines []Line
 
        Hash         map[string]*Hash // Maps "alg:fname" => hash (inter-package check).
        UsedLicenses map[string]bool  // Maps "license name" => true (inter-package check).
@@ -82,7 +81,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.7 pkgsrc/pkgtools/pkglint/files/toplevel.go:1.8
--- pkgsrc/pkgtools/pkglint/files/toplevel.go:1.7       Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/toplevel.go   Mon Jan  1 18:04:15 2018
@@ -1,7 +1,6 @@
 package main
 
 import (
-       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/trace"
 )
 
@@ -24,7 +23,7 @@ func CheckdirToplevel() {
        }
 
        for _, line := range lines {
-               if m, commentedOut, indentation, subdir, comment := match4(line.Text(), `^(#?)SUBDIR\s*\+=(\s*)(\S+)\s*(?:#\s*(.*?)\s*|)$`); m {
+               if m, commentedOut, indentation, subdir, comment := match4(line.Text, `^(#?)SUBDIR\s*\+=(\s*)(\S+)\s*(?:#\s*(.*?)\s*|)$`); m {
                        ctx.checkSubdir(line, commentedOut == "#", indentation, subdir, comment)
                }
        }
@@ -40,7 +39,7 @@ func CheckdirToplevel() {
        }
 }
 
-func (ctx *Toplevel) checkSubdir(line line.Line, commentedOut bool, indentation, subdir, comment string) {
+func (ctx *Toplevel) checkSubdir(line Line, commentedOut bool, indentation, subdir, comment string) {
        if commentedOut && comment == "" {
                line.Warnf("%q commented out without giving a reason.", subdir)
        }

Index: pkgsrc/pkgtools/pkglint/files/line.go
diff -u pkgsrc/pkgtools/pkglint/files/line.go:1.16 pkgsrc/pkgtools/pkglint/files/line.go:1.17
--- pkgsrc/pkgtools/pkglint/files/line.go:1.16  Sun Oct  8 22:31:13 2017
+++ pkgsrc/pkgtools/pkglint/files/line.go       Mon Jan  1 18:04:15 2018
@@ -16,14 +16,14 @@ package main
 import (
        "fmt"
        "io"
-       "netbsd.org/pkglint/line"
-       "netbsd.org/pkglint/linechecks"
        "netbsd.org/pkglint/regex"
        "path"
        "strconv"
        "strings"
 )
 
+type Line = *LineImpl
+
 type RawLine struct {
        Lineno int
        orignl string
@@ -35,48 +35,36 @@ func (rline *RawLine) String() string {
 }
 
 type LineImpl struct {
-       fname          string
+       Filename       string
        firstLine      int32 // Zero means not applicable, -1 means EOF
        lastLine       int32 // Usually the same as firstLine, may differ in Makefiles
-       text           string
+       Text           string
        raw            []*RawLine
-       changed        bool
+       Changed        bool
        before         []string
        after          []string
        autofixMessage string
 }
 
-func NewLine(fname string, lineno int, text string, rawLines []*RawLine) line.Line {
+func NewLine(fname string, lineno int, text string, rawLines []*RawLine) 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.Line {
+func NewLineMulti(fname string, firstLine, lastLine int, text string, rawLines []*RawLine) 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.Line {
+func NewLineEOF(fname string) 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.Line {
+func NewLineWhole(fname string) Line {
        return NewLine(fname, 0, "", nil)
 }
 
-func (line *LineImpl) Filename() string {
-       return line.fname
-}
-
-func (line *LineImpl) Text() string {
-       return line.text
-}
-
-func (line *LineImpl) IsChanged() bool {
-       return line.changed
-}
-
 func (line *LineImpl) modifiedLines() []string {
        var result []string
        result = append(result, line.before...)
@@ -100,9 +88,9 @@ func (line *LineImpl) Linenos() 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()
+func (line *LineImpl) ReferenceFrom(other Line) string {
+       if line.Filename != other.Filename {
+               return cleanpath(relpath(path.Dir(other.Filename), line.Filename)) + ":" + line.Linenos()
        }
        return "line " + line.Linenos()
 }
@@ -137,34 +125,34 @@ func (line *LineImpl) printSource(out io
 
 func (line *LineImpl) Fatalf(format string, args ...interface{}) {
        line.printSource(G.logErr)
-       logs(llFatal, line.fname, line.Linenos(), format, fmt.Sprintf(format, args...))
+       logs(llFatal, line.Filename, line.Linenos(), format, fmt.Sprintf(format, args...))
 }
 
 func (line *LineImpl) Errorf(format string, args ...interface{}) {
        line.printSource(G.logOut)
-       logs(llError, line.fname, line.Linenos(), format, fmt.Sprintf(format, args...))
+       logs(llError, line.Filename, line.Linenos(), format, fmt.Sprintf(format, args...))
        line.logAutofix()
 }
 
 func (line *LineImpl) Warnf(format string, args ...interface{}) {
        line.printSource(G.logOut)
-       logs(llWarn, line.fname, line.Linenos(), format, fmt.Sprintf(format, args...))
+       logs(llWarn, line.Filename, line.Linenos(), format, fmt.Sprintf(format, args...))
        line.logAutofix()
 }
 
 func (line *LineImpl) Notef(format string, args ...interface{}) {
        line.printSource(G.logOut)
-       logs(llNote, line.fname, line.Linenos(), format, fmt.Sprintf(format, args...))
+       logs(llNote, line.Filename, line.Linenos(), format, fmt.Sprintf(format, args...))
        line.logAutofix()
 }
 
 func (line *LineImpl) String() string {
-       return line.fname + ":" + line.Linenos() + ": " + line.text
+       return line.Filename + ":" + line.Linenos() + ": " + line.Text
 }
 
 func (line *LineImpl) logAutofix() {
        if line.autofixMessage != "" {
-               logs(llAutofix, line.fname, line.Linenos(), "%s", line.autofixMessage)
+               logs(llAutofix, line.Filename, line.Linenos(), "%s", line.autofixMessage)
                line.autofixMessage = ""
        }
 }
@@ -224,9 +212,9 @@ func (line *LineImpl) RememberAutofix(fo
        if line.firstLine < 1 {
                return false
        }
-       line.changed = true
+       line.Changed = true
        if G.opts.Autofix {
-               logs(llAutofix, line.fname, line.Linenos(), format, fmt.Sprintf(format, args...))
+               logs(llAutofix, line.Filename, line.Linenos(), format, fmt.Sprintf(format, args...))
                return true
        }
        if G.opts.PrintAutofix {
@@ -238,10 +226,5 @@ func (line *LineImpl) RememberAutofix(fo
 func (line *LineImpl) AutofixMark(reason string) {
        line.RememberAutofix(reason)
        line.logAutofix()
-       line.changed = true
-}
-
-func init() {
-       line.NewLineEOF = NewLineEOF
-       linechecks.Explain = Explain
+       line.Changed = true
 }

Index: pkgsrc/pkgtools/pkglint/files/mkline.go
diff -u pkgsrc/pkgtools/pkglint/files/mkline.go:1.22 pkgsrc/pkgtools/pkglint/files/mkline.go:1.23
--- pkgsrc/pkgtools/pkglint/files/mkline.go:1.22        Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/mkline.go     Mon Jan  1 18:04:15 2018
@@ -4,59 +4,15 @@ package main
 
 import (
        "fmt"
-       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
        "strings"
 )
 
-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 MkLine = *MkLineImpl
 
 type MkLineImpl struct {
-       line.Line
+       Line
        data interface{} // One of the following mkLine* types
 }
 type mkLineAssign struct {
@@ -90,10 +46,10 @@ type mkLineDependency struct {
        sources string
 }
 
-func NewMkLine(line line.Line) (mkline *MkLineImpl) {
+func NewMkLine(line Line) (mkline *MkLineImpl) {
        mkline = &MkLineImpl{Line: line}
 
-       text := line.Text()
+       text := line.Text
 
        if hasPrefix(text, " ") {
                mkline.Warnf("Makefile lines should not start with space characters.")
@@ -188,7 +144,7 @@ func NewMkLine(line line.Line) (mkline *
 }
 
 func (mkline *MkLineImpl) String() string {
-       return fmt.Sprintf("%s:%s", mkline.Filename(), mkline.Linenos())
+       return fmt.Sprintf("%s:%s", mkline.Filename, mkline.Linenos())
 }
 func (mkline *MkLineImpl) IsVarassign() bool { _, ok := mkline.data.(mkLineAssign); return ok }
 func (mkline *MkLineImpl) IsShellcmd() bool  { _, ok := mkline.data.(mkLineShell); return ok }
@@ -226,6 +182,7 @@ func (mkline *MkLineImpl) Includefile() 
 func (mkline *MkLineImpl) Targets() string     { return mkline.data.(mkLineDependency).targets }
 func (mkline *MkLineImpl) Sources() string     { return mkline.data.(mkLineDependency).sources }
 
+// Initialized step by step, when parsing other lines
 func (mkline *MkLineImpl) ConditionVars() string { return mkline.data.(mkLineInclude).conditionVars }
 func (mkline *MkLineImpl) SetConditionVars(varnames string) {
        include := mkline.data.(mkLineInclude)
@@ -238,7 +195,7 @@ func (mkline *MkLineImpl) Tokenize(s str
                defer trace.Call(mkline, s)()
        }
 
-       p := NewMkParser(mkline, s, true)
+       p := NewMkParser(mkline.Line, s, true)
        tokens := p.MkTokens()
        if p.Rest() != "" {
                mkline.Warnf("Pkglint parse error in MkLine.Tokenize at %q.", p.Rest())
@@ -593,7 +550,7 @@ func (mkline *MkLineImpl) ExtractUsedVar
 }
 
 func (mkline *MkLineImpl) DetermineUsedVariables() (varnames []string) {
-       rest := mkline.Text()
+       rest := mkline.Text
 
        if strings.HasPrefix(rest, "#") {
                return

Index: pkgsrc/pkgtools/pkglint/files/mkline_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mkline_test.go:1.24 pkgsrc/pkgtools/pkglint/files/mkline_test.go:1.25
--- pkgsrc/pkgtools/pkglint/files/mkline_test.go:1.24   Sun Oct  8 22:31:13 2017
+++ pkgsrc/pkgtools/pkglint/files/mkline_test.go        Mon Jan  1 18:04:15 2018
@@ -28,20 +28,20 @@ func (s *Suite) Test_VaralignBlock_Check
        }
        varalign.Finish()
 
-       c.Check(lines[0].IsChanged(), equals, true)
-       c.Check(lines[0].(*LineImpl).raw[0].String(), equals, "1:VAR=\tvalue\n")
-       c.Check(lines[2].IsChanged(), equals, true)
-       c.Check(lines[2].(*LineImpl).raw[0].String(), equals, "3:VAR=\tvalue\n")
-       c.Check(lines[4].IsChanged(), equals, true)
-       c.Check(lines[4].(*LineImpl).raw[0].String(), equals, "5:VAR=\tvalue\n")
-       c.Check(lines[6].IsChanged(), equals, true)
-       c.Check(lines[6].(*LineImpl).raw[0].String(), equals, "7:VAR=\tvalue\n")
-       c.Check(lines[8].IsChanged(), equals, true)
-       c.Check(lines[8].(*LineImpl).raw[0].String(), equals, "9:VAR=\tvalue\n")
-       c.Check(lines[10].IsChanged(), equals, true)
-       c.Check(lines[10].(*LineImpl).raw[0].String(), equals, "11:VAR=\tvalue\n")
-       c.Check(lines[12].IsChanged(), equals, false)
-       c.Check(lines[12].(*LineImpl).raw[0].String(), equals, "13:VAR=\tvalue\n")
+       c.Check(lines[0].Changed, equals, true)
+       c.Check(lines[0].raw[0].String(), equals, "1:VAR=\tvalue\n")
+       c.Check(lines[2].Changed, equals, true)
+       c.Check(lines[2].raw[0].String(), equals, "3:VAR=\tvalue\n")
+       c.Check(lines[4].Changed, equals, true)
+       c.Check(lines[4].raw[0].String(), equals, "5:VAR=\tvalue\n")
+       c.Check(lines[6].Changed, equals, true)
+       c.Check(lines[6].raw[0].String(), equals, "7:VAR=\tvalue\n")
+       c.Check(lines[8].Changed, equals, true)
+       c.Check(lines[8].raw[0].String(), equals, "9:VAR=\tvalue\n")
+       c.Check(lines[10].Changed, equals, true)
+       c.Check(lines[10].raw[0].String(), equals, "11:VAR=\tvalue\n")
+       c.Check(lines[12].Changed, equals, false)
+       c.Check(lines[12].raw[0].String(), equals, "13:VAR=\tvalue\n")
        c.Check(s.Output(), equals, ""+
                "NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 9.\n"+
                "AUTOFIX: file.mk:1: Replacing \"VAR=   \" with \"VAR=\\t\".\n"+

Index: pkgsrc/pkgtools/pkglint/files/mklinechecker.go
diff -u pkgsrc/pkgtools/pkglint/files/mklinechecker.go:1.3 pkgsrc/pkgtools/pkglint/files/mklinechecker.go:1.4
--- pkgsrc/pkgtools/pkglint/files/mklinechecker.go:1.3  Sun Oct  8 22:31:13 2017
+++ pkgsrc/pkgtools/pkglint/files/mklinechecker.go      Mon Jan  1 18:04:15 2018
@@ -2,7 +2,6 @@ package main
 
 import (
        "fmt"
-       "netbsd.org/pkglint/linechecks"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
        "os"
@@ -18,8 +17,8 @@ type MkLineChecker struct {
 func (ck MkLineChecker) Check() {
        mkline := ck.MkLine
 
-       linechecks.CheckTrailingWhitespace(mkline)
-       linechecks.CheckValidCharacters(mkline, `[\t -~]`)
+       CheckLineTrailingWhitespace(mkline.Line)
+       CheckLineValidCharacters(mkline.Line, `[\t -~]`)
 
        switch {
        case mkline.IsVarassign():
@@ -31,7 +30,7 @@ func (ck MkLineChecker) Check() {
                NewShellLine(mkline).CheckShellCommandLine(shellcmd)
 
        case mkline.IsComment():
-               if hasPrefix(mkline.Text(), "# url2pkg-marker") {
+               if hasPrefix(mkline.Text, "# url2pkg-marker") {
                        mkline.Errorf("This comment indicates unfinished work (url2pkg).")
                }
 
@@ -53,7 +52,7 @@ func (ck MkLineChecker) checkInclude() {
        includefile := mkline.Includefile()
        mustExist := mkline.MustExist()
        if trace.Tracing {
-               trace.Step2("includingFile=%s includefile=%s", mkline.Filename(), includefile)
+               trace.Step2("includingFile=%s includefile=%s", mkline.Filename, includefile)
        }
        ck.CheckRelativePath(includefile, mustExist)
 
@@ -67,7 +66,7 @@ func (ck MkLineChecker) checkInclude() {
                        "Makefile.common.")
 
        case includefile == "../../mk/bsd.prefs.mk":
-               if path.Base(mkline.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 {
@@ -248,7 +247,7 @@ func (ck MkLineChecker) checkVarassignDe
                return
        }
 
-       perms := vartype.EffectivePermissions(mkline.Filename())
+       perms := vartype.EffectivePermissions(mkline.Filename)
        var needed AclPermissions
        switch op {
        case opAssign, opAssignShell, opAssignEval:
@@ -358,7 +357,7 @@ func (ck MkLineChecker) CheckVarusePermi
        }
 
        mkline := ck.MkLine
-       perms := vartype.EffectivePermissions(mkline.Filename())
+       perms := vartype.EffectivePermissions(mkline.Filename)
 
        isLoadTime := false // Will the variable be used at load time?
 
@@ -726,7 +725,7 @@ func (ck MkLineChecker) checkVarassignVa
                defer trace.Call(vartype, time)()
        }
        mkline := ck.MkLine
-       tokens := NewMkParser(mkline, mkline.Value(), false).MkTokens()
+       tokens := NewMkParser(mkline.Line, mkline.Value(), false).MkTokens()
        for i, token := range tokens {
                if token.Varuse != nil {
                        spaceLeft := i-1 < 0 || matches(tokens[i-1].Text, `\s$`)
@@ -754,7 +753,7 @@ func (ck MkLineChecker) checkVarassignVa
        }
 
        mkline := ck.MkLine
-       atoms := NewShTokenizer(mkline, mkline.Value(), false).ShAtoms()
+       atoms := NewShTokenizer(mkline.Line, mkline.Value(), false).ShAtoms()
        for i, atom := range atoms {
                if atom.Type == shtVaruse {
                        isWordPart := isWordPart(atoms, i)
@@ -908,7 +907,7 @@ func (ck MkLineChecker) CheckVartype(var
                }
 
        case vartype.kindOfList == lkShell:
-               words, _ := splitIntoMkWords(mkline, value)
+               words, _ := splitIntoMkWords(mkline.Line, value)
                for _, word := range words {
                        ck.CheckVartypePrimitive(varname, vartype.basicType, op, word, comment, vartype.guessed)
                }
@@ -924,7 +923,7 @@ func (ck MkLineChecker) CheckVartypePrim
 
        mkline := ck.MkLine
        valueNoVar := mkline.WithoutMakeVariables(value)
-       ctx := &VartypeCheck{mkline, mkline, varname, op, value, valueNoVar, comment, guessed}
+       ctx := &VartypeCheck{mkline, mkline.Line, varname, op, value, valueNoVar, comment, guessed}
        checker.checker(ctx)
 }
 
@@ -982,7 +981,7 @@ func (ck MkLineChecker) CheckCond() {
                defer trace.Call1(mkline.Args())()
        }
 
-       p := NewMkParser(mkline, mkline.Args(), false)
+       p := NewMkParser(mkline.Line, mkline.Args(), false)
        cond := p.MkCond()
        if !p.EOF() {
                mkline.Warnf("Invalid conditional %q.", mkline.Args())

Index: pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go:1.2 pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go:1.3
--- pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go:1.2     Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go Mon Jan  1 18:04:15 2018
@@ -243,7 +243,7 @@ func (s *Suite) Test_MkLineChecker_Check
                "CFLAGS+=\t`pkg-config pidgin --cflags`")
        mkline := G.Mk.mklines[1]
 
-       words, rest := splitIntoMkWords(mkline, mkline.Value())
+       words, rest := splitIntoMkWords(mkline.Line, mkline.Value())
 
        c.Check(words, deepEquals, []string{"`pkg-config pidgin --cflags`"})
        c.Check(rest, equals, "")
Index: pkgsrc/pkgtools/pkglint/files/mkshwalker.go
diff -u pkgsrc/pkgtools/pkglint/files/mkshwalker.go:1.2 pkgsrc/pkgtools/pkglint/files/mkshwalker.go:1.3
--- pkgsrc/pkgtools/pkglint/files/mkshwalker.go:1.2     Sat Jul  9 09:43:48 2016
+++ pkgsrc/pkgtools/pkglint/files/mkshwalker.go Mon Jan  1 18:04:15 2018
@@ -3,6 +3,8 @@ package main
 type MkShWalker struct {
 }
 
+// Walk calls the given callback for each node of the parsed shell program.
+// See the types in mkshtypes.go for possible node types.
 func (w *MkShWalker) Walk(list *MkShList, callback func(node interface{})) {
        for element := range w.iterate(list) {
                callback(element)
Index: pkgsrc/pkgtools/pkglint/files/mktypes.go
diff -u pkgsrc/pkgtools/pkglint/files/mktypes.go:1.2 pkgsrc/pkgtools/pkglint/files/mktypes.go:1.3
--- pkgsrc/pkgtools/pkglint/files/mktypes.go:1.2        Sun Jul 10 21:24:47 2016
+++ pkgsrc/pkgtools/pkglint/files/mktypes.go    Mon Jan  1 18:04:15 2018
@@ -1,9 +1,13 @@
 package main
 
+// Example (3 tokens): /usr/share/${PKGNAME}/data
 type MkToken struct {
        Text   string // Used for both literals and varuses.
        Varuse *MkVarUse
 }
+
+// Example: ${PKGNAME}
+// Example: ${PKGNAME:S/from/to/}
 type MkVarUse struct {
        varname   string
        modifiers []string // E.g. "Q", "S/from/to/"

Index: pkgsrc/pkgtools/pkglint/files/mkparser.go
diff -u pkgsrc/pkgtools/pkglint/files/mkparser.go:1.9 pkgsrc/pkgtools/pkglint/files/mkparser.go:1.10
--- pkgsrc/pkgtools/pkglint/files/mkparser.go:1.9       Sun Oct  8 22:31:13 2017
+++ pkgsrc/pkgtools/pkglint/files/mkparser.go   Mon Jan  1 18:04:15 2018
@@ -1,7 +1,6 @@
 package main
 
 import (
-       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
        "strings"
@@ -11,7 +10,7 @@ type MkParser struct {
        *Parser
 }
 
-func NewMkParser(line line.Line, text string, emitWarnings bool) *MkParser {
+func NewMkParser(line Line, text string, emitWarnings bool) *MkParser {
        return &MkParser{NewParser(line, text, emitWarnings)}
 }
 

Index: pkgsrc/pkgtools/pkglint/files/mkshparser.go
diff -u pkgsrc/pkgtools/pkglint/files/mkshparser.go:1.5 pkgsrc/pkgtools/pkglint/files/mkshparser.go:1.6
--- pkgsrc/pkgtools/pkglint/files/mkshparser.go:1.5     Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/mkshparser.go Mon Jan  1 18:04:15 2018
@@ -2,12 +2,11 @@ package main
 
 import (
        "fmt"
-       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/trace"
        "strconv"
 )
 
-func parseShellProgram(line line.Line, program string) (list *MkShList, err error) {
+func parseShellProgram(line Line, program string) (list *MkShList, err error) {
        if trace.Tracing {
                defer trace.Call(program)()
        }

Index: pkgsrc/pkgtools/pkglint/files/mkshtypes.go
diff -u pkgsrc/pkgtools/pkglint/files/mkshtypes.go:1.6 pkgsrc/pkgtools/pkglint/files/mkshtypes.go:1.7
--- pkgsrc/pkgtools/pkglint/files/mkshtypes.go:1.6      Sun Oct  8 22:31:13 2017
+++ pkgsrc/pkgtools/pkglint/files/mkshtypes.go  Mon Jan  1 18:04:15 2018
@@ -5,6 +5,7 @@ import (
        "netbsd.org/pkglint/regex"
 )
 
+// Example: cd $dir && echo "In $dir"; cd ..; ls -l
 type MkShList struct {
        AndOrs     []*MkShAndOr
        Separators []MkShSeparator
@@ -24,6 +25,7 @@ func (list *MkShList) AddSeparator(separ
        return list
 }
 
+// Example: cd $dir && echo "In $dir" || echo "Cannot cd into $dir"
 type MkShAndOr struct {
        Pipes []*MkShPipeline
        Ops   []string // Each element is either "&&" or "||"
@@ -39,6 +41,7 @@ func (andor *MkShAndOr) Add(op string, p
        return andor
 }
 
+// Example: grep word file | sed s,^,---,
 type MkShPipeline struct {
        Negated bool
        Cmds    []*MkShCommand
@@ -53,6 +56,9 @@ func (pipe *MkShPipeline) Add(cmd *MkShC
        return pipe
 }
 
+// Example: LC_ALL=C sort */*.c > sorted
+// Example: dir() { ls -l "$@"; }
+// Example: { echo "first"; echo "second"; }
 type MkShCommand struct {
        Simple    *MkShSimpleCommand
        Compound  *MkShCompoundCommand
@@ -60,6 +66,10 @@ type MkShCommand struct {
        Redirects []*MkShRedirection // For Compound and FuncDef
 }
 
+// Example: { echo "first"; echo "second"; }
+// Example: for f in *.c; do compile "$f"; done
+// Example: if [ -f "$file" ]; then echo "It exists"; fi
+// Example: while sleep 1; do printf .; done
 type MkShCompoundCommand struct {
        Brace    *MkShList
        Subshell *MkShList
@@ -69,23 +79,27 @@ type MkShCompoundCommand struct {
        Loop     *MkShLoopClause
 }
 
+// Example: for f in *.c; do compile "$f"; done
 type MkShForClause struct {
        Varname string
        Values  []*ShToken
        Body    *MkShList
 }
 
+// Example: case $filename in *.c) echo "C source" ;; esac
 type MkShCaseClause struct {
        Word  *ShToken
        Cases []*MkShCaseItem
 }
 
+// Example: *.c) echo "C source" ;;
 type MkShCaseItem struct {
        Patterns  []*ShToken
        Action    *MkShList
        Separator MkShSeparator
 }
 
+// Example: if [ -f "$file" ]; then echo "It exists"; fi
 type MkShIfClause struct {
        Conds   []*MkShList
        Actions []*MkShList
@@ -97,17 +111,20 @@ func (cl *MkShIfClause) Prepend(cond *Mk
        cl.Actions = append([]*MkShList{action}, cl.Actions...)
 }
 
+// Example: while sleep 1; do printf .; done
 type MkShLoopClause struct {
        Cond   *MkShList
        Action *MkShList
        Until  bool
 }
 
+// Example: dir() { ls -l "$@"; }
 type MkShFunctionDefinition struct {
        Name string
        Body *MkShCompoundCommand
 }
 
+// Example: LC_ALL=C sort */*.c > sorted
 type MkShSimpleCommand struct {
        Assignments  []*ShToken
        Name         *ShToken
@@ -132,6 +149,11 @@ func NewStrCommand(cmd *MkShSimpleComman
        return strcmd
 }
 
+// Similar to MkShSimpleCommand, but all components are converted
+// to strings to allow for simpler checks, especially for analyzing
+// command line options.
+//
+// Example: LC_ALL=C sort */*.c > sorted
 type StrCommand struct {
        Assignments []string
        Name        string
@@ -160,10 +182,12 @@ func (c *StrCommand) String() string {
        return fmt.Sprintf("%v %v %v", c.Assignments, c.Name, c.Args)
 }
 
+// Example: > sorted
+// Example: 2>&1
 type MkShRedirection struct {
-       Fd     int // Or -1
-       Op     string
-       Target *ShToken
+       Fd     int      // Or -1
+       Op     string   // See io_file in shell.y for possible values
+       Target *ShToken // The file name or &fd
 }
 
 type MkShSeparator uint8
Index: pkgsrc/pkgtools/pkglint/files/shtokenizer.go
diff -u pkgsrc/pkgtools/pkglint/files/shtokenizer.go:1.6 pkgsrc/pkgtools/pkglint/files/shtokenizer.go:1.7
--- pkgsrc/pkgtools/pkglint/files/shtokenizer.go:1.6    Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/shtokenizer.go        Mon Jan  1 18:04:15 2018
@@ -1,7 +1,6 @@
 package main
 
 import (
-       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/textproc"
 )
 
@@ -10,7 +9,7 @@ type ShTokenizer struct {
        mkp    *MkParser
 }
 
-func NewShTokenizer(line line.Line, text string, emitWarnings bool) *ShTokenizer {
+func NewShTokenizer(line Line, text string, emitWarnings bool) *ShTokenizer {
        p := NewParser(line, text, emitWarnings)
        mkp := &MkParser{p}
        return &ShTokenizer{p, mkp}

Index: pkgsrc/pkgtools/pkglint/files/package.go
diff -u pkgsrc/pkgtools/pkglint/files/package.go:1.19 pkgsrc/pkgtools/pkglint/files/package.go:1.20
--- pkgsrc/pkgtools/pkglint/files/package.go:1.19       Sun Oct  8 22:31:13 2017
+++ pkgsrc/pkgtools/pkglint/files/package.go    Mon Jan  1 18:04:15 2018
@@ -2,7 +2,6 @@ package main
 
 import (
        "fmt"
-       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/pkgver"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
@@ -27,13 +26,13 @@ type Package struct {
        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.
+       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
 }
@@ -43,9 +42,9 @@ func NewPackage(pkgpath string) *Package
                Pkgpath:               pkgpath,
                vardef:                make(map[string]MkLine),
                varuse:                make(map[string]MkLine),
-               bl3:                   make(map[string]line.Line),
+               bl3:                   make(map[string]Line),
                plistSubstCond:        make(map[string]bool),
-               included:              make(map[string]line.Line),
+               included:              make(map[string]Line),
                loadTimeTools:         make(map[string]bool),
                conditionalIncludes:   make(map[string]MkLine),
                unconditionalIncludes: make(map[string]MkLine),
@@ -111,7 +110,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), pkgversion)
+                       mkline.Warnf("The package is being downgraded from %s (see %s) to %s", change.Version, change.Line.ReferenceFrom(mkline.Line), pkgversion)
                        Explain(
                                "The files in doc/CHANGES-*, in which all version changes are",
                                "recorded, have a higher version number than what the package says.",
@@ -280,10 +279,10 @@ func (pkg *Package) readMakefile(fname s
 
                if isMainMakefile {
                        mainLines.mklines = append(mainLines.mklines, mkline)
-                       mainLines.lines = append(mainLines.lines, mkline)
+                       mainLines.lines = append(mainLines.lines, mkline.Line)
                }
                allLines.mklines = append(allLines.mklines, mkline)
-               allLines.lines = append(allLines.lines, mkline)
+               allLines.lines = append(allLines.lines, mkline.Line)
 
                var includeFile, incDir, incBase string
                if mkline.IsInclude() {
@@ -301,7 +300,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] = mkline
+                                       G.Pkg.bl3[bl3File] = mkline.Line
                                        if trace.Tracing {
                                                trace.Step1("Buildlink3 file in package: %q", bl3File)
                                        }
@@ -310,7 +309,7 @@ func (pkg *Package) readMakefile(fname s
                }
 
                if includeFile != "" && G.Pkg.included[includeFile] == nil {
-                       G.Pkg.included[includeFile] = mkline
+                       G.Pkg.included[includeFile] = mkline.Line
 
                        if matches(includeFile, `^\.\./[^./][^/]*/[^/]+`) {
                                mkline.Warnf("References to other packages should look like \"../../category/package\", not \"../package\".")
@@ -396,7 +395,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))
+               perlLine.Warnf("REPLACE_PERL is ignored when NO_CONFIGURE is set (in %s)", noconfLine.ReferenceFrom(perlLine.Line))
        }
 
        if vardef["LICENSE"] == nil && vardef["META_PACKAGE"] == nil {
@@ -411,7 +410,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.ReferenceFrom(gnuLine))
+                               useLine.ReferenceFrom(gnuLine.Line))
                }
        }
 
@@ -423,8 +422,8 @@ func (pkg *Package) checkfilePackageMake
        }
 
        if imake, x11 := vardef["USE_IMAKE"], vardef["USE_X11"]; imake != nil && x11 != nil {
-               if !hasSuffix(x11.Filename(), "/mk/x11.buildlink3.mk") {
-                       imake.Notef("USE_IMAKE makes USE_X11 in %s superfluous.", x11.ReferenceFrom(imake))
+               if !hasSuffix(x11.Filename, "/mk/x11.buildlink3.mk") {
+                       imake.Notef("USE_IMAKE makes USE_X11 in %s superfluous.", x11.ReferenceFrom(imake.Line))
                }
        }
 
@@ -694,7 +693,7 @@ func (pkg *Package) ChecklinesPackageMak
        for lineno < len(mklines.lines) {
                mkline := mklines.mklines[lineno]
                line := mklines.lines[lineno]
-               text := line.Text()
+               text := line.Text
 
                if trace.Tracing {
                        trace.Stepf("[varorder] section %d variable %d vars %v", sectindex, varindex, vars)
@@ -786,13 +785,13 @@ func (mklines *MkLines) checkForUsedComm
 
        expected := "# used by " + relativeName
        for _, line := range lines {
-               if line.Text() == expected {
+               if line.Text == expected {
                        return
                }
        }
 
        i := 0
-       for i < 2 && hasPrefix(lines[i].Text(), "#") {
+       for i < 2 && hasPrefix(lines[i].Text, "#") {
                i++
        }
 
@@ -863,20 +862,20 @@ func (pkg *Package) CheckInclude(mkline 
                mkline.SetConditionVars(conditionVars)
        }
 
-       if path.Dir(abspath(mkline.Filename())) == abspath(G.CurrentDir) {
+       if path.Dir(abspath(mkline.Filename)) == abspath(G.CurrentDir) {
                includefile := mkline.Includefile()
 
                if indentation.IsConditional() {
                        pkg.conditionalIncludes[includefile] = mkline
                        if other := pkg.unconditionalIncludes[includefile]; other != nil {
                                mkline.Warnf("%q is included conditionally here (depending on %s) and unconditionally in %s.",
-                                       cleanpath(includefile), mkline.ConditionVars(), other.ReferenceFrom(mkline))
+                                       cleanpath(includefile), mkline.ConditionVars(), other.ReferenceFrom(mkline.Line))
                        }
                } else {
                        pkg.unconditionalIncludes[includefile] = mkline
                        if other := pkg.conditionalIncludes[includefile]; other != nil {
                                mkline.Warnf("%q is included unconditionally here and conditionally in %s (depending on %s).",
-                                       cleanpath(includefile), other.ReferenceFrom(mkline), other.ConditionVars())
+                                       cleanpath(includefile), other.ReferenceFrom(mkline.Line), other.ConditionVars())
                        }
                }
        }

Index: pkgsrc/pkgtools/pkglint/files/patches.go
diff -u pkgsrc/pkgtools/pkglint/files/patches.go:1.15 pkgsrc/pkgtools/pkglint/files/patches.go:1.16
--- pkgsrc/pkgtools/pkglint/files/patches.go:1.15       Sun Oct  8 22:31:13 2017
+++ pkgsrc/pkgtools/pkglint/files/patches.go    Mon Jan  1 18:04:15 2018
@@ -3,25 +3,22 @@ package main
 // Checks for patch files.
 
 import (
-       "netbsd.org/pkglint/line"
-       "netbsd.org/pkglint/linechecks"
-       "netbsd.org/pkglint/textproc"
        "netbsd.org/pkglint/trace"
        "path"
        "strings"
 )
 
-func ChecklinesPatch(lines []line.Line) {
+func ChecklinesPatch(lines []Line) {
        if trace.Tracing {
-               defer trace.Call1(lines[0].Filename())()
+               defer trace.Call1(lines[0].Filename)()
        }
 
-       (&PatchChecker{lines, textproc.NewExpecter(lines), false, false}).Check()
+       (&PatchChecker{lines, NewExpecter(lines), false, false}).Check()
 }
 
 type PatchChecker struct {
-       lines             []line.Line
-       exp               *textproc.Expecter
+       lines             []Line
+       exp               *Expecter
        seenDocumentation bool
        previousLineEmpty bool
 }
@@ -37,7 +34,7 @@ func (ck *PatchChecker) Check() {
                defer trace.Call0()()
        }
 
-       if linechecks.CheckRcsid(ck.lines[0], ``, "") {
+       if CheckLineRcsid(ck.lines[0], ``, "") {
                ck.exp.Advance()
        }
        ck.previousLineEmpty = ck.exp.ExpectEmptyLine(G.opts.WarnSpace)
@@ -80,16 +77,16 @@ func (ck *PatchChecker) Check() {
                }
 
                ck.exp.Advance()
-               ck.previousLineEmpty = ck.isEmptyLine(line.Text())
+               ck.previousLineEmpty = ck.isEmptyLine(line.Text)
                if !ck.previousLineEmpty {
                        ck.seenDocumentation = true
                }
        }
 
        if patchedFiles > 1 {
-               NewLineWhole(ck.lines[0].Filename()).Warnf("Contains patches for %d files, should be only one.", patchedFiles)
+               NewLineWhole(ck.lines[0].Filename).Warnf("Contains patches for %d files, should be only one.", patchedFiles)
        } else if patchedFiles == 0 {
-               NewLineWhole(ck.lines[0].Filename()).Errorf("Contains no patch.")
+               NewLineWhole(ck.lines[0].Filename).Errorf("Contains no patch.")
        }
 
        ChecklinesTrailingEmptyLines(ck.lines)
@@ -117,10 +114,10 @@ func (ck *PatchChecker) checkUnifiedDiff
                }
                ck.checktextUniHunkCr()
 
-               for linesToDel > 0 || linesToAdd > 0 || hasPrefix(ck.exp.CurrentLine().Text(), "\\") {
+               for linesToDel > 0 || linesToAdd > 0 || hasPrefix(ck.exp.CurrentLine().Text, "\\") {
                        line := ck.exp.CurrentLine()
                        ck.exp.Advance()
-                       text := line.Text()
+                       text := line.Text
                        switch {
                        case text == "":
                                linesToDel--
@@ -147,7 +144,7 @@ func (ck *PatchChecker) checkUnifiedDiff
        }
        if !ck.exp.EOF() {
                line := ck.exp.CurrentLine()
-               if !ck.isEmptyLine(line.Text()) && !matches(line.Text(), rePatchUniFileDel) {
+               if !ck.isEmptyLine(line.Text) && !matches(line.Text, rePatchUniFileDel) {
                        line.Warnf("Empty line or end of file expected.")
                        Explain(
                                "This empty line makes the end of the patch clearly visible.",
@@ -157,7 +154,7 @@ func (ck *PatchChecker) checkUnifiedDiff
        }
 }
 
-func (ck *PatchChecker) checkBeginDiff(line line.Line, patchedFiles int) {
+func (ck *PatchChecker) checkBeginDiff(line Line, patchedFiles int) {
        if trace.Tracing {
                defer trace.Call0()()
        }
@@ -231,7 +228,7 @@ func (ck *PatchChecker) checktextUniHunk
        }
 
        line := ck.exp.PreviousLine()
-       if hasSuffix(line.Text(), "\r") {
+       if hasSuffix(line.Text, "\r") {
                if !line.AutofixReplace("\r\n", "\n") {
                        line.Errorf("The hunk header must not end with a CR character.")
                        Explain(
@@ -286,7 +283,7 @@ func (ft FileType) String() string {
 }
 
 // This is used to select the proper subroutine for detecting absolute pathnames.
-func guessFileType(line line.Line, fname string) (fileType FileType) {
+func guessFileType(line Line, fname string) (fileType FileType) {
        if trace.Tracing {
                defer trace.Call(fname, "=>", &fileType)()
        }
@@ -320,7 +317,7 @@ func guessFileType(line line.Line, fname
 }
 
 // Looks for strings like "/dev/cd0" appearing in source code
-func checklineSourceAbsolutePathname(line line.Line, text string) {
+func checklineSourceAbsolutePathname(line Line, text string) {
        if !strings.ContainsAny(text, "\"'") {
                return
        }
@@ -337,12 +334,12 @@ func checklineSourceAbsolutePathname(lin
                        // ok; Python example: libdir = prefix + '/lib'
 
                default:
-                       linechecks.CheckwordAbsolutePathname(line, str)
+                       CheckwordAbsolutePathname(line, str)
                }
        }
 }
 
-func checklineOtherAbsolutePathname(line line.Line, text string) {
+func checklineOtherAbsolutePathname(line Line, text string) {
        if trace.Tracing {
                defer trace.Call1(text)()
        }
@@ -362,7 +359,7 @@ func checklineOtherAbsolutePathname(line
                        if trace.Tracing {
                                trace.Step1("before=%q", before)
                        }
-                       linechecks.CheckwordAbsolutePathname(line, path)
+                       CheckwordAbsolutePathname(line, path)
                }
        }
 }
Index: pkgsrc/pkgtools/pkglint/files/util.go
diff -u pkgsrc/pkgtools/pkglint/files/util.go:1.15 pkgsrc/pkgtools/pkglint/files/util.go:1.16
--- pkgsrc/pkgtools/pkglint/files/util.go:1.15  Sun Oct  8 22:31:13 2017
+++ pkgsrc/pkgtools/pkglint/files/util.go       Mon Jan  1 18:04:15 2018
@@ -3,7 +3,6 @@ package main
 import (
        "fmt"
        "io/ioutil"
-       "netbsd.org/pkglint/line"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
        "os"
@@ -101,7 +100,7 @@ func isCommitted(fname string) bool {
        lines := loadCvsEntries(fname)
        needle := "/" + path.Base(fname) + "/"
        for _, line := range lines {
-               if hasPrefix(line.Text(), needle) {
+               if hasPrefix(line.Text, needle) {
                        return true
                }
        }
@@ -112,8 +111,8 @@ func isLocallyModified(fname string) boo
        lines := loadCvsEntries(fname)
        needle := "/" + path.Base(fname) + "/"
        for _, line := range lines {
-               if hasPrefix(line.Text(), needle) {
-                       cvsModTime, err := time.Parse(time.ANSIC, strings.Split(line.Text(), "/")[3])
+               if hasPrefix(line.Text, needle) {
+                       cvsModTime, err := time.Parse(time.ANSIC, strings.Split(line.Text, "/")[3])
                        if err != nil {
                                return false
                        }
@@ -134,7 +133,7 @@ func isLocallyModified(fname string) boo
        return false
 }
 
-func loadCvsEntries(fname string) []line.Line {
+func loadCvsEntries(fname string) []Line {
        dir := path.Dir(fname)
        if dir == G.CvsEntriesDir {
                return G.CvsEntriesLines

Index: pkgsrc/pkgtools/pkglint/files/shell.go
diff -u pkgsrc/pkgtools/pkglint/files/shell.go:1.17 pkgsrc/pkgtools/pkglint/files/shell.go:1.18
--- pkgsrc/pkgtools/pkglint/files/shell.go:1.17 Sun Oct  8 22:31:13 2017
+++ pkgsrc/pkgtools/pkglint/files/shell.go      Mon Jan  1 18:04:15 2018
@@ -3,8 +3,6 @@ package main
 // Parsing and checking shell commands embedded in Makefiles
 
 import (
-       "netbsd.org/pkglint/line"
-       "netbsd.org/pkglint/linechecks"
        "netbsd.org/pkglint/textproc"
        "netbsd.org/pkglint/trace"
        "path"
@@ -38,7 +36,7 @@ func (shline *ShellLine) CheckWord(token
                return
        }
 
-       var line line.Line = shline.mkline
+       var line = shline.mkline.Line
 
        p := NewMkParser(line, token, false)
        if varuse := p.VarUse(); varuse != nil && p.EOF() {
@@ -225,7 +223,7 @@ func (shline *ShellLine) unescapeBacktic
                defer trace.Call(shellword, quoting, "=>", trace.Ref(&unescaped))()
        }
 
-       var line line.Line = shline.mkline
+       line := shline.mkline.Line
        for !repl.EOF() {
                switch {
                case repl.AdvanceStr("`"):
@@ -277,7 +275,7 @@ func (shline *ShellLine) CheckShellComma
                defer trace.Call1(shelltext)()
        }
 
-       var line line.Line = shline.mkline
+       line := shline.mkline.Line
 
        if contains(shelltext, "${SED}") && contains(shelltext, "${MV}") {
                line.Notef("Please use the SUBST framework instead of ${SED} and ${MV}.")
@@ -326,7 +324,7 @@ func (shline *ShellLine) CheckShellComma
                defer trace.Call()()
        }
 
-       var line line.Line = shline.mkline
+       line := shline.mkline.Line
        program, err := parseShellProgram(line, shellcmd)
        if err != nil && contains(shellcmd, "$$(") { // Hack until the shell parser can handle subshells.
                line.Warnf("Invoking subshells via $(...) is not portable enough.")
@@ -387,7 +385,7 @@ func (shline *ShellLine) checkHiddenAndS
                // Shell comments may be hidden, since they cannot have side effects.
 
        default:
-               tokens, _ := splitIntoShellTokens(shline.mkline, rest)
+               tokens, _ := splitIntoShellTokens(shline.mkline.Line, rest)
                if len(tokens) > 0 {
                        cmd := tokens[0]
                        switch cmd {
@@ -597,7 +595,7 @@ func (scc *SimpleCommandChecker) checkAb
        isSubst := false
        for _, arg := range scc.strcmd.Args {
                if !isSubst {
-                       linechecks.CheckAbsolutePathname(scc.shline.mkline, arg)
+                       CheckLineAbsolutePathname(scc.shline.mkline.Line, arg)
                }
                if false && isSubst && !matches(arg, `"^[\"\'].*[\"\']$`) {
                        scc.shline.mkline.Warnf("Substitution commands like %q should always be quoted.", arg)
@@ -764,7 +762,7 @@ func (spc *ShellProgramChecker) checkWor
        spc.shline.CheckWord(word.MkText, checkQuoting)
 }
 
-func (scc *ShellProgramChecker) checkPipeExitcode(line line.Line, pipeline *MkShPipeline) {
+func (scc *ShellProgramChecker) checkPipeExitcode(line Line, pipeline *MkShPipeline) {
        if trace.Tracing {
                defer trace.Call()()
        }
@@ -815,7 +813,7 @@ func (shline *ShellLine) checkCommandUse
                return
        }
 
-       var line line.Line = shline.mkline
+       line := shline.mkline.Line
        switch shellcmd {
        case "${INSTALL}",
                "${INSTALL_DATA}", "${INSTALL_DATA_DIR}",
@@ -850,7 +848,7 @@ func (shline *ShellLine) checkCommandUse
 }
 
 // Example: "word1 word2;;;" => "word1", "word2", ";;", ";"
-func splitIntoShellTokens(line line.Line, text string) (tokens []string, rest string) {
+func splitIntoShellTokens(line Line, text string) (tokens []string, rest string) {
        if trace.Tracing {
                defer trace.Call(line, text)()
        }
@@ -882,7 +880,7 @@ func splitIntoShellTokens(line line.Line
 
 // Example: "word1 word2;;;" => "word1", "word2;;;"
 // Compare devel/bmake/files/str.c, function brk_string.
-func splitIntoMkWords(line line.Line, text string) (words []string, rest string) {
+func splitIntoMkWords(line Line, text string) (words []string, rest string) {
        if trace.Tracing {
                defer trace.Call(line, text)()
        }

Index: pkgsrc/pkgtools/pkglint/files/vardefs.go
diff -u pkgsrc/pkgtools/pkglint/files/vardefs.go:1.31 pkgsrc/pkgtools/pkglint/files/vardefs.go:1.32
--- pkgsrc/pkgtools/pkglint/files/vardefs.go:1.31       Mon Jan  1 10:23:04 2018
+++ pkgsrc/pkgtools/pkglint/files/vardefs.go    Mon Jan  1 18:04:15 2018
@@ -428,6 +428,9 @@ func (gd *GlobalData) InitVartypes() {
        pkglist("CHECK_PERMS_SKIP", lkShell, BtPathmask)
        usr("CHECK_PORTABILITY", lkNone, BtYesNo)
        pkglist("CHECK_PORTABILITY_SKIP", lkShell, BtPathmask)
+       usr("CHECK_RELRO", lkNone, BtYesNo)
+       pkglist("CHECK_RELRO_SKIP", lkShell, BtPathmask)
+       pkg("CHECK_RELRO_SUPPORTED", lkNone, BtYesNo)
        acl("CHECK_SHLIBS", lkNone, BtYesNo, "Makefile: set")
        pkglist("CHECK_SHLIBS_SKIP", lkShell, BtPathmask)
        acl("CHECK_SHLIBS_SUPPORTED", lkNone, BtYesNo, "Makefile: set")

Index: pkgsrc/pkgtools/pkglint/files/vartypecheck.go
diff -u pkgsrc/pkgtools/pkglint/files/vartypecheck.go:1.26 pkgsrc/pkgtools/pkglint/files/vartypecheck.go:1.27
--- pkgsrc/pkgtools/pkglint/files/vartypecheck.go:1.26  Sun Oct  8 22:31:13 2017
+++ pkgsrc/pkgtools/pkglint/files/vartypecheck.go       Mon Jan  1 18:04:15 2018
@@ -1,8 +1,6 @@
 package main
 
 import (
-       "netbsd.org/pkglint/line"
-       "netbsd.org/pkglint/linechecks"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
        "path"
@@ -12,7 +10,7 @@ import (
 
 type VartypeCheck struct {
        MkLine     MkLine
-       Line       line.Line
+       Line       Line
        Varname    string
        Op         MkOperator
        Value      string
@@ -211,7 +209,7 @@ func (cv *VartypeCheck) Comment() {
 }
 
 func (cv *VartypeCheck) ConfFiles() {
-       words, _ := splitIntoMkWords(cv.MkLine, cv.Value)
+       words, _ := splitIntoMkWords(cv.MkLine.Line, cv.Value)
        if len(words)%2 != 0 {
                cv.Line.Warnf("Values for %s should always be pairs of paths.", cv.Varname)
        }
@@ -677,7 +675,7 @@ func (cv *VartypeCheck) Pathmask() {
        if !matches(cv.ValueNoVar, `^[#\-0-9A-Za-z._~+%*?/\[\]]*`) {
                cv.Line.Warnf("%q is not a valid pathname mask.", cv.Value)
        }
-       linechecks.CheckAbsolutePathname(cv.Line, cv.Value)
+       CheckLineAbsolutePathname(cv.Line, cv.Value)
 }
 
 // Like Filename, but including slashes
@@ -689,7 +687,7 @@ func (cv *VartypeCheck) Pathname() {
        if !matches(cv.ValueNoVar, `^[#\-0-9A-Za-z._~+%/]*$`) {
                cv.Line.Warnf("%q is not a valid pathname.", cv.Value)
        }
-       linechecks.CheckAbsolutePathname(cv.Line, cv.Value)
+       CheckLineAbsolutePathname(cv.Line, cv.Value)
 }
 
 func (cv *VartypeCheck) Perl5Packlist() {
@@ -737,7 +735,7 @@ func (cv *VartypeCheck) PkgRevision() {
        if !matches(cv.Value, `^[1-9]\d*$`) {
                cv.Line.Warnf("%s must be a positive integer number.", cv.Varname)
        }
-       if path.Base(cv.Line.Filename()) != "Makefile" {
+       if path.Base(cv.Line.Filename) != "Makefile" {
                cv.Line.Errorf("%s only makes sense directly in the package Makefile.", cv.Varname)
                Explain(
                        "Usually, different packages using the same Makefile.common have",
@@ -852,7 +850,7 @@ func (cv *VartypeCheck) SedCommands() {
 
        tokens, rest := splitIntoShellTokens(line, cv.Value)
        if rest != "" {
-               if strings.Contains(line.Text(), "#") {
+               if strings.Contains(line.Text, "#") {
                        line.Errorf("Invalid shell words %q in sed commands.", rest)
                        Explain(
                                "When sed commands have embedded \"#\" characters, they need to be",

Index: pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go
diff -u pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go:1.18 pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go:1.19
--- pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go:1.18     Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go  Mon Jan  1 18:04:15 2018
@@ -537,7 +537,7 @@ 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, mkline.Varname(), mkline.Op(), mkline.Value(), valueNovar, "", false}
+               vc := &VartypeCheck{mkline, mkline.Line, mkline.Varname(), mkline.Op(), mkline.Value(), valueNovar, "", false}
                checker(vc)
        }
 }
@@ -547,7 +547,7 @@ func runVartypeMatchChecks(varname strin
                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, varname, opUseMatch, value, valueNovar, "", false}
+               vc := &VartypeCheck{mkline, mkline.Line, varname, opUseMatch, value, valueNovar, "", false}
                checker(vc)
        }
 }
@@ -556,7 +556,7 @@ func runVartypeChecksFname(fname, varnam
        for i, value := range values {
                mkline := NewMkLine(NewLine(fname, i+1, varname+op.String()+value, nil))
                valueNovar := mkline.WithoutMakeVariables(value)
-               vc := &VartypeCheck{mkline, mkline, varname, op, value, valueNovar, "", false}
+               vc := &VartypeCheck{mkline, mkline.Line, varname, op, value, valueNovar, "", false}
                checker(vc)
        }
 }

Index: pkgsrc/pkgtools/pkglint/files/textproc/prefixreplacer.go
diff -u pkgsrc/pkgtools/pkglint/files/textproc/prefixreplacer.go:1.2 pkgsrc/pkgtools/pkglint/files/textproc/prefixreplacer.go:1.3
--- pkgsrc/pkgtools/pkglint/files/textproc/prefixreplacer.go:1.2        Sun Oct  8 22:31:13 2017
+++ pkgsrc/pkgtools/pkglint/files/textproc/prefixreplacer.go    Mon Jan  1 18:04:16 2018
@@ -127,6 +127,7 @@ func (pr *PrefixReplacer) SkipSpace() {
        pr.rest = strings.TrimLeft(pr.rest, " \t")
 }
 
+// Since returns the substring between the mark and the current position.
 func (pr *PrefixReplacer) Since(mark PrefixReplacerMark) string {
        return string(mark[:len(mark)-len(pr.rest)])
 }

Added files:

Index: pkgsrc/pkgtools/pkglint/files/expecter.go
diff -u /dev/null pkgsrc/pkgtools/pkglint/files/expecter.go:1.9
--- /dev/null   Mon Jan  1 18:04:16 2018
+++ pkgsrc/pkgtools/pkglint/files/expecter.go   Mon Jan  1 18:04:15 2018
@@ -0,0 +1,111 @@
+package main
+
+import (
+       "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
+       index int
+       m     []string
+}
+
+func NewExpecter(lines []Line) *Expecter {
+       return &Expecter{lines, 0, nil}
+}
+
+func (exp *Expecter) CurrentLine() Line {
+       if exp.index < len(exp.lines) {
+               return exp.lines[exp.index]
+       }
+
+       return NewLineEOF(exp.lines[0].Filename)
+}
+
+func (exp *Expecter) PreviousLine() 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.Pattern) 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
+}

Index: pkgsrc/pkgtools/pkglint/files/linechecker.go
diff -u /dev/null pkgsrc/pkgtools/pkglint/files/linechecker.go:1.4
--- /dev/null   Mon Jan  1 18:04:16 2018
+++ pkgsrc/pkgtools/pkglint/files/linechecker.go        Mon Jan  1 18:04:15 2018
@@ -0,0 +1,106 @@
+package main
+
+import (
+       "fmt"
+       "netbsd.org/pkglint/regex"
+       "netbsd.org/pkglint/trace"
+       "strings"
+)
+
+func CheckLineAbsolutePathname(line Line, text string) {
+       if trace.Tracing {
+               defer trace.Call1(text)()
+       }
+
+       // In the GNU coding standards, DESTDIR is defined as a (usually
+       // empty) prefix that can be used to install files to a different
+       // location from what they have been built for. Therefore
+       // everything following it is considered an absolute pathname.
+       //
+       // Another context where absolute pathnames usually appear is in
+       // assignments like "bindir=/bin".
+       if m, path := regex.Match1(text, `(?:^|\$[{(]DESTDIR[)}]|[\w_]+\s*=\s*)(/(?:[^"'\s]|"[^"*]"|'[^']*')*)`); m {
+               if regex.Matches(path, `^/\w`) {
+                       CheckwordAbsolutePathname(line, path)
+               }
+       }
+}
+
+func CheckLineLength(line Line, maxlength int) {
+       if len(line.Text) > maxlength {
+               line.Warnf("Line too long (should be no more than %d characters).", maxlength)
+               Explain(
+                       "Back in the old time, terminals with 80x25 characters were common.",
+                       "And this is still the default size of many terminal emulators.",
+                       "Moderately short lines also make reading easier.")
+       }
+}
+
+func CheckLineValidCharacters(line Line, reChar regex.Pattern) {
+       rest := regex.Compile(reChar).ReplaceAllString(line.Text, "")
+       if rest != "" {
+               uni := ""
+               for _, c := range rest {
+                       uni += fmt.Sprintf(" %U", c)
+               }
+               line.Warnf("Line contains invalid characters (%s).", uni[1:])
+       }
+}
+
+func CheckLineTrailingWhitespace(line Line) {
+       if strings.HasSuffix(line.Text, " ") || strings.HasSuffix(line.Text, "\t") {
+               if !line.AutofixReplaceRegexp(`\s+\n$`, "\n") {
+                       line.Notef("Trailing white-space.")
+                       Explain(
+                               "When a line ends with some white-space, that space is in most cases",
+                               "irrelevant and can be removed.")
+               }
+       }
+}
+
+func CheckLineRcsid(line Line, prefixRe regex.Pattern, suggestedPrefix string) bool {
+       if trace.Tracing {
+               defer trace.Call(prefixRe, suggestedPrefix)()
+       }
+
+       if regex.Matches(line.Text, `^`+prefixRe+`\$`+`NetBSD(?::[^\$]+)?\$$`) {
+               return true
+       }
+
+       if !line.AutofixInsertBefore(suggestedPrefix + "$" + "NetBSD$") {
+               line.Errorf("Expected %q.", suggestedPrefix+"$"+"NetBSD$")
+               Explain(
+                       "Several files in pkgsrc must contain the CVS Id, so that their",
+                       "current version can be traced back later from a binary package.",
+                       "This is to ensure reproducible builds, for example for finding bugs.")
+       }
+       return false
+}
+
+func CheckwordAbsolutePathname(line Line, word string) {
+       if trace.Tracing {
+               defer trace.Call1(word)()
+       }
+
+       switch {
+       case regex.Matches(word, `^/dev/(?:null|tty|zero)$`):
+       // These are defined by POSIX.
+       case word == "/bin/sh":
+       // This is usually correct, although on Solaris, it's pretty feature-crippled.
+       case regex.Matches(word, `^/s\W`):
+       // Probably a sed(1) command
+       case regex.Matches(word, `^/(?:[a-z]|\$[({])`):
+               // Absolute paths probably start with a lowercase letter.
+               line.Warnf("Found absolute pathname: %s", word)
+               Explain(
+                       "Absolute pathnames are often an indicator for unportable code.  As",
+                       "pkgsrc aims to be a portable system, absolute pathnames should be",
+                       "avoided whenever possible.",
+                       "",
+                       "A special variable in this context is ${DESTDIR}, which is used in",
+                       "GNU projects to specify a different directory for installation than",
+                       "what the programs see later when they are executed.  Usually it is",
+                       "empty, so if anything after that variable starts with a slash, it is",
+                       "considered an absolute pathname.")
+       }
+}
Index: pkgsrc/pkgtools/pkglint/files/linechecker_test.go
diff -u /dev/null pkgsrc/pkgtools/pkglint/files/linechecker_test.go:1.4
--- /dev/null   Mon Jan  1 18:04:16 2018
+++ pkgsrc/pkgtools/pkglint/files/linechecker_test.go   Mon Jan  1 18:04:15 2018
@@ -0,0 +1,45 @@
+package main
+
+import (
+       "gopkg.in/check.v1"
+)
+
+func (s *Suite) Test_LineChecker_CheckAbsolutePathname(c *check.C) {
+       s.Init(c)
+       line := NewLine("Makefile", 1, "# dummy", nil)
+
+       CheckLineAbsolutePathname(line, "bindir=/bin")
+       CheckLineAbsolutePathname(line, "bindir=/../lib")
+
+       s.CheckOutputLines(
+               "WARN: Makefile:1: Found absolute pathname: /bin")
+}
+
+func (s *Suite) Test_LineChecker_CheckTrailingWhitespace(c *check.C) {
+       s.Init(c)
+       line := NewLine("Makefile", 32, "The line must go on   ", nil)
+
+       CheckLineTrailingWhitespace(line)
+
+       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$",
+               "$"+"Id: dummy $",
+               "$"+"Id$",
+               "$"+"FreeBSD$")
+
+       for _, line := range lines {
+               CheckLineRcsid(line, ``, "")
+       }
+
+       s.CheckOutputLines(
+               "ERROR: fname:3: Expected \"$"+"NetBSD$\".",
+               "ERROR: fname:4: Expected \"$"+"NetBSD$\".",
+               "ERROR: fname:5: Expected \"$"+"NetBSD$\".")
+}



Home | Main Index | Thread Index | Old Index