Skip to content

Commit f813455

Browse files
committed
Merge pull request #54 from cbusbey/gen_components
generate header, trailer components
2 parents bd6ac94 + 932c2cb commit f813455

File tree

22 files changed

+700
-15
lines changed

22 files changed

+700
-15
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ get:
55
go get gopkg.in/check.v1
66

77
GEN_MESSAGES = go run _gen/generate-messages/main.go
8+
GEN_COMPONENTS = go run _gen/generate-components/main.go
89
GEN_FIELDS = go run _gen/generate-fields/main.go
910
FIXVERS = FIX40 FIX41 FIX42 FIX43 FIX44 FIX50 FIX50SP1 FIX50SP2 FIXT11
1011

1112
generate:
1213
$(GEN_FIELDS) $(foreach vers, $(FIXVERS), spec/$(vers).xml)
14+
$(foreach vers, $(FIXVERS), $(GEN_COMPONENTS) spec/$(vers).xml;)
1315
$(foreach vers, $(FIXVERS), $(GEN_MESSAGES) spec/$(vers).xml;)
1416

1517
fmt:

_gen/generate-components/main.go

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"github.com/quickfixgo/quickfix/_gen"
7+
"github.com/quickfixgo/quickfix/datadictionary"
8+
"os"
9+
"path"
10+
"strconv"
11+
"strings"
12+
)
13+
14+
var (
15+
pkg string
16+
fixSpec *datadictionary.DataDictionary
17+
)
18+
19+
func usage() {
20+
fmt.Fprintf(os.Stderr, "usage: generate-components [flags] <path to data dictionary>\n")
21+
flag.PrintDefaults()
22+
os.Exit(2)
23+
}
24+
25+
func initPackage() {
26+
pkg = strings.ToLower(fixSpec.FIXType) + strconv.Itoa(fixSpec.Major) + strconv.Itoa(fixSpec.Minor)
27+
28+
if fixSpec.ServicePack != 0 {
29+
pkg += "sp" + strconv.Itoa(fixSpec.ServicePack)
30+
}
31+
}
32+
33+
func packageString() (s string) {
34+
s = fmt.Sprintf("package %v\n", pkg)
35+
return
36+
}
37+
38+
func writeField(field *datadictionary.FieldDef, componentName string) (s string) {
39+
if field.Required {
40+
s += fmt.Sprintf("//%v is a required field for %v.\n", field.Name, componentName)
41+
} else {
42+
s += fmt.Sprintf("//%v is a non-required field for %v.\n", field.Name, componentName)
43+
}
44+
45+
goType := ""
46+
switch field.Type {
47+
case "MULTIPLESTRINGVALUE", "MULTIPLEVALUESTRING":
48+
fallthrough
49+
case "MULTIPLECHARVALUE":
50+
fallthrough
51+
case "CHAR":
52+
fallthrough
53+
case "CURRENCY":
54+
fallthrough
55+
case "DATA":
56+
fallthrough
57+
case "MONTHYEAR":
58+
fallthrough
59+
case "LOCALMKTDATE":
60+
fallthrough
61+
case "EXCHANGE":
62+
fallthrough
63+
case "LANGUAGE":
64+
fallthrough
65+
case "XMLDATA":
66+
fallthrough
67+
case "COUNTRY":
68+
fallthrough
69+
case "UTCTIMEONLY":
70+
fallthrough
71+
case "UTCDATEONLY":
72+
fallthrough
73+
case "TZTIMEONLY":
74+
fallthrough
75+
case "TZTIMESTAMP":
76+
fallthrough
77+
case "STRING":
78+
goType = "string"
79+
80+
case "BOOLEAN":
81+
goType = "bool"
82+
83+
case "LENGTH":
84+
fallthrough
85+
case "DAYOFMONTH":
86+
fallthrough
87+
case "NUMINGROUP":
88+
fallthrough
89+
case "SEQNUM":
90+
fallthrough
91+
case "INT":
92+
goType = "int"
93+
94+
case "TIME":
95+
fallthrough
96+
case "UTCTIMESTAMP":
97+
goType = "time.Time"
98+
99+
case "QTY":
100+
fallthrough
101+
case "AMT":
102+
fallthrough
103+
case "PRICE":
104+
fallthrough
105+
case "PRICEOFFSET":
106+
fallthrough
107+
case "PERCENTAGE":
108+
fallthrough
109+
case "FLOAT":
110+
goType = "float64"
111+
112+
default:
113+
fmt.Printf("Unknown type '%v' for tag '%v'\n", field.Type, field.Tag)
114+
}
115+
116+
fixTags := strconv.Itoa(field.Tag)
117+
if field.Tag == 8 {
118+
if fixSpec.Major == 4 {
119+
fixTags = fmt.Sprintf("%v,default=FIX.%v.%v", fixTags, fixSpec.Major, fixSpec.Minor)
120+
} else {
121+
fixTags = fixTags + ",default=FIXT.1.1"
122+
}
123+
}
124+
125+
if field.Required {
126+
s += fmt.Sprintf("%v %v `fix:\"%v\"`\n", field.Name, goType, fixTags)
127+
} else {
128+
s += fmt.Sprintf("%v *%v `fix:\"%v\"`\n", field.Name, goType, fixTags)
129+
}
130+
return
131+
}
132+
133+
func genComponentImports() string {
134+
fileOut := "import \"time\"\n"
135+
return fileOut
136+
}
137+
138+
func genHeader(header *datadictionary.MessageDef) {
139+
fileOut := packageString()
140+
fileOut += genComponentImports()
141+
142+
fileOut += fmt.Sprintf("//Header is the %v Header type\n", pkg)
143+
fileOut += "type Header struct {\n"
144+
for _, field := range header.FieldsInDeclarationOrder {
145+
fileOut += writeField(field, "Header")
146+
}
147+
fileOut += "}\n"
148+
149+
gen.WriteFile(path.Join(pkg, "header.go"), fileOut)
150+
}
151+
152+
func genTrailer(trailer *datadictionary.MessageDef) {
153+
fileOut := packageString()
154+
fileOut += fmt.Sprintf("//Trailer is the %v Trailer type\n", pkg)
155+
fileOut += "type Trailer struct {\n"
156+
for _, field := range trailer.FieldsInDeclarationOrder {
157+
fileOut += writeField(field, "Trailer")
158+
}
159+
fileOut += "}\n"
160+
161+
gen.WriteFile(path.Join(pkg, "trailer.go"), fileOut)
162+
}
163+
164+
func main() {
165+
flag.Usage = usage
166+
flag.Parse()
167+
168+
if flag.NArg() != 1 {
169+
usage()
170+
}
171+
172+
dataDict := flag.Arg(0)
173+
174+
if spec, err := datadictionary.Parse(dataDict); err != nil {
175+
panic(err)
176+
} else {
177+
fixSpec = spec
178+
}
179+
180+
initPackage()
181+
if fi, err := os.Stat(pkg); os.IsNotExist(err) {
182+
if err := os.Mkdir(pkg, os.ModePerm); err != nil {
183+
panic(err)
184+
}
185+
} else if !fi.IsDir() {
186+
panic(pkg + "/ is not a directory")
187+
}
188+
189+
switch pkg {
190+
//uses fixt11 header/trailer
191+
case "fix50", "fix50sp1", "fix50sp2":
192+
default:
193+
genHeader(fixSpec.Header)
194+
genTrailer(fixSpec.Trailer)
195+
}
196+
}

