fix(adif): one record, one line
An exported file was full of blank gaps: a record ran down a dozen lines and the next appeared to start in the middle of the page. ADDRESS is a multi-line field by the standard and callbooks and other loggers fill it that way — "Kabul", four blank lines, "Afghanistan" — and the writer copied the value out as it stood. The files were always valid, since ADIF counts bytes; they were unreadable, and so was anything that quoted them. Line breaks inside a value are now joined with a comma and tabs become spaces, which is how an address reads on one line anyway. The length prefix is computed after the flattening, so the record stays exact, and every path through the writer gets it: the file exports, the uploads and the record forwarded over UDP. The changelog's 0.27.15 block also takes back the FT-map hover fix, which landed after the 0.27.14 release commit and was sitting in that block.
This commit is contained in:
@@ -407,12 +407,41 @@ func writeRecord(bw *bufio.Writer, q qso.QSO, includeApp bool, allow map[string]
|
||||
// length is the byte count (ADIF spec), which matches len(v) in Go since v is
|
||||
// already a UTF-8 byte string.
|
||||
func writeField(bw *bufio.Writer, tag, v string) {
|
||||
v = oneLine(v)
|
||||
if v == "" {
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(bw, "<%s:%d>%s ", tag, len(v), v)
|
||||
}
|
||||
|
||||
// oneLine flattens a value onto a single line.
|
||||
//
|
||||
// ADIF counts bytes, so a value carrying line breaks is still read correctly —
|
||||
// and it turns the file into something nobody can read. ADDRESS is a multi-line
|
||||
// field by the standard, and callbooks and other loggers fill it that way: a
|
||||
// value of "Kabul" followed by four blank lines and "Afghanistan" came out of
|
||||
// OpsLog as one record spread down a dozen lines, with the next record
|
||||
// apparently starting in the middle of the page.
|
||||
//
|
||||
// The breaks are dropped rather than escaped: the parts are trimmed and joined
|
||||
// with a comma, which is how an address reads on one line anyway, and empty
|
||||
// fragments go. The length prefix is computed after this, so the record stays
|
||||
// exact.
|
||||
func oneLine(v string) string {
|
||||
if !strings.ContainsAny(v, "\r\n\t") {
|
||||
return v
|
||||
}
|
||||
parts := strings.FieldsFunc(v, func(r rune) bool { return r == '\r' || r == '\n' })
|
||||
out := make([]string, 0, len(parts))
|
||||
for _, part := range parts {
|
||||
part = strings.TrimSpace(strings.ReplaceAll(part, "\t", " "))
|
||||
if part != "" {
|
||||
out = append(out, part)
|
||||
}
|
||||
}
|
||||
return strings.Join(out, ", ")
|
||||
}
|
||||
|
||||
func writeIntPtr(bw *bufio.Writer, tag string, p *int) {
|
||||
if p == nil {
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user