# fixrecord.awk version 1.0 # Construct a new 'record' (nethack's high scores file) by # making a replacement file containing the corresponding # end-of-game records from 'logfile', which aren't subject # to the nethack 3.6.0 "while helpless" proliferation bug. # # Warning -- this does not attempt to lock out active games from # updating record or logfile or xlogfile while it is executing. # # usage: # 1) first, copy record to record.old # 2) next, run this awk script # awk -f fixrecord.awk record.old logfile >record.new # or # awk -f fixrecord.awk record.old xlogfile >record.new # 3) then, set file access permissions on record.new to match record's # 4) last, replace record with record.new # # More that one logfile and/or xlogfile may be specified. # Omitting them will yield an unaltered copy of record.old. # FNR==1 { # first record of current input file if (!Pass++) MinScore = 2147483647 # will be adjusted downwards else # determine whether we're using xlogfile rather than logfile X = index($1, "=") # test for version=1.2.3 } X { # every record from an xlogfile split($2, e, "=") # 2nd element is score=12345 if (e[2] < MinScore) next # skip entry with too-low score # convert a subset of an xlogfile record into a logfile record split($0, e, "[=\t]") # '=' within fields, \t between them # first 15 fields of logfile are straightforward; # 16th element of logfile is "name,death" and might have spaces; # 16th element of xlogfile is name=character_name; # 17th is death=death_reason; 18th might be while=helpless_reason R = ( e[2] " " e[4] " " e[6] " " e[8] " " e[10] " " \ e[12] " " e[14] " " e[16] " " e[18] " " e[20] " " \ e[22] " " e[24] " " e[26] " " e[28] " " e[30] " " \ e[32] "," e[34] ) if (e[35] == "while") R = (R ", while " e[36]) $0 = R } { # every record if ($2 < MinScore) { if (Pass > 1) next # skip logfile entry with too-low score else MinScore = $2 # Pass==1: remember record's lowest score } split($0, e, ",") # [1] most fields, [2] death, [3+] while* Entry = (e[1] "," e[2]) # first comma separates name and death if (Pass == 1) { indx[++RcrdCount] = Entry rcrd[Entry] = $0 } else { lgfl[Entry] = $0 } } END { # no more input for (i = 1; i <= RcrdCount; ++i) { Entry = indx[i] if (Entry in lgfl) print lgfl[Entry] else print rcrd[Entry] } } # # BUGS: # It is possible to have multiple logfile entries which are identical # up until different while-helpless explanations; matching score will # be replaced by the last one. [This circumstance is very unlikely.] # # An entry for a death by named monster which has a comma in its # name may result in a record that doesn't get repaired. But it will # remain intact and won't interfere with fixing the rest of the file. #