errors.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ func ValueIsIncorrect(tag Tag) MessageRejectError {
6565
return NewMessageRejectError("Value is incorrect (out of range) for this tag", rejectReasonValueIsIncorrect, &tag)
6666
}
6767

68+
//ConditionallyRequiredFieldMissing indicates that the requested field could not be found in the FIX message.
69+
func ConditionallyRequiredFieldMissing(tag Tag) MessageRejectError {
70+
return NewBusinessMessageRejectError("Conditionally required field missing", rejectReasonConditionallyRequiredFieldMissing, &tag)
71+
}
72+
6873
//valueIsIncorrectNoTag returns an error indicating a field with value that is not valid.
6974
//FIXME: to be compliant with legacy tests, for certain value issues, do not include reftag? (11c_NewSeqNoLess)
7075
func valueIsIncorrectNoTag() MessageRejectError {
@@ -116,11 +121,6 @@ func invalidTagNumber(tag Tag) MessageRejectError {
116121
return NewMessageRejectError("Invalid tag number", rejectReasonInvalidTagNumber, &tag)
117122
}
118123

119-
//conditionallyRequiredFieldMissing indicates that the requested field could not be found in the FIX message.
120-
func conditionallyRequiredFieldMissing(tag Tag) MessageRejectError {
121-
return NewBusinessMessageRejectError("Conditionally required field missing", rejectReasonConditionallyRequiredFieldMissing, &tag)
122-
}
123-
124124
//compIDProblem creates a reject for msg where msg has invalid comp id values.
125125
func compIDProblem() MessageRejectError {
126126
return NewMessageRejectError("CompID problem", rejectReasonCompIDProblem, nil)

field_map.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ func (m FieldMap) Has(tag Tag) bool {
9393
func (m FieldMap) GetField(tag Tag, parser FieldValueReader) MessageRejectError {
9494
tagValues, ok := m.tagLookup[tag]
9595
if !ok {
96-
return conditionallyRequiredFieldMissing(tag)
96+
return ConditionallyRequiredFieldMissing(tag)
9797
}
9898

9999
if err := parser.Read(tagValues[0].Value); err != nil {
@@ -106,7 +106,7 @@ func (m FieldMap) GetField(tag Tag, parser FieldValueReader) MessageRejectError
106106
func (m FieldMap) GetGroup(parser *RepeatingGroup) MessageRejectError {
107107
tagValues, ok := m.tagLookup[parser.Tag]
108108
if !ok {
109-
return conditionallyRequiredFieldMissing(parser.Tag)
109+
return ConditionallyRequiredFieldMissing(parser.Tag)
110110
}
111111

112112
if _, err := parser.Read(tagValues); err != nil {

fix40/header.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package fix40
2+
3+
import "time"
4+
5+
//Header is the fix40 Header type
6+
type Header struct {
7+
//BeginString is a required field for Header.
8+
BeginString string `fix:"8,default=FIX.4.0"`
9+
//BodyLength is a required field for Header.
10+
BodyLength int `fix:"9"`
11+
//MsgType is a required field for Header.
12+
MsgType string `fix:"35"`
13+
//SenderCompID is a required field for Header.
14+
SenderCompID string `fix:"49"`
15+
//TargetCompID is a required field for Header.
16+
TargetCompID string `fix:"56"`
17+
//OnBehalfOfCompID is a non-required field for Header.
18+
OnBehalfOfCompID *string `fix:"115"`
19+
//DeliverToCompID is a non-required field for Header.
20+
DeliverToCompID *string `fix:"128"`
21+
//SecureDataLen is a non-required field for Header.
22+
SecureDataLen *int `fix:"90"`
23+
//SecureData is a non-required field for Header.
24+
SecureData *string `fix:"91"`
25+
//MsgSeqNum is a required field for Header.
26+
MsgSeqNum int `fix:"34"`
27+
//SenderSubID is a non-required field for Header.
28+
SenderSubID *string `fix:"50"`
29+
//TargetSubID is a non-required field for Header.
30+
TargetSubID *string `fix:"57"`
31+
//OnBehalfOfSubID is a non-required field for Header.
32+
OnBehalfOfSubID *string `fix:"116"`
33+
//DeliverToSubID is a non-required field for Header.
34+
DeliverToSubID *string `fix:"129"`
35+
//PossDupFlag is a non-required field for Header.
36+
PossDupFlag *string `fix:"43"`
37+
//PossResend is a non-required field for Header.
38+
PossResend *string `fix:"97"`
39+
//SendingTime is a required field for Header.
40+
SendingTime time.Time `fix:"52"`
41+
//OrigSendingTime is a non-required field for Header.
42+
OrigSendingTime *time.Time `fix:"122"`
43+
}

fix40/trailer.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package fix40
2+
3+
//Trailer is the fix40 Trailer type
4+
type Trailer struct {
5+
//SignatureLength is a non-required field for Trailer.
6+
SignatureLength *int `fix:"93"`
7+
//Signature is a non-required field for Trailer.
8+
Signature *string `fix:"89"`
9+
//CheckSum is a required field for Trailer.
10+
CheckSum string `fix:"10"`
11+
}

fix41/header.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package fix41
2+
3+
import "time"
4+
5+
//Header is the fix41 Header type
6+
type Header struct {
7+
//BeginString is a required field for Header.
8+
BeginString string `fix:"8,default=FIX.4.1"`
9+
//BodyLength is a required field for Header.
10+
BodyLength int `fix:"9"`
11+
//MsgType is a required field for Header.
12+
MsgType string `fix:"35"`
13+
//SenderCompID is a required field for Header.
14+
SenderCompID string `fix:"49"`
15+
//TargetCompID is a required field for Header.
16+
TargetCompID string `fix:"56"`
17+
//OnBehalfOfCompID is a non-required field for Header.
18+
OnBehalfOfCompID *string `fix:"115"`
19+
//DeliverToCompID is a non-required field for Header.
20+
DeliverToCompID *string `fix:"128"`
21+
//SecureDataLen is a non-required field for Header.
22+
SecureDataLen *int `fix:"90"`
23+
//SecureData is a non-required field for Header.
24+
SecureData *string `fix:"91"`
25+
//MsgSeqNum is a required field for Header.
26+
MsgSeqNum int `fix:"34"`
27+
//SenderSubID is a non-required field for Header.
28+
SenderSubID *string `fix:"50"`
29+
//SenderLocationID is a non-required field for Header.
30+
SenderLocationID *string `fix:"142"`
31+
//TargetSubID is a non-required field for Header.
32+
TargetSubID *string `fix:"57"`
33+
//TargetLocationID is a non-required field for Header.
34+
TargetLocationID *string `fix:"143"`
35+
//OnBehalfOfSubID is a non-required field for Header.
36+
OnBehalfOfSubID *string `fix:"116"`
37+
//OnBehalfOfLocationID is a non-required field for Header.
38+
OnBehalfOfLocationID *string `fix:"144"`
39+
//DeliverToSubID is a non-required field for Header.
40+
DeliverToSubID *string `fix:"129"`
41+
//DeliverToLocationID is a non-required field for Header.
42+
DeliverToLocationID *string `fix:"145"`
43+
//PossDupFlag is a non-required field for Header.
44+
PossDupFlag *string `fix:"43"`
45+
//PossResend is a non-required field for Header.
46+
PossResend *string `fix:"97"`
47+
//SendingTime is a required field for Header.
48+
SendingTime time.Time `fix:"52"`
49+
//OrigSendingTime is a non-required field for Header.
50+
OrigSendingTime *time.Time `fix:"122"`
51+
}

fix41/trailer.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package fix41
2+
3+
//Trailer is the fix41 Trailer type
4+
type Trailer struct {
5+
//SignatureLength is a non-required field for Trailer.
6+
SignatureLength *int `fix:"93"`
7+
//Signature is a non-required field for Trailer.
8+
Signature *string `fix:"89"`
9+
//CheckSum is a required field for Trailer.
10+
CheckSum string `fix:"10"`
11+
}

0 commit comments

Comments
 (0)