Reformat the sources with go fmt

pull/2/head
Jean-Marc MEESSEN 4 years ago
parent 590988f3ad
commit ab925ad2dd

@ -1,4 +1,5 @@
package cmd
/*
Copyright © 2020 Jean-Marc Meessen, ON4KJM <on4kjm@gmail.com>
@ -24,8 +25,8 @@ type BraketType int
//Enumeration of the valid Bracket Types
const (
COMMENT BraketType = iota
QSL
COMMENT BraketType = iota
QSL
)
func getBraketedData(inputLine string, braketType BraketType) (braketedData, cleanedLine string) {
@ -37,26 +38,26 @@ func getBraketedData(inputLine string, braketType BraketType) (braketedData, cle
if braketType == COMMENT {
a = "<"
b = ">"
}
}
if braketType == QSL {
a = "["
b = "]"
}
posFirst := strings.Index(inputLine, a)
if posFirst == -1 {
return "",inputLine
}
posLast := strings.Index(inputLine, b)
if posLast == -1 {
return "",inputLine
}
posFirstAdjusted := posFirst + 1
if posFirstAdjusted > posLast {
return "",inputLine
}
posFirst := strings.Index(inputLine, a)
if posFirst == -1 {
return "", inputLine
}
posLast := strings.Index(inputLine, b)
if posLast == -1 {
return "", inputLine
}
posFirstAdjusted := posFirst + 1
if posFirstAdjusted > posLast {
return "", inputLine
}
braketedData = inputLine[posFirstAdjusted:posLast]
cleanedLine = strings.Replace(inputLine, a + braketedData + b, "",1)
return braketedData, cleanedLine
}
cleanedLine = strings.Replace(inputLine, a+braketedData+b, "", 1)
return braketedData, cleanedLine
}

@ -14,45 +14,45 @@ func Test_getBraketedData(t *testing.T) {
wantCleanedLine string
}{
{
"Happy case: comment",
args{ inputLine: "aaaa <bracketed text> bbbbb", braketType: COMMENT},
"bracketed text",
"Happy case: comment",
args{inputLine: "aaaa <bracketed text> bbbbb", braketType: COMMENT},
"bracketed text",
"aaaa bbbbb",
},
{
"Happy case: QSL",
args{ inputLine: "aaaa [bracketed text] bbbbb", braketType: QSL},
"bracketed text",
"Happy case: QSL",
args{inputLine: "aaaa [bracketed text] bbbbb", braketType: QSL},
"bracketed text",
"aaaa bbbbb",
},
{
"Happy case: nothing",
args{ inputLine: "aaaa bbbbb cccccc", braketType: QSL},
"",
"Happy case: nothing",
args{inputLine: "aaaa bbbbb cccccc", braketType: QSL},
"",
"aaaa bbbbb cccccc",
},
{
"Empty brackets",
args{ inputLine: "aaaa <> bbbbb", braketType: COMMENT},
"",
"Empty brackets",
args{inputLine: "aaaa <> bbbbb", braketType: COMMENT},
"",
"aaaa bbbbb",
},
{
"Brackets at right",
args{ inputLine: "aaaa bbbbb <bracketed text>", braketType: COMMENT},
"bracketed text",
"Brackets at right",
args{inputLine: "aaaa bbbbb <bracketed text>", braketType: COMMENT},
"bracketed text",
"aaaa bbbbb ",
},
{
"concatenated",
args{ inputLine: "aaaa<bracketed text>bbbbb", braketType: COMMENT},
"bracketed text",
"concatenated",
args{inputLine: "aaaa<bracketed text>bbbbb", braketType: COMMENT},
"bracketed text",
"aaaabbbbb",
},
{
"duplicated",
args{ inputLine: "aaaa <bracketed text> bbbbb < double > cccc", braketType: COMMENT},
"bracketed text",
"duplicated",
args{inputLine: "aaaa <bracketed text> bbbbb < double > cccc", braketType: COMMENT},
"bracketed text",
"aaaa bbbbb < double > cccc",
},
}

@ -1,4 +1,5 @@
package cmd
/*
Copyright © 2020 Jean-Marc Meessen, ON4KJM <on4kjm@gmail.com>
@ -19,7 +20,7 @@ import (
)
// SprintLogRecord outputs the content of a logline
func SprintLogRecord(logLine LogLine) (output string){
func SprintLogRecord(logLine LogLine) (output string) {
output = ""
output = output + "Date " + logLine.Date + "\n"
output = output + "MyCall " + logLine.MyCall + "\n"
@ -49,10 +50,10 @@ func SprintLogRecord(logLine LogLine) (output string){
}
// SprintHeaderValues displays the header values
func SprintHeaderValues(logLine LogLine) (output string){
func SprintHeaderValues(logLine LogLine) (output string) {
output = ""
output = output + "MyCall " + logLine.MyCall
output = output + "MyCall " + logLine.MyCall
if logLine.Operator != "" {
output = output + " (" + logLine.Operator + ")"
}
@ -66,21 +67,21 @@ func SprintHeaderValues(logLine LogLine) (output string){
output = output + "MySOTA " + logLine.MySOTA + "\n"
}
return output
}
// Date, Time, band, mode, call, report sent, report rcvd, Notes
var logLineFormat = "%-10s %-4s %-4s %-4s %-10s %-4s %-4s %s \n"
// SprintColumnTitles displays the column titles for a log line
func SprintColumnTitles(logLine LogLine) (output string){
func SprintColumnTitles(logLine LogLine) (output string) {
output = fmt.Sprintf(logLineFormat, "Date", "Time", "Band", "Mode", "Call", "Sent", "Rcvd", "Notes")
output = output + fmt.Sprintf(logLineFormat, "----", "----", "----", "----", "----", "----", "----", "----")
return output
}
// SprintLogInColumn displays the logLine in column mode
func SprintLogInColumn(logLine LogLine) (output string){
func SprintLogInColumn(logLine LogLine) (output string) {
notes := ""
if logLine.Frequency != "" {
notes = notes + "QRG: " + logLine.Frequency + " "
@ -107,4 +108,4 @@ func SprintLogInColumn(logLine LogLine) (output string){
output = fmt.Sprintf(logLineFormat, logLine.Date, logLine.Time, logLine.Band, logLine.Mode, logLine.Call, logLine.RSTsent, logLine.RSTrcvd, notes)
return output
}
}

@ -1,4 +1,5 @@
package cmd
/*
Copyright © 2020 Jean-Marc Meessen, ON4KJM <on4kjm@gmail.com>
@ -16,9 +17,9 @@ limitations under the License.
*/
import (
"bufio"
"fmt"
"github.com/spf13/cobra"
"bufio"
"log"
"os"
"regexp"
@ -29,12 +30,12 @@ import (
var loadCmd = &cobra.Command{
Use: "load",
Short: "Loads and validates a FLE type logfile",
// Long: `A longer description that spans multiple lines and likely contains examples
// and usage of using your command. For example:
// Long: `A longer description that spans multiple lines and likely contains examples
// and usage of using your command. For example:
// Cobra is a CLI library for Go that empowers applications.
// This application is a tool to generate the needed files
// to quickly create a Cobra application.`,
// Cobra is a CLI library for Go that empowers applications.
// This application is a tool to generate the needed files
// to quickly create a Cobra application.`,
Run: func(cmd *cobra.Command, args []string) {
//fmt.Println("load called")
//fmt.Println("Inputfile: ",inputFilename)
@ -58,19 +59,19 @@ func init() {
func loadFile() {
file, err := os.Open(inputFilename)
if err != nil {
log.Fatalf("failed opening file: %s", err)
}
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
var txtlines []string
for scanner.Scan() {
txtlines = append(txtlines, scanner.Text())
}
file.Close()
regexpLineComment, _ := regexp.Compile("^#")
@ -79,14 +80,13 @@ func loadFile() {
regexpStartMultiLineComment, _ := regexp.Compile("^{")
regexpEndMultiLineComment, _ := regexp.Compile("}$")
regexpHeaderMyCall, _ := regexp.Compile("(?i)^mycall ")
regexpHeaderOperator, _ := regexp.Compile("(?i)^operator ")
regexpHeaderOperator, _ := regexp.Compile("(?i)^operator ")
regexpHeaderMyWwff, _ := regexp.Compile("(?i)^mywwff ")
regexpHeaderMySota, _ := regexp.Compile("(?i)^mysota ")
regexpHeaderQslMsg, _ := regexp.Compile("(?i)^qslmsg ")
regexpHeaderNickname, _ := regexp.Compile("(?i)^nickname ")
regexpHeaderDate, _ := regexp.Compile("(?i)^date ")
headerMyCall := ""
headerOperator := ""
headerMyWWFF := ""
@ -96,14 +96,13 @@ func loadFile() {
headerDate := ""
lineCount := 0
var isInMultiLine = false
var isInMultiLine = false
var cleanedInput []string
var errorLog []string
var previousLogLine LogLine
var fullLog []LogLine
//Loop through all the stored lined
for _, eachline := range txtlines {
lineCount++
@ -113,25 +112,25 @@ func loadFile() {
// ****
//Skip the line if it starts with "#"
if(regexpLineComment.MatchString(eachline)) {
if regexpLineComment.MatchString(eachline) {
continue
}
//Skip if line is empty or blank
if((len(eachline) == 0) || (regexpOnlySpaces.MatchString(eachline))) {
if (len(eachline) == 0) || (regexpOnlySpaces.MatchString(eachline)) {
continue
}
// Process multi-line comments
if(regexpStartMultiLineComment.MatchString(eachline)) {
if regexpStartMultiLineComment.MatchString(eachline) {
//Single-line "multi-line" coment
if(regexpSingleMultiLineComment.MatchString(eachline)) {
continue
if regexpSingleMultiLineComment.MatchString(eachline) {
continue
}
isInMultiLine = true
continue
}
if(isInMultiLine) {
if(regexpEndMultiLineComment.MatchString(eachline)) {
if isInMultiLine {
if regexpEndMultiLineComment.MatchString(eachline) {
isInMultiLine = false
}
continue
@ -142,29 +141,29 @@ func loadFile() {
// ****
//My Call
if(regexpHeaderMyCall.MatchString(eachline)) {
if regexpHeaderMyCall.MatchString(eachline) {
errorMsg := ""
myCallList := regexpHeaderMyCall.Split(eachline,-1)
if(len(myCallList[1]) > 0) {
myCallList := regexpHeaderMyCall.Split(eachline, -1)
if len(myCallList[1]) > 0 {
headerMyCall, errorMsg = ValidateCall(myCallList[1])
cleanedInput = append(cleanedInput, fmt.Sprintf("My call: %s", headerMyCall))
if(len(errorMsg) != 0) {
errorLog = append(errorLog, fmt.Sprintf("Invalid myCall at line %d: %s (%s)",lineCount, myCallList[1], errorMsg))
if len(errorMsg) != 0 {
errorLog = append(errorLog, fmt.Sprintf("Invalid myCall at line %d: %s (%s)", lineCount, myCallList[1], errorMsg))
}
}
//If there is no data after the marker, we just skip the data.
//If there is no data after the marker, we just skip the data.
continue
}
//Operator
if(regexpHeaderOperator.MatchString(eachline)) {
if regexpHeaderOperator.MatchString(eachline) {
errorMsg := ""
myOperatorList := regexpHeaderOperator.Split(eachline,-1)
if(len(myOperatorList[1]) > 0) {
myOperatorList := regexpHeaderOperator.Split(eachline, -1)
if len(myOperatorList[1]) > 0 {
headerOperator, errorMsg = ValidateCall(myOperatorList[1])
cleanedInput = append(cleanedInput, fmt.Sprintf("Operator: %s", headerOperator))
if(len(errorMsg) != 0) {
errorLog = append(errorLog, fmt.Sprintf("Invalid Operator at line %d: %s (%s)",lineCount, myOperatorList[1], errorMsg))
if len(errorMsg) != 0 {
errorLog = append(errorLog, fmt.Sprintf("Invalid Operator at line %d: %s (%s)", lineCount, myOperatorList[1], errorMsg))
}
}
//If there is no data after the marker, we just skip the data.
@ -172,29 +171,29 @@ func loadFile() {
}
// My WWFF
if(regexpHeaderMyWwff.MatchString(eachline)) {
if regexpHeaderMyWwff.MatchString(eachline) {
errorMsg := ""
myWwffList := regexpHeaderMyWwff.Split(eachline,-1)
if(len(myWwffList[1]) > 0) {
myWwffList := regexpHeaderMyWwff.Split(eachline, -1)
if len(myWwffList[1]) > 0 {
headerMyWWFF, errorMsg = ValidateWwff(myWwffList[1])
cleanedInput = append(cleanedInput, fmt.Sprintf("My WWFF: %s", headerMyWWFF))
if(len(errorMsg) != 0) {
errorLog = append(errorLog, fmt.Sprintf("Invalid \"My WWFF\" at line %d: %s (%s)",lineCount, myWwffList[1], errorMsg))
if len(errorMsg) != 0 {
errorLog = append(errorLog, fmt.Sprintf("Invalid \"My WWFF\" at line %d: %s (%s)", lineCount, myWwffList[1], errorMsg))
}
}
}
//If there is no data after the marker, we just skip the data.
continue
}
//My Sota
if(regexpHeaderMySota.MatchString(eachline)) {
if regexpHeaderMySota.MatchString(eachline) {
errorMsg := ""
mySotaList := regexpHeaderMySota.Split(eachline,-1)
if(len(mySotaList[1]) > 0) {
mySotaList := regexpHeaderMySota.Split(eachline, -1)
if len(mySotaList[1]) > 0 {
headerMySOTA, errorMsg = ValidateSota(mySotaList[1])
cleanedInput = append(cleanedInput, fmt.Sprintf("My Sota: %s", headerMySOTA))
if(len(errorMsg) != 0) {
errorLog = append(errorLog, fmt.Sprintf("Invalid \"My SOTA\" at line %d: %s (%s)",lineCount, mySotaList[1], errorMsg))
if len(errorMsg) != 0 {
errorLog = append(errorLog, fmt.Sprintf("Invalid \"My SOTA\" at line %d: %s (%s)", lineCount, mySotaList[1], errorMsg))
}
}
//If there is no data after the marker, we just skip the data.
@ -202,9 +201,9 @@ func loadFile() {
}
//QSL Message
if(regexpHeaderQslMsg.MatchString(eachline)) {
myQslMsgList := regexpHeaderQslMsg.Split(eachline,-1)
if(len(myQslMsgList[1]) > 0) {
if regexpHeaderQslMsg.MatchString(eachline) {
myQslMsgList := regexpHeaderQslMsg.Split(eachline, -1)
if len(myQslMsgList[1]) > 0 {
headerQslMsg = myQslMsgList[1]
cleanedInput = append(cleanedInput, fmt.Sprintf("QSL Message: %s", headerQslMsg))
}
@ -213,9 +212,9 @@ func loadFile() {
}
//Nickname
if(regexpHeaderNickname.MatchString(eachline)) {
myNicknameList := regexpHeaderNickname.Split(eachline,-1)
if(len(myNicknameList[1]) > 0) {
if regexpHeaderNickname.MatchString(eachline) {
myNicknameList := regexpHeaderNickname.Split(eachline, -1)
if len(myNicknameList[1]) > 0 {
headerNickname = myNicknameList[1]
cleanedInput = append(cleanedInput, fmt.Sprintf("eQSL Nickmane: %s", headerNickname))
}
@ -224,23 +223,23 @@ func loadFile() {
}
// Date
if(regexpHeaderDate.MatchString(eachline)) {
if regexpHeaderDate.MatchString(eachline) {
errorMsg := ""
myDateList := regexpHeaderDate.Split(eachline,-1)
if(len(myDateList[1]) > 0) {
myDateList := regexpHeaderDate.Split(eachline, -1)
if len(myDateList[1]) > 0 {
headerDate, errorMsg = ValidateDate(myDateList[1])
if(len(errorMsg) != 0) {
errorLog = append(errorLog, fmt.Sprintf("Invalid Date at line %d: %s (%s)",lineCount, myDateList[1], errorMsg))
if len(errorMsg) != 0 {
errorLog = append(errorLog, fmt.Sprintf("Invalid Date at line %d: %s (%s)", lineCount, myDateList[1], errorMsg))
}
}
}
//If there is no data after the marker, we just skip the data.
continue
}
}
// ****
// ** Process the data block
// ****
// Load the header values in the previousLogLine
previousLogLine.MyCall = headerMyCall
previousLogLine.Operator = headerOperator
@ -256,7 +255,7 @@ func loadFile() {
fullLog = append(fullLog, logline)
}
if errorLine != "" {
errorLog = append(errorLog, fmt.Sprintf("Parsing error at line %d: %s ",lineCount,errorLine))
errorLog = append(errorLog, fmt.Sprintf("Parsing error at line %d: %s ", lineCount, errorLine))
}
previousLogLine = logline
//Go back to the top (Continue not necessary)
@ -279,14 +278,13 @@ func loadFile() {
fmt.Print(SprintLogInColumn(filledLogLine))
}
if(len(errorLog) != 0){
if len(errorLog) != 0 {
fmt.Println("\nProcessing errors:")
for _, errorLogLine := range errorLog {
fmt.Println(errorLogLine)
}
} else {
fmt.Println("\nSuccesfuly parsed ",lineCount, " lines.")
fmt.Println("\nSuccesfuly parsed ", lineCount, " lines.")
}
}

@ -1,4 +1,5 @@
package cmd
/*
Copyright © 2020 Jean-Marc Meessen, ON4KJM <on4kjm@gmail.com>
@ -15,7 +16,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import (
"fmt"
"regexp"
@ -26,32 +26,31 @@ import (
//TODO: validate a record for minimal values
// LogLine is used to store all the data of a single log line
type LogLine struct {
Date string
MyCall string
Operator string
MyWWFF string
MySOTA string
QslMsg string
Nickname string
Mode string
ModeType string
Band string
Date string
MyCall string
Operator string
MyWWFF string
MySOTA string
QslMsg string
Nickname string
Mode string
ModeType string
Band string
BandLowerLimit float64
BandUpperLimit float64
Frequency string
Time string
Call string
Comment string
QSLmsg string
OMname string
GridLoc string
RSTsent string
RSTrcvd string
WWFF string
SOTA string
Frequency string
Time string
Call string
Comment string
QSLmsg string
OMname string
GridLoc string
RSTsent string
RSTrcvd string
WWFF string
SOTA string
}
var regexpIsFullTime = regexp.MustCompile("^[0-2]{1}[0-9]{3}$")
@ -62,7 +61,7 @@ var regexpIsRst = regexp.MustCompile("^[\\d]{1,3}$")
var regexpIsFreq = regexp.MustCompile("^[\\d]+\\.[\\d]+$")
// ParseLine cuts a FLE line into useful bits
func ParseLine(inputStr string, previousLine LogLine) (logLine LogLine, errorMsg string){
func ParseLine(inputStr string, previousLine LogLine) (logLine LogLine, errorMsg string) {
//TODO: input null protection?
//Flag telling that we are processing data to the right of the callsign
@ -85,23 +84,22 @@ func ParseLine(inputStr string, previousLine LogLine) (logLine LogLine, errorMsg
//TODO: what happens when we have <> or when there are multiple comments
//TODO: Refactor this! it is ugly
comment,inputStr := getBraketedData(inputStr, COMMENT)
comment, inputStr := getBraketedData(inputStr, COMMENT)
if comment != "" {
logLine.Comment = comment
}
QSLmsg,inputStr := getBraketedData(inputStr, QSL)
QSLmsg, inputStr := getBraketedData(inputStr, QSL)
if QSLmsg != "" {
logLine.QSLmsg = QSLmsg
}
elements := strings.Fields(inputStr)
for _, element := range elements {
// Is it a mode?
if lookupMode( strings.ToUpper(element)) {
if lookupMode(strings.ToUpper(element)) {
logLine.Mode = strings.ToUpper(element)
//TODO: improve this: what if the band is at the end of the line
// Set the default RST depending of the mode
@ -119,7 +117,7 @@ func ParseLine(inputStr string, previousLine LogLine) (logLine LogLine, errorMsg
}
// Is it a band?
isBandElement, bandLowerLimit, bandUpperLimit := IsBand(element)
isBandElement, bandLowerLimit, bandUpperLimit := IsBand(element)
if isBandElement {
logLine.Band = strings.ToLower(element)
logLine.BandLowerLimit = bandLowerLimit
@ -130,10 +128,10 @@ func ParseLine(inputStr string, previousLine LogLine) (logLine LogLine, errorMsg
// Is it a Frequency?
if regexpIsFreq.MatchString(element) {
var qrg float64
qrg,_ = strconv.ParseFloat(element, 32)
if (logLine.BandLowerLimit != 0.0) && (logLine.BandUpperLimit != 0.0){
qrg, _ = strconv.ParseFloat(element, 32)
if (logLine.BandLowerLimit != 0.0) && (logLine.BandUpperLimit != 0.0) {
if (qrg >= logLine.BandLowerLimit) && (qrg <= logLine.BandUpperLimit) {
logLine.Frequency = fmt.Sprintf("%.3f",qrg)
logLine.Frequency = fmt.Sprintf("%.3f", qrg)
} else {
logLine.Frequency = ""
errorMsg = errorMsg + " Frequency " + element + " is invalid for " + logLine.Band + " band"
@ -171,18 +169,16 @@ func ParseLine(inputStr string, previousLine LogLine) (logLine LogLine, errorMsg
continue
}
}
// Is it the OM's name (starting with "@")
if regexpIsOMname.MatchString(element) {
logLine.OMname = strings.TrimLeft(element, "@")
logLine.OMname = strings.TrimLeft(element, "@")
continue
}
// Is it the Grid Locator (starting with "#")
if regexpIsGridLoc.MatchString(element) {
logLine.GridLoc = strings.TrimLeft(element, "#")
logLine.GridLoc = strings.TrimLeft(element, "#")
continue
}
@ -194,18 +190,18 @@ func ParseLine(inputStr string, previousLine LogLine) (logLine LogLine, errorMsg
case 1:
if logLine.ModeType == "CW" {
workRST = "5" + element + "9"
} else {
} else {
if logLine.ModeType == "PHONE" {
workRST = "5" + element
}
}
}
case 2:
if logLine.ModeType == "CW" {
workRST = element + "9"
} else {
} else {
if logLine.ModeType == "PHONE" {
workRST = element
}
}
}
case 3:
if logLine.ModeType == "CW" {
@ -225,14 +221,14 @@ func ParseLine(inputStr string, previousLine LogLine) (logLine LogLine, errorMsg
}
// Is it a WWFF to WWFF reference?
workRef, wwffErr := ValidateWwff(element)
workRef, wwffErr := ValidateWwff(element)
if wwffErr == "" {
logLine.WWFF = workRef
continue
}
// Is it a WWFF to WWFF reference?
workRef, sotaErr := ValidateSota(element)
workRef, sotaErr := ValidateSota(element)
if sotaErr == "" {
logLine.SOTA = workRef
continue
@ -258,15 +254,14 @@ func ParseLine(inputStr string, previousLine LogLine) (logLine LogLine, errorMsg
return logLine, errorMsg
}
func lookupMode(lookup string) bool {
switch lookup {
case
"CW",
"SSB",
"CW",
"SSB",
"AM",
"FM",
"RTTY",
"RTTY",
"FT8",
"PSK",
"JT65",
@ -310,11 +305,8 @@ func lookupMode(lookup string) bool {
"V4",
"VOI",
"WINMOR",
"WSPR":
"WSPR":
return true
}
return false
}

@ -5,7 +5,6 @@ import (
"testing"
)
func TestParseLine(t *testing.T) {
type args struct {
inputStr string
@ -18,94 +17,94 @@ func TestParseLine(t *testing.T) {
wantErrorMsg string
}{
{
"Parse band and mode only",
args{ inputStr: "40M cw", previousLine: LogLine{ Mode: "SSB", }},
LogLine{ Band: "40m", BandLowerLimit: 7, BandUpperLimit: 7.3, Mode: "CW", ModeType: "CW", RSTsent: "599", RSTrcvd: "599"}, "",
"Parse band and mode only",
args{inputStr: "40M cw", previousLine: LogLine{Mode: "SSB"}},
LogLine{Band: "40m", BandLowerLimit: 7, BandUpperLimit: 7.3, Mode: "CW", ModeType: "CW", RSTsent: "599", RSTrcvd: "599"}, "",
},
{
"Parse for time",
args{ inputStr: "1314 g3noh", previousLine: LogLine{ Mode: "SSB", }},
LogLine{ Time: "1314", Call: "G3NOH", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "",
"Parse for time",
args{inputStr: "1314 g3noh", previousLine: LogLine{Mode: "SSB"}},
LogLine{Time: "1314", Call: "G3NOH", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "",
},
{
"Parse partial time - 1",
args{ inputStr: "4 g3noh", previousLine: LogLine{ Time: "", Mode: "SSB", }},
LogLine{ Time: "4", Call: "G3NOH", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "", //TODO: should fail
"Parse partial time - 1",
args{inputStr: "4 g3noh", previousLine: LogLine{Time: "", Mode: "SSB"}},
LogLine{Time: "4", Call: "G3NOH", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "", //TODO: should fail
},
{
"Parse partial time - 2",
args{ inputStr: "15 g3noh", previousLine: LogLine{ Time: "1200", Mode: "SSB", }},
LogLine{ Time: "1215", Call: "G3NOH", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "",
"Parse partial time - 2",
args{inputStr: "15 g3noh", previousLine: LogLine{Time: "1200", Mode: "SSB"}},
LogLine{Time: "1215", Call: "G3NOH", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "",
},
{
"Parse partial time - 3",
args{ inputStr: "4 g3noh", previousLine: LogLine{ Time: "1200", Mode: "SSB", }},
LogLine{ Time: "1204", Call: "G3NOH", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "",
"Parse partial time - 3",
args{inputStr: "4 g3noh", previousLine: LogLine{Time: "1200", Mode: "SSB"}},
LogLine{Time: "1204", Call: "G3NOH", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "",
},
{
"Parse for comment",
args{ inputStr: "4 g3noh <PSE QSL Direct>", previousLine: LogLine{ Mode: "SSB", }},
LogLine{ Time: "4", Comment: "PSE QSL Direct", Call: "G3NOH", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "",
"Parse for comment",
args{inputStr: "4 g3noh <PSE QSL Direct>", previousLine: LogLine{Mode: "SSB"}},
LogLine{Time: "4", Comment: "PSE QSL Direct", Call: "G3NOH", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "",
},
{
"Parse for QSL",
args{ inputStr: "g3noh [Custom QSL message]", previousLine: LogLine{ Mode: "SSB", }},
LogLine{ QSLmsg: "Custom QSL message", Call: "G3NOH", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "",
"Parse for QSL",
args{inputStr: "g3noh [Custom QSL message]", previousLine: LogLine{Mode: "SSB"}},
LogLine{QSLmsg: "Custom QSL message", Call: "G3NOH", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "",
},
{
"Wrong mode",
args{ inputStr: "cww", previousLine: LogLine{ Mode: "SSB", }},
LogLine{ Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "Unable to parse cww ",
"Wrong mode",
args{inputStr: "cww", previousLine: LogLine{Mode: "SSB"}},
LogLine{Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "Unable to parse cww ",
},
{
"Parse OM name",
args{ inputStr: "@Jean", previousLine: LogLine{ Mode: "SSB", }},
LogLine{ OMname: "Jean", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "",
"Parse OM name",
args{inputStr: "@Jean", previousLine: LogLine{Mode: "SSB"}},
LogLine{OMname: "Jean", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "",
},
{
"Parse Grid locator",
args{ inputStr: "#grid", previousLine: LogLine{ Mode: "SSB", }},
LogLine{ GridLoc: "grid", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "",
"Parse Grid locator",
args{inputStr: "#grid", previousLine: LogLine{Mode: "SSB"}},
LogLine{GridLoc: "grid", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "",
},
{
"Parse frequency",
args{ inputStr: "14.153 on4kjm", previousLine: LogLine{ Mode: "SSB", Band: "20m", BandLowerLimit: 14.0, BandUpperLimit: 14.35}},
LogLine{ Band: "20m", BandLowerLimit: 14.0, BandUpperLimit: 14.35, Frequency: "14.153", Call: "ON4KJM" ,Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "",
"Parse frequency",
args{inputStr: "14.153 on4kjm", previousLine: LogLine{Mode: "SSB", Band: "20m", BandLowerLimit: 14.0, BandUpperLimit: 14.35}},
LogLine{Band: "20m", BandLowerLimit: 14.0, BandUpperLimit: 14.35, Frequency: "14.153", Call: "ON4KJM", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, "",
},
{
"Parse frequency out of limit",
args{ inputStr: "14.453 on4kjm", previousLine: LogLine{ Mode: "SSB", Band: "20m", BandLowerLimit: 14.0, BandUpperLimit: 14.35}},
LogLine{ Band: "20m", BandLowerLimit: 14.0, BandUpperLimit: 14.35, Call: "ON4KJM" ,Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, " Frequency 14.453 is invalid for 20m band",
"Parse frequency out of limit",
args{inputStr: "14.453 on4kjm", previousLine: LogLine{Mode: "SSB", Band: "20m", BandLowerLimit: 14.0, BandUpperLimit: 14.35}},
LogLine{Band: "20m", BandLowerLimit: 14.0, BandUpperLimit: 14.35, Call: "ON4KJM", Mode: "SSB", RSTsent: "59", RSTrcvd: "59"}, " Frequency 14.453 is invalid for 20m band",
},
{
"parse partial RST (sent) - CW",
args{ inputStr: "1230 on4kjm 5", previousLine: LogLine{ Mode: "CW", ModeType: "CW"}},
LogLine{ Call: "ON4KJM", Time: "1230", RSTsent: "559", RSTrcvd: "599", Mode: "CW", ModeType: "CW"}, "",
"parse partial RST (sent) - CW",
args{inputStr: "1230 on4kjm 5", previousLine: LogLine{Mode: "CW", ModeType: "CW"}},
LogLine{Call: "ON4KJM", Time: "1230", RSTsent: "559", RSTrcvd: "599", Mode: "CW", ModeType: "CW"}, "",
},
{
"parse partial RST (received) - CW",
args{ inputStr: "1230 on4kjm 5 44", previousLine: LogLine{ Mode: "CW", ModeType: "CW"}},
LogLine{ Call: "ON4KJM", Time: "1230", RSTsent: "559", RSTrcvd: "449", Mode: "CW", ModeType: "CW"}, "",
"parse partial RST (received) - CW",
args{inputStr: "1230 on4kjm 5 44", previousLine: LogLine{Mode: "CW", ModeType: "CW"}},
LogLine{Call: "ON4KJM", Time: "1230", RSTsent: "559", RSTrcvd: "449", Mode: "CW", ModeType: "CW"}, "",
},
{
"parse full RST (received) - CW",
args{ inputStr: "1230 on4kjm 5 448", previousLine: LogLine{ Mode: "CW", ModeType: "CW"}},
LogLine{ Call: "ON4KJM", Time: "1230", RSTsent: "559", RSTrcvd: "448", Mode: "CW", ModeType: "CW"}, "",
"parse full RST (received) - CW",
args{inputStr: "1230 on4kjm 5 448", previousLine: LogLine{Mode: "CW", ModeType: "CW"}},
LogLine{Call: "ON4KJM", Time: "1230", RSTsent: "559", RSTrcvd: "448", Mode: "CW", ModeType: "CW"}, "",
},
{
"parse partial report (sent) - FM",
args{ inputStr: "1230 on4kjm 5", previousLine: LogLine{ Mode: "FM", ModeType: "PHONE"}},
LogLine{ Call: "ON4KJM", Time: "1230", RSTsent: "55", RSTrcvd: "59", Mode: "FM", ModeType: "PHONE"}, "",
"parse partial report (sent) - FM",
args{inputStr: "1230 on4kjm 5", previousLine: LogLine{Mode: "FM", ModeType: "PHONE"}},
LogLine{Call: "ON4KJM", Time: "1230", RSTsent: "55", RSTrcvd: "59", Mode: "FM", ModeType: "PHONE"}, "",
},
{
"parse partial report (received) - FM",
args{ inputStr: "1230 on4kjm 5 44", previousLine: LogLine{ Mode: "FM", ModeType: "PHONE"}},
LogLine{ Call: "ON4KJM", Time: "1230", RSTsent: "55", RSTrcvd: "44", Mode: "FM", ModeType: "PHONE"}, "",
"parse partial report (received) - FM",
args{inputStr: "1230 on4kjm 5 44", previousLine: LogLine{Mode: "FM", ModeType: "PHONE"}},
LogLine{Call: "ON4KJM", Time: "1230", RSTsent: "55", RSTrcvd: "44", Mode: "FM", ModeType: "PHONE"}, "",
},
{
"Incompatible report",
args{ inputStr: "1230 on4kjm 5 599", previousLine: LogLine{ Mode: "FM", ModeType: "PHONE"}},
LogLine{ Call: "ON4KJM", Time: "1230", RSTsent: "55", RSTrcvd: "*599", Mode: "FM", ModeType: "PHONE"}, "Invalid report (599) for PHONE mode ",
"Incompatible report",
args{inputStr: "1230 on4kjm 5 599", previousLine: LogLine{Mode: "FM", ModeType: "PHONE"}},
LogLine{Call: "ON4KJM", Time: "1230", RSTsent: "55", RSTrcvd: "*599", Mode: "FM", ModeType: "PHONE"}, "Invalid report (599) for PHONE mode ",
},
}
for _, tt := range tests {
@ -133,34 +132,34 @@ func TestHappyParseLine(t *testing.T) {
wantErrorMsg string
}{
{
"test1",
args{ inputStr: "1202 g4elz",
previousLine: LogLine{ Mode: "CW", ModeType: "CW", Band: "40m", BandLowerLimit: 7, BandUpperLimit: 7.3}},
LogLine{ Time: "1202", Call: "G4ELZ", Band: "40m", BandLowerLimit: 7, BandUpperLimit: 7.3, Mode: "CW", ModeType: "CW", RSTsent: "599", RSTrcvd: "599"}, "",
"test1",
args{inputStr: "1202 g4elz",
previousLine: LogLine{Mode: "CW", ModeType: "CW", Band: "40m", BandLowerLimit: 7, BandUpperLimit: 7.3}},
LogLine{Time: "1202", Call: "G4ELZ", Band: "40m", BandLowerLimit: 7, BandUpperLimit: 7.3, Mode: "CW", ModeType: "CW", RSTsent: "599", RSTrcvd: "599"}, "",
},
{
"test2",
args{ inputStr: "4 g3noh <PSE QSL Direct>",
previousLine: LogLine{ Time: "1202", Mode: "CW", ModeType: "CW", Band: "40m", BandLowerLimit: 7, BandUpperLimit: 7.3}},
LogLine{ Time: "1204", Call: "G3NOH", Band: "40m", BandLowerLimit: 7, BandUpperLimit: 7.3, Mode: "CW", ModeType: "CW", Comment: "PSE QSL Direct", RSTsent: "599", RSTrcvd: "599"}, "",
"test2",
args{inputStr: "4 g3noh <PSE QSL Direct>",
previousLine: LogLine{Time: "1202", Mode: "CW", ModeType: "CW", Band: "40m", BandLowerLimit: 7, BandUpperLimit: 7.3}},
LogLine{Time: "1204", Call: "G3NOH", Band: "40m", BandLowerLimit: 7, BandUpperLimit: 7.3, Mode: "CW", ModeType: "CW", Comment: "PSE QSL Direct", RSTsent: "599", RSTrcvd: "599"}, "",
},
{
"test3",
args{ inputStr: "1227 gw4gte <Dave>",
previousLine: LogLine{ Time: "1202", Mode: "FM", ModeType: "PHONE", Band: "2m", BandLowerLimit: 144, BandUpperLimit: 148}},
LogLine{ Time: "1227", Call: "GW4GTE", Band: "2m", BandLowerLimit: 144, BandUpperLimit: 148, Mode: "FM", ModeType: "PHONE", Comment: "Dave", RSTsent: "59", RSTrcvd: "59"}, "",
"test3",
args{inputStr: "1227 gw4gte <Dave>",
previousLine: LogLine{Time: "1202", Mode: "FM", ModeType: "PHONE", Band: "2m", BandLowerLimit: 144, BandUpperLimit: 148}},
LogLine{Time: "1227", Call: "GW4GTE", Band: "2m", BandLowerLimit: 144, BandUpperLimit: 148, Mode: "FM", ModeType: "PHONE", Comment: "Dave", RSTsent: "59", RSTrcvd: "59"}, "",
},
{
"test4",
args{ inputStr: "8 gw0tlk/m gwff-0021",
previousLine: LogLine{ Time: "1227", Mode: "FM", ModeType: "PHONE", Band: "2m", BandLowerLimit: 144, BandUpperLimit: 148}},
LogLine{ Time: "1228", Call: "GW0TLK/M", Band: "2m", BandLowerLimit: 144, BandUpperLimit: 148, Mode: "FM", ModeType: "PHONE", WWFF: "GWFF-0021", RSTsent: "59", RSTrcvd: "59"}, "",
"test4",
args{inputStr: "8 gw0tlk/m gwff-0021",
previousLine: LogLine{Time: "1227", Mode: "FM", ModeType: "PHONE", Band: "2m", BandLowerLimit: 144, BandUpperLimit: 148}},
LogLine{Time: "1228", Call: "GW0TLK/M", Band: "2m", BandLowerLimit: 144, BandUpperLimit: 148, Mode: "FM", ModeType: "PHONE", WWFF: "GWFF-0021", RSTsent: "59", RSTrcvd: "59"}, "",
},
{
"test5",
args{ inputStr: "7 dl0dan/p dlff-0002 dl/al-044",
previousLine: LogLine{ Time: "1220", Mode: "FM", ModeType: "PHONE", Band: "2m", BandLowerLimit: 144, BandUpperLimit: 148}},
LogLine{ Time: "1227", Call: "DL0DAN/P", Band: "2m", BandLowerLimit: 144, BandUpperLimit: 148, Mode: "FM", ModeType: "PHONE", WWFF: "DLFF-0002", SOTA: "DL/AL-044", RSTsent: "59", RSTrcvd: "59"}, "",
"test5",
args{inputStr: "7 dl0dan/p dlff-0002 dl/al-044",
previousLine: LogLine{Time: "1220", Mode: "FM", ModeType: "PHONE", Band: "2m", BandLowerLimit: 144, BandUpperLimit: 148}},
LogLine{Time: "1227", Call: "DL0DAN/P", Band: "2m", BandLowerLimit: 144, BandUpperLimit: 148, Mode: "FM", ModeType: "PHONE", WWFF: "DLFF-0002", SOTA: "DL/AL-044", RSTsent: "59", RSTrcvd: "59"}, "",
},
}
for _, tt := range tests {
@ -174,4 +173,4 @@ func TestHappyParseLine(t *testing.T) {
}
})
}
}
}

@ -1,4 +1,5 @@
package cmd
/*
Copyright © 2020 Jean-Marc Meessen, ON4KJM <on4kjm@gmail.com>
@ -36,15 +37,15 @@ var inputFilename string
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "FLEcli",
Short: "A Command Line \"Fast Log Entry\" (FLE) processor",
Use: "FLEcli",
Short: "A Command Line \"Fast Log Entry\" (FLE) processor",
TraverseChildren: true,
// Long: `A longer description that spans multiple lines and likely contains
// examples and usage of using your application. For example:
// Long: `A longer description that spans multiple lines and likely contains
// examples and usage of using your application. For example:
// Cobra is a CLI library for Go that empowers applications.
// This application is a tool to generate the needed files
// to quickly create a Cobra application.`,
// Cobra is a CLI library for Go that empowers applications.
// This application is a tool to generate the needed files
// to quickly create a Cobra application.`,
// Uncomment the following line if your bare application
// has an action associated with it:
// Run: func(cmd *cobra.Command, args []string) { },

@ -1,4 +1,5 @@
package cmd
/*
Copyright © 2020 Jean-Marc Meessen, ON4KJM <on4kjm@gmail.com>
@ -16,24 +17,23 @@ limitations under the License.
*/
import (
"fmt"
"regexp"
"strings"
"fmt"
"time"
)
var validSotaRegexp = regexp.MustCompile(`^[0-9A-Z]{1,3}/[A-Z]{2}-[\d]{3}$`)
// ValidateSota verifies whether the supplied string is a valid SOTA reference.
// The syntax is: AA/NN-CCC: Association/Name-3-digit numeric Code (e.g. G/CE-001).
// The syntax is: AA/NN-CCC: Association/Name-3-digit numeric Code (e.g. G/CE-001).
func ValidateSota(inputStr string) (ref, errorMsg string) {
inputStr = strings.ToUpper(strings.TrimSpace(inputStr))
wrongInputStr := "*" + inputStr
if validSotaRegexp.MatchString(inputStr) {
return inputStr, ""
}
return wrongInputStr, "Invalid SOTA reference"
if validSotaRegexp.MatchString(inputStr) {
return inputStr, ""
}
return wrongInputStr, "Invalid SOTA reference"
}
var validWwffRegexp = regexp.MustCompile(`^[\d]{0,1}[A-Z]{1,2}FF-[\d]{4}$`)
@ -43,14 +43,12 @@ var validWwffRegexp = regexp.MustCompile(`^[\d]{0,1}[A-Z]{1,2}FF-[\d]{4}$`)
func ValidateWwff(inputStr string) (ref, errorMsg string) {
inputStr = strings.ToUpper(strings.TrimSpace(inputStr))
wrongInputStr := "*" + inputStr
if validWwffRegexp.MatchString(inputStr) {
return inputStr, ""
}
return wrongInputStr, "Invalid WWFF reference"
if validWwffRegexp.MatchString(inputStr) {
return inputStr, ""
}
return wrongInputStr, "Invalid WWFF reference"
}
var validCallRegexp = regexp.MustCompile(`[\d]{0,1}[A-Z]{1,2}\d([A-Z]{1,4}|\d{3,3}|\d{1,3}[A-Z])[A-Z]{0,5}`)
var validPrefixRegexp = regexp.MustCompile(`\A\d?[a-zA-Z]{1,2}$`)
@ -72,9 +70,9 @@ func ValidateCall(sign string) (call, errorMsg string) {
if validCallRegexp.MatchString(sp[0]) {
//Callisign with suffix (unchecked)
return sign, ""
}
}
//else we are dealing with a prefixed Callsign
//validate the part that should contain the call (sp[1])
//validate the part that should contain the call (sp[1])
if !validCallRegexp.MatchString(sp[1]) {
return wrongSign, "Invalid call"
}
@ -84,7 +82,7 @@ func ValidateCall(sign string) (call, errorMsg string) {
}
return sign, ""
case 3:
//validate the part that should contain the call (sp[1])
//validate the part that should contain the call (sp[1])
if !validCallRegexp.MatchString(sp[1]) {
return wrongSign, "Invalid call"
}
@ -117,85 +115,84 @@ func ValidateDate(inputStr string) (ref, errorMsg string) {
//IsBand retuns true if the passed input string is a valid string
func IsBand(inputStr string) (result bool, lowerLimit, upperLimit float64) {
switch strings.ToLower(inputStr) {
case "2190m":
return true, 0.1357, 0.1378
case "630m":
return true, 0.472, 0.479
case "560m":
return true, 0.501, 0.504
case "160m":
return true, 1.8, 2.0
case "80m":
return true, 3.5, 4.0
case "60m":
return true, 5.06, 5.45
case "40m":
return true, 7.0, 7.3
case "30m":
return true, 10.1, 10.15
case "20m":
return true, 14.0, 14.35
case "17m":
return true, 18.068, 18.168
case "15m":
return true, 21.0, 21.45
case "12m":
return true, 24.890, 24.99
case "10m":
return true, 28.0, 29.7
case "6m":
return true, 50, 54
case "4m":
return true, 70, 71
case "2m":
return true, 144, 148
case "1.25m":
return true, 222, 225
case "70cm":
return true, 420, 450
case "33cm":
return true, 902, 928
case "23cm":
return true, 1240, 1300
case "13cm":
return true, 2300, 2450
case "9cm":
return true, 3300, 3500
case "6cm":
return true, 5650, 5925
case "3cm":
return true, 10000, 10500
case "1.25cm":
return true, 24000, 24250
case "6mm":
return true, 47000, 47200
case "4mm":
return true, 75500, 81000
case "2.5mm":
return true, 119980, 120020
case "2mm":
return true, 142000, 149000
case "1mm":
return true, 241000, 250000
case "2190m":
return true, 0.1357, 0.1378
case "630m":
return true, 0.472, 0.479
case "560m":
return true, 0.501, 0.504
case "160m":
return true, 1.8, 2.0
case "80m":
return true, 3.5, 4.0
case "60m":
return true, 5.06, 5.45
case "40m":
return true, 7.0, 7.3
case "30m":
return true, 10.1, 10.15
case "20m":
return true, 14.0, 14.35
case "17m":
return true, 18.068, 18.168
case "15m":
return true, 21.0, 21.45
case "12m":
return true, 24.890, 24.99
case "10m":
return true, 28.0, 29.7
case "6m":
return true, 50, 54
case "4m":
return true, 70, 71
case "2m":
return true, 144, 148
case "1.25m":
return true, 222, 225
case "70cm":
return true, 420, 450
case "33cm":
return true, 902, 928
case "23cm":
return true, 1240, 1300
case "13cm":
return true, 2300, 2450
case "9cm":
return true, 3300, 3500
case "6cm":
return true, 5650, 5925
case "3cm":
return true, 10000, 10500
case "1.25cm":
return true, 24000, 24250
case "6mm":
return true, 47000, 47200
case "4mm":
return true, 75500, 81000
case "2.5mm":
return true, 119980, 120020
case "2mm":
return true, 142000, 149000
case "1mm":
return true, 241000, 250000
}
return false, 0, 0
}
func getDefaultReport(mode string) (modeType, defaultReport string) {
modeType = ""
defaultReport = ""
switch mode {
case "SSB", "AM", "FM" :
case "SSB", "AM", "FM":
modeType = "PHONE"
defaultReport = "59"
case "CW", "RTTY", "PSK":
modeType = "CW"
defaultReport = "599"
case "JT65", "JT9", "JT6M", "JT4", "JT44", "FSK441", "FT8", "ISCAT", "MSK144", "QRA64", "T10", "WSPR" :
case "JT65", "JT9", "JT6M", "JT4", "JT44", "FSK441", "FT8", "ISCAT", "MSK144", "QRA64", "T10", "WSPR":
modeType = "DIGITAL"
defaultReport = "-10"
defaultReport = "-10"
}
return modeType, defaultReport
}

Loading…
Cancel
Save