This file is indexed.

/usr/games/pgnfix is in scid 1:4.6.4+dfsg1-2.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
#!/usr/bin/env python

# pgnfix, by John Wiegley <johnw@gnu.org>
# version 1.2, 2001.08.28
#
# This script will take a PGN file (typically gigantic), and perform
# as many normalizations and spelling corrections on the player's
# names as possible.  If there is embedded rating information in the
# player's name, it will be extracted and moved to the correct field.
# If you have a scid spelling.ssp file, spelling corrections will also
# take place.  It will even extract dates that have been mistakenly
# put in the Site or Event field, and move them to the Date field.

import sys
import string
import re

if len(sys.argv) < 2:
    sys.stderr.write("usage: pgnfix file.pgn [spelling.ssp]\n")
    sys.stderr.write("pgnfix cleans up a PGN file, writing clean games\n")
    sys.stderr.write("to stdout and games with errors to stderr.\n")
    sys.exit(1)

# If a field matches one of these values, discard the field altogether
bogus = {
    "Round": "[?-]",
    "Date":  "\?\?\?\?\.\?\?\.\?\?",
    "Site":  "\?",
    "Event": "\?",
}

# The preferred ordering for the known fields
order = [
    "Event",
    "Site",
    "Date",
    "Round",
    "White",
    "WhiteElo",
    "Black",
    "BlackElo",
    "TimeControl",
    "Result",
    "FEN",
    "ECO",
    "Opening",
    "Variation",
]

headers = {}
specials = {}

# Grab all the spelling names
spelling = {}

if len(sys.argv) == 3:
    spell = open(sys.argv[2], "r")
    in_player = 0
    while 1:
        line = spell.readline()
        if not line:
            break
        if re.match("@PLAYER", line):
            in_player = 1
        elif re.match("### END OF PLAYER SECTION", line):
            break
        elif in_player:
            match = re.match("^([A-Z][^,#]+)([^#]*)", line)
            if match:
                full = match.group(0)
                last, first = match.groups()
                first = string.strip(first)
                full  = string.strip(full)
                last  = string.strip(last)
                if first:
                    for name in (full, last,
                                 last + " " + first,
                                 last + ", " + first[0],
                                 last + " " + first[0]):
                        name = string.lower(name)
                        if spelling.has_key(name):
                            del spelling[name]
                        else:
                            spelling[name] = full

fd = open(sys.argv[1], "r")
current = []
bad_lines = []
in_body = 0
error = 0

while 1:
    line = fd.readline()
    if not line:
        break

    if not in_body and re.match("\s*$", line):
        in_body = 1

    if in_body:
        if line[0] == '[':
            in_body = 0
            # We've seen a header line; output whichever game was seen
            # last
            if current:
                out = sys.stdout
                if error:
                    out = sys.stderr
                    error = 0
                out.write(string.join(current, ""))
                current = []
                bad_lines = []
        else:
            if headers:
                for field, value in specials.items():
                    if not headers.has_key(field):
                        headers[field] = value
                for field in order:
                    if headers.has_key(field):
                        current.append('[%s "%s"]\n' % (field, headers[field]))
                        del headers[field]
                for field, value in headers.items():
                    current.append('[%s "%s"]\n' % (field, value))
                current.extend(bad_lines)
                headers = {}
                specials = {}
            current.append(line)
            continue

    # See whether we have a broken header line
    if line[0] == '[' and line[-2] != ']':
        next = fd.readline()
        if line[0] != '[' and line[-2] == ']':
            line = line[:-1] + next
        else:
            # Just skip both
            error = 1
            bad_lines.append(line)
            bad_lines.append(next)
            continue

    match = re.match('\[(\S+)\s+"(.*)"\]', line)
    if not match:
        error = 1
        bad_lines.append(line)
        continue

    field, value = match.groups()
    if value:
        if field in ("Event", "Site"):
            match = re.search("\(?([0-9]{4})\.([0-9]+)\.([0-9]+)\)?", value)
            if match:
                year = int(match.group(3))
                month = int(match.group(2))
                day = int(match.group(1))
                specials["Date"] = "%04d.%02d.%02d" % (year, month, day)
                value = re.sub("\(?([0-9]{4})\.([0-9]+)\.([0-9]+)\)?",
                               "", value)
            match = re.search("\(?([0-9]+)/([0-9]+)/([0-9]+)\)?", value)
            if match:
                year = int(match.group(3))
                day = int(match.group(2))
                month = int(match.group(1))
                if month > 12:
                    t = day
                    day = month
                    month = t
                if year < 100 and year > 20:
                    year = 1900 + year
                if year < 10:
                    year = 2000 + year
                specials["Date"] = "%04d.%02d.%02d" % (year, month, day)
                value = re.sub("\(?([0-9]+)/([0-9]+)/([0-9]+)\)?", "", value)

        value = string.strip(value)

        if field in ("White", "Black"):
            name = re.sub("[MW][0-9]{5}", "", value)

            # Extract any embedded Elo rating
            match = re.search("(^|[, {(])([1-9][0-9]{3})($|[, })])", name)
            if match:
                specials[field + "Elo"] = match.group(2)
                name = re.sub("(^|[ {(])([1-9][0-9]{3})($|[ })])", "", name)

            name = re.sub("(.+?),\s*(.+?)&", "\\2 & \\1", name)

            if not re.search("[A-Z]{4}", name):
                match = re.search("[-A-Za-z.'` _]+"
                                  "(,\s*[-A-Za-z.'` _]+)?(\s*[1-3])?", name)
                if match:
                    name = match.group(0)
                    name = re.sub("_", " ", name)
                    name = re.sub("\.", "", name)
                    name = re.sub("([A-Za-z])([0-9])", "\\1 \\2", name)
                    name = string.strip(name)
                    name = re.sub("^([A-Z]+?)\s*([A-Z][a-z].+)", "\\2, \\1",
                                  name)

                name = re.sub(",\s*([GI]M)?$", "", name)

            name = string.strip(name)
            t = string.lower(name)

            if spelling.has_key(t):
                name = spelling[t]

            headers[field] = name

        elif not bogus.has_key(field) or not re.search(bogus[field], value):
            headers[field] = value

if current:
    out = sys.stdout
    if error:
        out = sys.stderr
        error = 0
    out.write(string.join(current, ""))
    current = []
    bad_lines = []

fd.close()
print