Documentation
¶
Overview ¶
Package adif implements a high performance ADIF library for Go. It provides types, structs and methods for managing ADIF Records. Idiomatic interfaces for reading and writing ADI formatted data make integration with other Go libraries fast and easy.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrAdiReaderMalformedADI is returned when the ADI formatted data does not conform to the ADIF specification. ErrAdiReaderMalformedADI = errors.New("adi reader: data is malformed") // ErrAdiReaderNilReader is returned when the reader passed to NewADIDocumentReader is nil. ErrAdiWriterNilWriter = errors.New("adi writer: nil writer") // ErrHeaderAlreadyWritten is returned when attempting to write more than one header record. ErrHeaderAlreadyWritten = errors.New("header record already written") )
Functions ¶
This section is empty.
Types ¶
type DocumentReader ¶
type DocumentReader interface {
// Next reads and returns the next Record.
// It returns io.EOF when no more records are available.
// isHeader indicates if the record is a header record.
Next() (record Record, isHeader bool, err error)
}
DocumentReader reads Amateur Data Interchange Format (ADIF) records sequentially.
func NewADIDocumentReader ¶
func NewADIDocumentReader(r io.Reader, skipHeader bool) DocumentReader
NewADIDocumentReader returns an ADIFReader that can parse ADIF *.adi formatted records. If skipHeader is true, Next() will not return the header record if it exists. This is a streaming parser that processes the input as it is read, using minimal memory.
Example ¶
// Example ADI data
adiData := `
<ADIF_VERS:5>3.1.0
<PROGRAMID:4>Test
<EOH>
<CALL:5>K9CTS<QSO_DATE:8>20230101<TIME_ON:4>1200<BAND:3>20m<MODE:3>ssb<eor>
<CALL:5>W9PVA<QSO_DATE:8>20230102<TIME_ON:4>1300<BAND:3>40m<MODE:2>cw<eor>
`
reader := NewADIDocumentReader(strings.NewReader(adiData), true)
record, _, err := reader.Next()
for err == nil {
fmt.Printf("Call: %s, Date: %s, Time: %s, Band: %s, Mode: %s\n",
record.Get(adifield.CALL),
record.Get(adifield.QSO_DATE),
record.Get(adifield.TIME_ON),
record.Get(adifield.BAND),
record.Get(adifield.MODE))
record, _, err = reader.Next()
}
if !errors.Is(err, io.EOF) {
panic(err)
}
Output: Call: K9CTS, Date: 20230101, Time: 1200, Band: 20m, Mode: ssb Call: W9PVA, Date: 20230102, Time: 1300, Band: 40m, Mode: cw
func NewJSONDocumentReader ¶
func NewJSONDocumentReader(r io.Reader, skipHeader bool) (DocumentReader, error)
NewJSONDocumentReader returns an ADIFDocumentReader that can parse ADIF records in ADIJ JSON format. If skipHeader is true, Next() will not return the header record if it exists.
Example ¶
jsonExample := `{
"HEADER": {
"CREATED_TIMESTAMP": "20250907 212700",
"PROGRAMID": "ExampleProgram",
"PROGRAMVERSION": "1.0"
},
"RECORDS": [
{
"BAND": "20m",
"CALL": "K9CTS",
"MODE": "ssb",
"QSO_DATE": "20250907",
"TIME_ON": "2127"
},
{
"BAND": "40m",
"CALL": "W9PVA",
"MODE": "cw",
"QSO_DATE": "20250907",
"TIME_ON": "2130"
}
]
}`
// Create a reader from the ADIJ data
reader, err := NewJSONDocumentReader(strings.NewReader(jsonExample), false)
if err != nil {
fmt.Printf("Error creating reader: %v\n", err)
return
}
record, isHeader, err := reader.Next()
for err == nil {
fmt.Printf("Is Header: %v\n", isHeader)
if isHeader {
fmt.Printf("created_timestamp: %s\n", record.Get(adifield.CREATED_TIMESTAMP))
} else {
fmt.Printf("call: %s, band: %s, mode: %s\n", record.Get(adifield.CALL), record.Get(adifield.BAND), record.Get(adifield.MODE))
}
fmt.Println()
record, isHeader, err = reader.Next()
}
if !errors.Is(err, io.EOF) {
panic(err)
}
Output: Is Header: true created_timestamp: 20250907 212700 Is Header: false call: K9CTS, band: 20m, mode: ssb Is Header: false call: W9PVA, band: 40m, mode: cw
type DocumentWriter ¶
type DocumentWriter interface {
// WriteHeader writes the ADIF header record to the output.
// It MUST be called before using WriteRecord.
// If WriteHeader is called more than once, it returns an error.
WriteHeader(record Record) error
// WriteRecord writes ADIF record(s) to the output.
// When writing a header record, it MUST be the first record written.
WriteRecord(record Record) error
// Flush writes buffered data to the underlying writer.
// IMPORTANT: This MUST be called once the header and records have been written to ensure all data is properly written.
Flush() error
}
DocumentWriter writes Amateur Data Interchange Format (ADIF) records sequentially.
func NewADIDocumentWriter ¶
func NewADIDocumentWriter(w io.Writer) DocumentWriter
NewADIDocumentWriter returns an ADIFDocumentWriter that can write ADIF *.adi formatted records.
Example ¶
ExampleNewADIDocumentWriter demonstrates how to write an ADI document using NewADIDocumentWriter.
var sb strings.Builder
writer := NewADIDocumentWriter(&sb)
hdr := NewRecord()
hdr.Set(adifield.CREATED_TIMESTAMP, "20250907 212700")
writer.WriteHeader(hdr)
qso := NewRecord()
qso.Set(adifield.CALL, "K9CTS")
qso.Set(adifield.BAND, band.BAND_20M.String())
qso.Set(adifield.MODE, mode.SSB.String())
qso.Set(adifield.New("APP_Example"), "Example")
writer.WriteRecord(qso)
if err := writer.Flush(); err != nil {
panic(err)
}
fmt.Println(sb.String())
Output: AM✠DG K9CTS High Performance ADIF Processing Library https://github.com/farmergreg/adif <CREATED_TIMESTAMP:15>20250907 212700<EOH> <BAND:3>20M<MODE:3>SSB<CALL:5>K9CTS<APP_EXAMPLE:7>Example<EOR>
func NewADIDocumentWriterWithPreamble ¶
func NewADIDocumentWriterWithPreamble(w io.Writer, adiPreamble string) DocumentWriter
NewADIDocumentWriterWithPreamble returns an ADIFDocumentWriter that can write ADIF *.adi formatted records with a custom preamble for header records.
func NewJSONDocumentWriter ¶
func NewJSONDocumentWriter(w io.Writer, indent string) DocumentWriter
NewJSONDocumentWriter creates a new ADIFDocumentWriter that writes ADIJ JSON to the provided io.Writer. The indent parameter specifies the string to use for indentation (e.g. "\t" or " "). An empty string means no indentation. JSON is not an official ADIF document container format. It is, however, useful for interoperability with other systems.
Example ¶
ExampleNewADIJWriter demonstrates how to write ADIJ JSON document using NewADIJWriter.
var sb strings.Builder
writer := NewJSONDocumentWriter(&sb, " ")
hdr := NewRecord()
hdr.Set(adifield.CREATED_TIMESTAMP, "20250907 212700")
writer.WriteHeader(hdr)
qso := NewRecord()
qso.Set(adifield.CALL, "K9CTS")
qso.Set(adifield.BAND, band.BAND_20M.String())
qso.Set(adifield.MODE, mode.SSB.String())
writer.WriteRecord(qso)
if err := writer.Flush(); err != nil {
panic(err)
}
fmt.Println(sb.String())
Output: { "HEADER": { "CREATED_TIMESTAMP": "20250907 212700" }, "RECORDS": [ { "BAND": "20M", "CALL": "K9CTS", "MODE": "SSB" } ] }
type Record ¶
type Record interface {
Get(field adifield.Field) string // Get returns the value for the specified field, or an empty string if the field is not present.
Set(field adifield.Field, value string) // Set sets the value for the specified field.
Fields() func(func(adifield.Field, string) bool) // Fields returns an iterator that yields field-value pairs for all fields in the record.
FieldCount() int // FieldCount returns the number of fields in the record.
}
Record represents a single ADIF record. It represents both Header and QSO records.