package main import ( "fmt" "git.swzry.com/zry/go-hhc-cli/hhc_ast" "git.swzry.com/zry/go-hhc-cli/hhc_common" "github.com/cheynewallace/tabby" "math/rand" "net" "os" "regexp" "strconv" "strings" ) var FRGEXP *regexp.Regexp var ExecSB strings.Builder func FExec(ctx *hhc_ast.SDTWalkContext) hhc_common.SDTWalkError { fmt.Println("! Command Execute: ", CtxToCommand(ctx)) ExecSB.WriteString(CtxToCommand(ctx) + "\r\n") return nil } func VLoopbackInf(t string) bool { i, e := strconv.Atoi(t) if e != nil { return false } if i < 0 || i > 7 { return false } return true } func VSubnetLen(t string) bool { i, e := strconv.Atoi(t) if e != nil { return false } if i < 1 || i > 31 { return false } return true } func VMTU(t string) bool { i, e := strconv.Atoi(t) if e != nil { return false } if i < 128 || i > 1500 { return false } return true } func VVlanInf(t string) bool { i, e := strconv.Atoi(t) if e != nil { return false } if i < 0 || i > 4095 { return false } return true } func VIPAddress(t string) bool { _, err := net.ResolveIPAddr("ip", t) return err == nil } func main() { var err error FRGEXP, err = regexp.Compile("INTEGER<([0-9]+)\\-([0-9]+)>") if err != nil { fmt.Println("Failed Compile Regexp:", err) return } ctx := &hhc_ast.SDTWalkContext{ASTNodes: []hhc_ast.ASTNode{}} var cur hhc_ast.SyntaxDefTreeNode cur = (&hhc_ast.SyntaxDefinitionTreeRoot{}).AddCommand( (&hhc_ast.SDTNode_Command{ Name: "ip", Description: "Specify IP configuration", }).AddSubCommand( (&hhc_ast.SDTNode_Command{ Name: "address", Description: "Set the IP address of an interface", }).AddSubCommand((&hhc_ast.SDTNode_Command{ Name: "dhcp-alloc", Description: "Obtain an IP address through DHCP", }).AddEnd(&hhc_ast.SDTNode_End{ Exec: FExec, })).AddSubCommand((&hhc_ast.SDTNode_Command{ Name: "unnumbered", Description: "Share an address with another interface", }).AddSubCommand((&hhc_ast.SDTNode_Command{ Name: "interface", Description: "Specify the interface whose ip address was unnumbered", }).AddSubCommand((&hhc_ast.SDTNode_Command{ Name: "loopback", Description: "LoopBack interface", }).AddValArgument((&hhc_ast.SDTNode_Argument{ FormatDescription: "INTEGER<0-7>", Description: "LoopBack interface number", Validator: VLoopbackInf, }).AddEnd(&hhc_ast.SDTNode_End{ Exec: FExec, }))).AddSubCommand((&hhc_ast.SDTNode_Command{ Name: "vlan-interface", Description: "VLAN interface", }).AddValArgument((&hhc_ast.SDTNode_Argument{ FormatDescription: "INTEGER<0-4095>", Description: "Vlan-interface interface number", Validator: VVlanInf, }).AddEnd(&hhc_ast.SDTNode_End{ Exec: FExec, }))))).AddValArgument((&hhc_ast.SDTNode_Argument{ FormatDescription: "X.X.X.X", Description: "IP address", Validator: VIPAddress, }).AddValArgument((&hhc_ast.SDTNode_Argument{ FormatDescription: "INTEGER<1-31>", Description: "IP mask length", Validator: VSubnetLen, }).AddSubCommand((&hhc_ast.SDTNode_Command{ Name: "sub", Description: "Indicate a subordinate address", }).AddEnd(&hhc_ast.SDTNode_End{ Exec: FExec, })).AddEnd(&hhc_ast.SDTNode_End{ Exec: FExec, })).AddValArgument((&hhc_ast.SDTNode_Argument{ FormatDescription: "X.X.X.X", Description: "IP mask", Validator: VIPAddress, }).AddSubCommand((&hhc_ast.SDTNode_Command{ Name: "sub", Description: "Indicate a subordinate address", }).AddEnd(&hhc_ast.SDTNode_End{ Exec: FExec, })).AddEnd(&hhc_ast.SDTNode_End{ Exec: FExec, })))).AddSubCommand((&hhc_ast.SDTNode_Command{ Name: "mtu", Description: "Specify the MTU of the interface", }).AddValArgument((&hhc_ast.SDTNode_Argument{ FormatDescription: "INTEGER<128-1500>", Description: "MTU in bytes", Validator: VMTU, }).AddEnd(&hhc_ast.SDTNode_End{ Exec: FExec, })))).AddCommand((&hhc_ast.SDTNode_Command{ Name: "ipv6", Description: "Specify IPv6 configuration", }).AddSubCommand((&hhc_ast.SDTNode_Command{ Name: "dhcp", Description: "Configure DHCPv6", }).AddSubCommand((&hhc_ast.SDTNode_Command{ Name: "select", Description: "Specify process mode of DHCPv6 packet", }).AddSubCommand((&hhc_ast.SDTNode_Command{ Name: "relay", Description: "Relay mode", }).AddEnd(&hhc_ast.SDTNode_End{ Exec: FExec, })).AddSubCommand((&hhc_ast.SDTNode_Command{ Name: "server", Description: "Server mode", }).AddEnd(&hhc_ast.SDTNode_End{ Exec: FExec, })))).AddSubCommand((&hhc_ast.SDTNode_Command{ Name: "mtu", Description: "Specify the IPv6 MTU of the interface", }).AddValArgument((&hhc_ast.SDTNode_Argument{ FormatDescription: "INTEGER<128-1500>", Description: "MTU in bytes", Validator: VMTU, }).AddEnd(&hhc_ast.SDTNode_End{ Exec: FExec, })))) t := GenerateValByFormatDesc("X.X.X.X") fmt.Println(t, VIPAddress(t)) t = GenerateValByFormatDesc("INTEGER<1-31>") fmt.Println(t, VSubnetLen(t)) fmt.Println("==== ==== ==== Ready ==== ==== ====") AutoWalk(ctx, cur) fmt.Println("==== ==== ==== End of AutoWalk ==== ==== ====") fmt.Println("All Command Lines:") fmt.Println(ExecSB.String()) //_, _ = ctx, cur } func Walk(ctx *hhc_ast.SDTWalkContext, cur hhc_ast.SyntaxDefTreeNode, token string) hhc_ast.SyntaxDefTreeNode { fmt.Println("Walk into with token:", token) ncur, err := cur.WalkNext(ctx, token) if err != nil { fmt.Println("Error In Walk") fmt.Println("FES:", err.FES()) fmt.Println("EES:", err.EES()) os.Exit(-1) } fmt.Println("Walked into", GetCtxPath(ctx)) return ncur } func AutoWalk(ctx *hhc_ast.SDTWalkContext, cur hhc_ast.SyntaxDefTreeNode) { fmt.Println("======== Help of", GetCtxPath(ctx), "========") if cur.IsEnd() { switch cur.(type) { case *hhc_ast.SDTNode_End: ncur := cur.(*hhc_ast.SDTNode_End) ncur.Exec(ctx) } return } PrintHelp(cur.GetHelps("")) for _, v := range cur.GetHelps("") { nctx := CopyCtx(ctx) var cin hhc_ast.SyntaxDefTreeNode if v.IsArg { cin = Walk(nctx, cur, GenerateValByFormatDesc(v.Name)) } else { cin = Walk(nctx, cur, v.Name) } AutoWalk(nctx, cin) } } func CopyCtx(ctx *hhc_ast.SDTWalkContext) *hhc_ast.SDTWalkContext { nctx := &hhc_ast.SDTWalkContext{ASTNodes: make([]hhc_ast.ASTNode, len(ctx.ASTNodes))} for i, v := range ctx.ASTNodes { nctx.ASTNodes[i] = v } return nctx } func PrintHelp(h []hhc_common.SDTHelpInfo) { t := tabby.New() for i, v := range h { t.AddLine(i, v.IsArg, v.Name, v.Description) } t.Print() } func GetCtxPath(ctx *hhc_ast.SDTWalkContext) string { sb := strings.Builder{} sb.WriteString("/") for _, v := range ctx.ASTNodes { sb.WriteString(v.GetTokenRaw() + "/") } return sb.String() } func CtxToCommand(ctx *hhc_ast.SDTWalkContext) string { sb := strings.Builder{} for _, v := range ctx.ASTNodes { sb.WriteString(v.GetTokenRaw() + " ") } return sb.String() } func GenerateValByFormatDesc(format string) string { if format == "" { return "" } if format == "X.X.X.X" { return "192.168.1.1" } ret := FRGEXP.FindAllStringSubmatch(format, 1) if len(ret) == 1 { if len(ret[0]) == 3 { min, _ := strconv.Atoi(ret[0][1]) max, _ := strconv.Atoi(ret[0][2]) vi := rand.Intn(max-min) + min return strconv.Itoa(vi) } } return "" }