diff options
author | Chris Koch <chrisko@google.com> | 2023-02-18 14:41:32 -0800 |
---|---|---|
committer | Chris K <c@chrisko.ch> | 2023-02-18 23:57:24 -0800 |
commit | b606c2152e1b91a556c42f126d5279348678682d (patch) | |
tree | a621015fb6b48c48ae4130beb49760328e15a039 | |
parent | 573052511f5790667b95f4a801f7ed0680a66a83 (diff) |
Recursive pretty-printing with indentation
Signed-off-by: Chris Koch <chrisko@google.com>
-rw-r--r-- | dhcpv6/dhcpv6.go | 1 | ||||
-rw-r--r-- | dhcpv6/dhcpv6message.go | 38 | ||||
-rw-r--r-- | dhcpv6/dhcpv6relay.go | 39 | ||||
-rw-r--r-- | dhcpv6/option_4rd.go | 5 | ||||
-rw-r--r-- | dhcpv6/option_dhcpv4_msg.go | 12 | ||||
-rw-r--r-- | dhcpv6/option_iaaddress.go | 6 | ||||
-rw-r--r-- | dhcpv6/option_iapd.go | 5 | ||||
-rw-r--r-- | dhcpv6/option_nontemporaryaddress.go | 5 | ||||
-rw-r--r-- | dhcpv6/option_relaymsg.go | 5 | ||||
-rw-r--r-- | dhcpv6/option_temporaryaddress.go | 5 | ||||
-rw-r--r-- | dhcpv6/option_vendor_opts.go | 5 | ||||
-rw-r--r-- | dhcpv6/options.go | 29 |
12 files changed, 125 insertions, 30 deletions
diff --git a/dhcpv6/dhcpv6.go b/dhcpv6/dhcpv6.go index 59d9733..8addba2 100644 --- a/dhcpv6/dhcpv6.go +++ b/dhcpv6/dhcpv6.go @@ -14,6 +14,7 @@ type DHCPv6 interface { ToBytes() []byte String() string Summary() string + LongString(indent int) string IsRelay() bool // GetInnerMessage returns the innermost encapsulated DHCPv6 message. diff --git a/dhcpv6/dhcpv6message.go b/dhcpv6/dhcpv6message.go index e68284f..17f371a 100644 --- a/dhcpv6/dhcpv6message.go +++ b/dhcpv6/dhcpv6message.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "net" + "strings" "time" "github.com/insomniacslk/dhcp/iana" @@ -549,22 +550,27 @@ func (m *Message) String() string { // Summary prints all options associated with this message. func (m *Message) Summary() string { - ret := fmt.Sprintf( - "Message\n"+ - " messageType=%s\n"+ - " transactionid=%s\n", - m.MessageType, - m.TransactionID, - ) - ret += " options=[" - if len(m.Options.Options) > 0 { - ret += "\n" - } - for _, opt := range m.Options.Options { - ret += fmt.Sprintf(" %v\n", opt.String()) - } - ret += " ]\n" - return ret + return m.LongString(0) +} + +// LongString prints all options associated with this message. +func (m *Message) LongString(spaceIndent int) string { + indent := strings.Repeat(" ", spaceIndent) + + var s strings.Builder + s.WriteString("Message{\n") + s.WriteString(indent) + s.WriteString(fmt.Sprintf(" MessageType=%s\n", m.MessageType)) + s.WriteString(indent) + s.WriteString(fmt.Sprintf(" TransactionID=%s\n", m.TransactionID)) + s.WriteString(indent) + s.WriteString(" Options: ") + s.WriteString(m.Options.Options.LongString(spaceIndent + 2)) + s.WriteString("\n") + s.WriteString(indent) + s.WriteString("}") + + return s.String() } // ToBytes returns the serialized version of this message as defined by RFC diff --git a/dhcpv6/dhcpv6relay.go b/dhcpv6/dhcpv6relay.go index ace35f7..5a29c87 100644 --- a/dhcpv6/dhcpv6relay.go +++ b/dhcpv6/dhcpv6relay.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "net" + "strings" "github.com/insomniacslk/dhcp/iana" "github.com/u-root/uio/uio" @@ -100,20 +101,30 @@ func (r *RelayMessage) String() string { // Summary prints all options associated with this relay message. func (r *RelayMessage) Summary() string { - ret := fmt.Sprintf( - "RelayMessage\n"+ - " messageType=%v\n"+ - " hopcount=%v\n"+ - " linkaddr=%v\n"+ - " peeraddr=%v\n"+ - " options=%v\n", - r.Type(), - r.HopCount, - r.LinkAddr, - r.PeerAddr, - r.Options, - ) - return ret + return r.LongString(0) +} + +// LongString prints all options associated with this message. +func (r *RelayMessage) LongString(spaceIndent int) string { + indent := strings.Repeat(" ", spaceIndent) + + var s strings.Builder + s.WriteString(indent) + s.WriteString("RelayMessage{\n") + s.WriteString(indent) + s.WriteString(fmt.Sprintf(" MessageType=%s\n", r.MessageType)) + s.WriteString(indent) + s.WriteString(fmt.Sprintf(" HopCount=%d\n", r.HopCount)) + s.WriteString(indent) + s.WriteString(fmt.Sprintf(" LinkAddr=%s\n", r.LinkAddr)) + s.WriteString(indent) + s.WriteString(fmt.Sprintf(" PeerAddr=%s\n", r.PeerAddr)) + s.WriteString(indent) + s.WriteString(" Options: ") + s.WriteString(r.Options.Options.LongString(spaceIndent + 2)) + s.WriteString("\n}") + + return s.String() } // ToBytes returns the serialized version of this relay message as defined by diff --git a/dhcpv6/option_4rd.go b/dhcpv6/option_4rd.go index 317f13a..2faea25 100644 --- a/dhcpv6/option_4rd.go +++ b/dhcpv6/option_4rd.go @@ -27,6 +27,11 @@ func (op *Opt4RD) String() string { return fmt.Sprintf("%s: {Options=%v}", op.Code(), op.Options) } +// LongString returns a multi-line human-readable representation of the option +func (op *Opt4RD) LongString(indentSpace int) string { + return fmt.Sprintf("%s: Options=%v", op.Code(), op.Options.LongString(indentSpace)) +} + // ParseOpt4RD builds an Opt4RD structure from a sequence of bytes. // The input data does not include option code and length bytes func ParseOpt4RD(data []byte) (*Opt4RD, error) { diff --git a/dhcpv6/option_dhcpv4_msg.go b/dhcpv6/option_dhcpv4_msg.go index 2cf988a..ad29353 100644 --- a/dhcpv6/option_dhcpv4_msg.go +++ b/dhcpv6/option_dhcpv4_msg.go @@ -2,6 +2,7 @@ package dhcpv6 import ( "fmt" + "strings" "github.com/insomniacslk/dhcp/dhcpv4" ) @@ -28,6 +29,17 @@ func (op *OptDHCPv4Msg) String() string { return fmt.Sprintf("%s: %v", op.Code(), op.Msg) } +// LongString returns a multi-line string representation of DHCPv4 data. +func (op *OptDHCPv4Msg) LongString(indent int) string { + summary := op.Msg.Summary() + ind := strings.Repeat(" ", indent+2) + if strings.Contains(summary, "\n") { + summary = strings.Replace(summary, "\n ", "\n"+ind, -1) + } + ind = strings.Repeat(" ", indent) + return fmt.Sprintf("%s: {%v%s}", op.Code(), summary, ind) +} + // ParseOptDHCPv4Msg builds an OptDHCPv4Msg structure // from a sequence of bytes. The input data does not include option code and length // bytes. diff --git a/dhcpv6/option_iaaddress.go b/dhcpv6/option_iaaddress.go index c107b83..072ba65 100644 --- a/dhcpv6/option_iaaddress.go +++ b/dhcpv6/option_iaaddress.go @@ -63,6 +63,12 @@ func (op *OptIAAddress) String() string { op.Code(), op.IPv6Addr, op.PreferredLifetime, op.ValidLifetime, op.Options) } +// LongString returns a multi-line string representation of the OptIAAddress data. +func (op *OptIAAddress) LongString(indent int) string { + return fmt.Sprintf("%s: {IP=%v PreferredLifetime=%v ValidLifetime=%v Options=%v}", + op.Code(), op.IPv6Addr, op.PreferredLifetime, op.ValidLifetime, op.Options.LongString(indent)) +} + // ParseOptIAAddress builds an OptIAAddress structure from a sequence // of bytes. The input data does not include option code and length // bytes. diff --git a/dhcpv6/option_iapd.go b/dhcpv6/option_iapd.go index c71b0f6..6296103 100644 --- a/dhcpv6/option_iapd.go +++ b/dhcpv6/option_iapd.go @@ -74,6 +74,11 @@ func (op *OptIAPD) String() string { op.Code(), op.IaId, op.T1, op.T2, op.Options) } +// LongString returns a multi-line string representation of the OptIAPD data +func (op *OptIAPD) LongString(indentSpace int) string { + return fmt.Sprintf("%s: IAID=%#x T1=%v T2=%v Options=%v", op.Code(), op.IaId, op.T1, op.T2, op.Options.LongString(indentSpace)) +} + // ParseOptIAPD builds an OptIAPD structure from a sequence of bytes. // The input data does not include option code and length bytes. func ParseOptIAPD(data []byte) (*OptIAPD, error) { diff --git a/dhcpv6/option_nontemporaryaddress.go b/dhcpv6/option_nontemporaryaddress.go index 9232bb5..76f6f4c 100644 --- a/dhcpv6/option_nontemporaryaddress.go +++ b/dhcpv6/option_nontemporaryaddress.go @@ -97,6 +97,11 @@ func (op *OptIANA) String() string { op.Code(), op.IaId, op.T1, op.T2, op.Options) } +// LongString returns a multi-line string representation of IANA data. +func (op *OptIANA) LongString(indentSpace int) string { + return fmt.Sprintf("%s: IAID=%#x T1=%s T2=%s Options=%s", op.Code(), op.IaId, op.T1, op.T2, op.Options.LongString(indentSpace)) +} + // ParseOptIANA builds an OptIANA structure from a sequence of bytes. The // input data does not include option code and length bytes. func ParseOptIANA(data []byte) (*OptIANA, error) { diff --git a/dhcpv6/option_relaymsg.go b/dhcpv6/option_relaymsg.go index 5e1d902..216f53b 100644 --- a/dhcpv6/option_relaymsg.go +++ b/dhcpv6/option_relaymsg.go @@ -28,6 +28,11 @@ func (op *optRelayMsg) String() string { return fmt.Sprintf("%s: %v", op.Code(), op.Msg) } +// LongString returns a multi-line string representation of the relay message data. +func (op *optRelayMsg) LongString(indent int) string { + return fmt.Sprintf("%s: %v", op.Code(), op.Msg.LongString(indent)) +} + // build an optRelayMsg structure from a sequence of bytes. // The input data does not include option code and length bytes. func parseOptRelayMsg(data []byte) (*optRelayMsg, error) { diff --git a/dhcpv6/option_temporaryaddress.go b/dhcpv6/option_temporaryaddress.go index 624b4f9..4a79bac 100644 --- a/dhcpv6/option_temporaryaddress.go +++ b/dhcpv6/option_temporaryaddress.go @@ -33,6 +33,11 @@ func (op *OptIATA) String() string { return fmt.Sprintf("%s: {IAID=%#x, Options=%v}", op.Code(), op.IaId, op.Options) } +// LongString returns a multi-line string representation of IATA data. +func (op *OptIATA) LongString(indentSpace int) string { + return fmt.Sprintf("%s: IAID=%#x Options=%v", op.Code(), op.IaId, op.Options.LongString(indentSpace)) +} + // ParseOptIATA builds an OptIATA structure from a sequence of bytes. The // input data does not include option code and length bytes. func ParseOptIATA(data []byte) (*OptIATA, error) { diff --git a/dhcpv6/option_vendor_opts.go b/dhcpv6/option_vendor_opts.go index 74a4b70..11811c0 100644 --- a/dhcpv6/option_vendor_opts.go +++ b/dhcpv6/option_vendor_opts.go @@ -33,6 +33,11 @@ func (op *OptVendorOpts) String() string { return fmt.Sprintf("%s: {EnterpriseNumber=%v VendorOptions=%v}", op.Code(), op.EnterpriseNumber, op.VendorOpts) } +// LongString returns a string representation of the VendorOpts data +func (op *OptVendorOpts) LongString(indent int) string { + return fmt.Sprintf("%s: EnterpriseNumber=%v VendorOptions=%s", op.Code(), op.EnterpriseNumber, op.VendorOpts.LongString(indent)) +} + // ParseOptVendorOpts builds an OptVendorOpts structure from a sequence of bytes. // The input data does not include option code and length bytes. func ParseOptVendorOpts(data []byte) (*OptVendorOpts, error) { diff --git a/dhcpv6/options.go b/dhcpv6/options.go index 8bf1321..308fc2c 100644 --- a/dhcpv6/options.go +++ b/dhcpv6/options.go @@ -2,6 +2,7 @@ package dhcpv6 import ( "fmt" + "strings" "github.com/u-root/uio/uio" ) @@ -119,9 +120,37 @@ func ParseOption(code OptionCode, optData []byte) (Option, error) { return opt, nil } +type longStringer interface { + LongString(spaceIndent int) string +} + // Options is a collection of options. type Options []Option +// LongString prints options with indentation of at least spaceIndent spaces. +func (o Options) LongString(spaceIndent int) string { + indent := strings.Repeat(" ", spaceIndent) + var s strings.Builder + if len(o) == 0 { + s.WriteString("[]") + } else { + s.WriteString("[\n") + for _, opt := range o { + s.WriteString(indent) + s.WriteString(" ") + if ls, ok := opt.(longStringer); ok { + s.WriteString(ls.LongString(spaceIndent + 2)) + } else { + s.WriteString(opt.String()) + } + s.WriteString("\n") + } + s.WriteString(indent) + s.WriteString("]") + } + return s.String() +} + // Get returns all options matching the option code. func (o Options) Get(code OptionCode) []Option { var ret []Option |