195 lines
4.2 KiB
Go
195 lines
4.2 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"path"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"text/template"
|
|
|
|
"quantex.com/qfixdpl/quickfix/cmd/generate-fix/internal"
|
|
"quantex.com/qfixdpl/quickfix/datadictionary"
|
|
)
|
|
|
|
var (
|
|
waitGroup sync.WaitGroup
|
|
errors = make(chan error)
|
|
)
|
|
|
|
func usage() {
|
|
fmt.Fprintf(os.Stderr, "usage: %v [flags] <path to data dictionary> ... \n", os.Args[0])
|
|
flag.PrintDefaults()
|
|
os.Exit(2)
|
|
}
|
|
|
|
func getPackageName(fixSpec *datadictionary.DataDictionary) string {
|
|
pkg := strings.ToLower(fixSpec.FIXType) + strconv.Itoa(fixSpec.Major) + strconv.Itoa(fixSpec.Minor)
|
|
|
|
if fixSpec.ServicePack != 0 {
|
|
pkg += "sp" + strconv.Itoa(fixSpec.ServicePack)
|
|
}
|
|
|
|
return pkg
|
|
}
|
|
|
|
func getTransportPackageName(fixSpec *datadictionary.DataDictionary) string {
|
|
if fixSpec.Major >= 5 {
|
|
return "fixt11"
|
|
}
|
|
return getPackageName(fixSpec)
|
|
}
|
|
|
|
type component struct {
|
|
Package string
|
|
FIXPackage string
|
|
TransportPackage string
|
|
FIXSpec *datadictionary.DataDictionary
|
|
Name string
|
|
*datadictionary.MessageDef
|
|
}
|
|
|
|
func genHeader(pkg string, spec *datadictionary.DataDictionary) {
|
|
c := component{
|
|
Package: pkg,
|
|
Name: "Header",
|
|
MessageDef: spec.Header,
|
|
FIXSpec: spec,
|
|
}
|
|
gen(internal.HeaderTemplate, path.Join(pkg, "header.generated.go"), c)
|
|
}
|
|
|
|
func genTrailer(pkg string, spec *datadictionary.DataDictionary) {
|
|
c := component{
|
|
Package: pkg,
|
|
Name: "Trailer",
|
|
MessageDef: spec.Trailer,
|
|
}
|
|
gen(internal.TrailerTemplate, path.Join(pkg, "trailer.generated.go"), c)
|
|
}
|
|
|
|
func genMessage(fixPkg string, spec *datadictionary.DataDictionary, msg *datadictionary.MessageDef) {
|
|
pkgName := strings.ToLower(msg.Name)
|
|
transportPkg := getTransportPackageName(spec)
|
|
|
|
c := component{
|
|
Package: pkgName,
|
|
FIXPackage: fixPkg,
|
|
TransportPackage: transportPkg,
|
|
FIXSpec: spec,
|
|
Name: msg.Name,
|
|
MessageDef: msg,
|
|
}
|
|
|
|
gen(internal.MessageTemplate, path.Join(fixPkg, pkgName, msg.Name+".generated.go"), c)
|
|
}
|
|
|
|
func genTags() {
|
|
gen(internal.TagTemplate, "tag/tag_numbers.generated.go", internal.GlobalFieldTypes)
|
|
}
|
|
|
|
func genFields() {
|
|
gen(internal.FieldTemplate, "field/fields.generated.go", internal.GlobalFieldTypes)
|
|
}
|
|
|
|
func genEnums() {
|
|
gen(internal.EnumTemplate, "enum/enums.generated.go", internal.GlobalFieldTypes)
|
|
}
|
|
|
|
func gen(t *template.Template, fileOut string, data interface{}) {
|
|
defer waitGroup.Done()
|
|
writer := new(bytes.Buffer)
|
|
|
|
if err := t.Execute(writer, data); err != nil {
|
|
errors <- err
|
|
return
|
|
}
|
|
|
|
if err := internal.WriteFile(fileOut, writer.String()); err != nil {
|
|
errors <- err
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
flag.Usage = usage
|
|
flag.Parse()
|
|
|
|
if flag.NArg() < 1 {
|
|
usage()
|
|
}
|
|
|
|
args := flag.Args()
|
|
if len(args) == 1 {
|
|
dictpath := args[0]
|
|
if strings.Contains(dictpath, "FIX50SP1") {
|
|
args = append(args, strings.Replace(dictpath, "FIX50SP1", "FIXT11", -1))
|
|
} else if strings.Contains(dictpath, "FIX50SP2") {
|
|
args = append(args, strings.Replace(dictpath, "FIX50SP2", "FIXT11", -1))
|
|
} else if strings.Contains(dictpath, "FIX50") {
|
|
args = append(args, strings.Replace(dictpath, "FIX50", "FIXT11", -1))
|
|
}
|
|
}
|
|
specs := []*datadictionary.DataDictionary{}
|
|
|
|
for _, dataDictPath := range args {
|
|
spec, err := datadictionary.Parse(dataDictPath)
|
|
if err != nil {
|
|
log.Fatalf("Error Parsing %v: %v", dataDictPath, err)
|
|
}
|
|
specs = append(specs, spec)
|
|
}
|
|
|
|
internal.BuildGlobalFieldTypes(specs)
|
|
|
|
waitGroup.Add(1)
|
|
go genTags()
|
|
waitGroup.Add(1)
|
|
go genFields()
|
|
waitGroup.Add(1)
|
|
go genEnums()
|
|
|
|
for _, spec := range specs {
|
|
pkg := getPackageName(spec)
|
|
|
|
if fi, err := os.Stat(pkg); os.IsNotExist(err) {
|
|
if err := os.Mkdir(pkg, os.ModePerm); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
} else if !fi.IsDir() {
|
|
log.Fatalf("%v/ is not a directory", pkg)
|
|
}
|
|
|
|
switch pkg {
|
|
// Uses fixt11 header/trailer.
|
|
case "fix50", "fix50sp1", "fix50sp2":
|
|
default:
|
|
waitGroup.Add(1)
|
|
go genHeader(pkg, spec)
|
|
|
|
waitGroup.Add(1)
|
|
go genTrailer(pkg, spec)
|
|
}
|
|
|
|
for _, m := range spec.Messages {
|
|
waitGroup.Add(1)
|
|
go genMessage(pkg, spec, m)
|
|
}
|
|
}
|
|
|
|
go func() {
|
|
waitGroup.Wait()
|
|
close(errors)
|
|
}()
|
|
|
|
var h internal.ErrorHandler
|
|
for err := range errors {
|
|
h.Handle(err)
|
|
}
|
|
|
|
os.Exit(h.ReturnCode)
|
|
}
|