From 58556d728126274bc06b54a48813cbb412615132 Mon Sep 17 00:00:00 2001 From: brent saner Date: Mon, 22 Jun 2026 18:51:13 -0400 Subject: [PATCH] v1.16.9 ADDED: * netx.IsPub * encodingx/hexx Rest are mostly small corrections and docs --- .githooks/pre-commit/01-docgen | 5 +- TODO | 2 + bitmask/bitmask.go | 69 +- bitmask/doc.go | 161 +- bytesx/doc.go | 6 + encodingx/binaryx/doc.go | 4 + encodingx/binaryx/funcs.go | 122 + encodingx/doc.go | 4 + encodingx/hexx/doc.go | 4 + encodingx/hexx/funcs.go | 30 + encodingx/hexx/funcs_hexstrfmtropt.go | 67 + encodingx/hexx/types.go | 16 + go.mod | 32 +- go.sum | 53 + iox/funcs_ctxio.go | 4 + iox/types.go | 12 + logging/TODO | 4 +- netx/consts.go | 10 + netx/doc.go | 4 + netx/docs.go | 4 - netx/funcs.go | 76 + netx/internal/README | 1 + netx/internal/go.mod | 20 + netx/internal/go.sum | 45 + netx/internal/main.go | 295 ++ netx/internal/main.go.orig | 147 + regexpx/TODO | 57 + stringsx/TODO | 10 + stringsx/funcs.go | 47 + tplx/sprigx/README.adoc | 1525 ++++++----- tplx/sprigx/README.html | 1775 ++++++++---- tplx/sprigx/README.md | 3277 ++++++++++++++--------- tplx/sprigx/TODO | 16 +- tplx/sprigx/_docs/includes/funcsig.adoc | 5 + tplx/sprigx/consts.go | 69 +- 35 files changed, 5492 insertions(+), 2486 deletions(-) create mode 100644 bytesx/doc.go create mode 100644 encodingx/binaryx/doc.go create mode 100644 encodingx/binaryx/funcs.go create mode 100644 encodingx/doc.go create mode 100644 encodingx/hexx/doc.go create mode 100644 encodingx/hexx/funcs.go create mode 100644 encodingx/hexx/funcs_hexstrfmtropt.go create mode 100644 encodingx/hexx/types.go create mode 100644 netx/consts.go create mode 100644 netx/doc.go delete mode 100644 netx/docs.go create mode 100644 netx/internal/README create mode 100644 netx/internal/go.mod create mode 100644 netx/internal/go.sum create mode 100644 netx/internal/main.go create mode 100644 netx/internal/main.go.orig create mode 100644 regexpx/TODO create mode 100644 tplx/sprigx/_docs/includes/funcsig.adoc diff --git a/.githooks/pre-commit/01-docgen b/.githooks/pre-commit/01-docgen index a13ed62..c51148f 100755 --- a/.githooks/pre-commit/01-docgen +++ b/.githooks/pre-commit/01-docgen @@ -67,8 +67,9 @@ for f in $(find . -type f -iname "README.adoc"); do newf="${pfx}.md" set +e - #asciidoctor -a ROOTDIR="${orig}/" -b docbook -o - "${f}" | pandoc -f docbook -t markdown_strict -o "${newf}" - asciidoctor -a ROOTDIR="${orig}/" -b html -o - "${f}" | pandoc -f html -t gfm -o "${newf}" + # --wrap=preserve or --wrap=none is required to avoid it reflowing the section titles to newlines. + #asciidoctor -a ROOTDIR="${orig}/" -b docbook -o - "${f}" | pandoc -f docbook -t markdown_strict -o "${newf}" --wrap=none + asciidoctor -a ROOTDIR="${orig}/" -b html -o - "${f}" | pandoc -f html -t gfm -o "${newf}" --wrap=none if [ $? -eq 0 ]; then echo "Generated ${newf} from ${f}" diff --git a/TODO b/TODO index 45ac5eb..ef9fe18 100644 --- a/TODO +++ b/TODO @@ -1 +1,3 @@ - validx: validator functions for https://pkg.go.dev/github.com/go-playground/validator/v10 + +- hashx? diff --git a/bitmask/bitmask.go b/bitmask/bitmask.go index 80bfdc8..ef8bb7f 100644 --- a/bitmask/bitmask.go +++ b/bitmask/bitmask.go @@ -11,11 +11,11 @@ import ( type MaskBit uint /* - NewMaskBit is a convenience function. - It will return a MaskBit with a (referenced) value of 0, so set your consts up accordingly. +NewMaskBit is a convenience function. +It will return a MaskBit with a (referenced) value of 0, so set your consts up accordingly. - It is highly recommended to set this default as a "None" flag (separate from your iotas!) - as shown in the example. +It is highly recommended to set this default as a "None" flag (separate from your iotas!) +as shown in the example. */ func NewMaskBit() (m *MaskBit) { @@ -35,26 +35,10 @@ func NewMaskBitExplicit(value uint) (m *MaskBit) { } /* - HasFlag is true if m has MaskBit flag set/enabled. +HasFlag is true if m has MaskBit flag set/enabled. - THIS WILL RETURN FALSE FOR OR'd FLAGS. - - For example: - - flagA MaskBit = 0x01 - flagB MaskBit = 0x02 - flagComposite = flagA | flagB - - m *MaskBit = NewMaskBitExplicit(uint(flagA)) - - m.HasFlag(flagComposite) will return false even though flagComposite is an OR - that contains flagA. - Use [MaskBit.IsOneOf] instead if you do not desire this behavior, - and instead want to test composite flag *membership*. - (MaskBit.IsOneOf will also return true for non-composite equality.) - - To be more clear, if MaskBit flag is a composite MaskBit (e.g. flagComposite above), - HasFlag will only return true of ALL bits in flag are also set in MaskBit m. +See the "Composite (OR'd) Flags" section in this module's +documentation for important caveats. */ func (m *MaskBit) HasFlag(flag MaskBit) (r bool) { @@ -67,19 +51,20 @@ func (m *MaskBit) HasFlag(flag MaskBit) (r bool) { } /* - IsOneOf is like a "looser" form of [MaskBit.HasFlag] - in that it allows for testing composite membership. +HasOneOf is like a "looser" form of [MaskBit.HasFlag] +in that it allows for testing composite membership. - See [MaskBit.HasFlag] for more information. +See [MaskBit.HasFlag] and the "Composite (OR'd) Flags" +section in this module's documentation for more details. - If composite is *not* an OR'd MaskBit (i.e. - it falls directly on a boundary -- 0, 1, 2, 4, 8, 16, etc.), - then IsOneOf will behave exactly like HasFlag. +If composite is *not* an OR'd MaskBit (i.e. +it falls directly on a boundary -- 0, 1, 2, 4, 8, 16, etc.), +then HasOneOf will behave exactly like [MaskBit.HasFlag]. - If m is a composite MaskBit (it usually is) and composite is ALSO a composite MaskBit, - IsOneOf will return true if ANY of the flags set in m is set in composite. +If m is a composite [MaskBit] (it usually is) and composite is ALSO a composite MaskBit, +HasOneOf will return true if ANY of the flags set in composite is set in m. */ -func (m *MaskBit) IsOneOf(composite MaskBit) (r bool) { +func (m *MaskBit) HasOneOf(composite MaskBit) (r bool) { var b MaskBit = *m @@ -89,6 +74,13 @@ func (m *MaskBit) IsOneOf(composite MaskBit) (r bool) { return } +/* +IsOneOf is the old name for [MaskBit.HasOneOf]. + +DEPRECATED: This method will be removed sometime in the future. Use [MaskBit.HasOneOf] instead. +*/ +func (m *MaskBit) IsOneOf(composite MaskBit) (r bool) { return m.HasOneOf(composite) } + // AddFlag adds MaskBit flag to m. func (m *MaskBit) AddFlag(flag MaskBit) { @@ -114,15 +106,14 @@ func (m *MaskBit) ToggleFlag(flag MaskBit) { } /* - Bytes returns the current value of a MasBit as a byte slice (big-endian). +Bytes returns the current value of a MasBit as a byte slice (big-endian). - If trim is false, b will (probably) be 4 bytes long if you're on a 32-bit size system, - and b will (probably) be 8 bytes long if you're on a 64-bit size system. You can determine - the size of the resulting slice via (math/)bits.UintSize / 8. - - If trim is true, it will trim leading null bytes (if any). This will lead to an unpredictable - byte slice length in b, but is most likely preferred for byte operations. +If trim is false, b will (probably) be 4 bytes long if you're on a 32-bit size system, +and b will (probably) be 8 bytes long if you're on a 64-bit size system. You can determine +the size of the resulting slice via (math/)bits.UintSize / 8. +If trim is true, it will trim leading null bytes (if any). This will lead to an unpredictable +byte slice length in b, but is most likely preferred for byte operations. */ func (m *MaskBit) Bytes(trim bool) (b []byte) { diff --git a/bitmask/doc.go b/bitmask/doc.go index 8f834cf..09fcc44 100644 --- a/bitmask/doc.go +++ b/bitmask/doc.go @@ -11,21 +11,84 @@ However, a [bitmask.MaskBit] is backed by a uint which (depending on your platfo "But wait, that takes up more memory though!" -Yep, but bitmasking lets you store a "boolean" AT EACH BIT - it operates on +Yep - compared to a *single boolean*. But bitmasking lets you store a "boolean" AT EACH BIT boundary - it operates on whether a bit in a byte/set of bytes at a given position is 0 or 1. -Which means on 32-bit platforms, a [MaskBit] can have up to 4294967295 "booleans" in a single value (0 to (2^32)-1). +In other words: -On 64-bit platforms, a [MaskBit] can have up to 18446744073709551615 "booleans" in a single value (0 to (2^64)-1). + type ( + OptStruct struct { + A bool + B bool + C bool + D bool + E bool + F bool + G bool + H bool + } + ) -If you tried to do that with Go bool values, that'd take up 4294967295 bytes (4 GiB) -or 18446744073709551615 bytes (16 EiB - yes, that's [exbibytes]) of RAM for 32-bit/64-bit platforms respectively. +One instance of OptStruct takes up *8 bytes* (*64 bits*). + +As a uint8 bitmask, however, it takes up exactly *one byte/8 bits*: + + type ( + Opt uint8 + ) + + const OptNone Opt = 0 + const ( + A Opt = 1 << iota // 1 + B // 2 + C // 4 + D // 8 + E // 16 + F // 32 + G // 64 + H // 128 + // Would overflow to 0: + // I + ) + +As shown, the size of an unsigned integer determines the number of bit-boundaried flags for that bitmask. + +Which means on 32-bit platforms, a [MaskBit] can have up to 32 different flags but only occupies 4 bytes of memory. + +On 64-bit platforms, a [MaskBit] can have up to 64 different flags but only occupies 8 bytes of memory. + +If you tried to do that with a struct of booleans instead, that'd occupy 32 *bytes* and 64 *bytes* respectively. + +In summary, a bitmask set occupies 1/8th the amount of memory as a set of equal number of booleans in Go. + +You can, of course, extend this even further by defining meaningful "composites", +or OR'd-combination of flags (see the "Composite Flags" section below): + + type Perms uint8 + const NoPerms Perms = 0 + const ( + PermsRead Perms = 1 << iota + PermsList + PermsUpdate + PermsCreate + PermsDelete + PermsUpdateBulk + PermsCreateBulk + PermsDeleteBulk + + // This makes it easy to add multiple permissions at once. + PermsCRUD Perms = PermsCreate | PermsRead | PermsUpdate | PermsDelete + PermsCRUDL Perms = PermsCRUD | PermsList + // And so forth. + ) "But that has to be so slow to unpack that!" -Nope. It's not using compression or anything, the CPU is just comparing bit "A" vs. bit "B" 32/64 times. That's super easy work for a CPU. +Nope. It's not using compression or anything, the CPU is just comparing bit "A" vs. bit "B" 32/64 times. +That's super easy work for a CPU. -There's a reason Doom used bitmasking for the "dmflags" value in its server configs. +There's a reason ZDoom used bitmasking for the [dmflags] value in its server configs, +and why *NIX platforms uses them for permission/type modes. # Usage @@ -34,6 +97,8 @@ To use this library, set constants like thus: package main import ( + "fmt" + "r00t2.io/goutils/bitmask" ) @@ -45,34 +110,32 @@ To use this library, set constants like thus: // ... ) - var MyMask *bitmask.MaskBit + var ( + MyMask *bitmask.MaskBit = bitmask.NewMaskBit() + ) func main() { - MyMask = bitmask.NewMaskBit() MyMask.AddFlag(OPT1) MyMask.AddFlag(OPT3) - _ = MyMask + // This would print true. + fmt.Println(MyMask.HasFlag(OPT1)) + + // As would this: + fmt.Println(MyMask.HasFlag(OPT3)) + + // But this would print false: + fmt.Println(MyMask.HasFlag(OPT2)) } -This would return true: - - MyMask.HasFlag(OPT1) - -As would this: - - MyMask.HasFlag(OPT3) - -But this would return false: - - MyMask.HasFlag(OPT2) - # Technical Caveats -TARGETING +Targeting + +When implementing, you should always set a "source" mask (e.g. MyMask, from Usage section above) +as the actual value. -When implementing, you should always set MyMask (from Usage section above) as the actual value. For example, if you are checking a permissions set for a user that has the value, say, 6 var userPerms uint = 6 // 0x0000000000000006 @@ -88,7 +151,7 @@ and your library has the following permission bits defined: PermsAdmin // 16 ) -And you want to see if the user has the PermsRead flag set, you would do: +and you want to see if the user has the PermsRead flag set, you would do: userPermMask = bitmask.NewMaskBitExplicit(userPerms) if userPermMask.HasFlag(PermsRead) { @@ -98,55 +161,65 @@ And you want to see if the user has the PermsRead flag set, you would do: NOT: userPermMask = bitmask.NewMaskBitExplicit(PermsRead) - // Nor: - // userPermMask = PermsRead - if userPermMask.HasFlag(userPerms) { + userPermMask.HasFlag(bitmask.MaskBit(userPerms)) + +NOR: + userPermMask = PermsRead + if userPermMask.HasFlag(bitmask.MaskBit(userPerms)) { // ... } This will be terribly, horribly wrong, cause incredibly unexpected results, and quite possibly cause massive security issues. Don't do it. -COMPOSITES +Remember, [MaskBit.HasFlag] (and other methods) are for comparing/modifying an +*authoritative/concrete value* with one or more *attributes*, not the other way around. -If you want to define a set of flags that are a combination of other flags, -your inclination would be to bitwise-OR them together: +Composite Flags + +If you want to define a set of flags that are a combination +(a "composite", or OR'd set) of other flags, your inclination +would be to bitwise-OR them together: const ( flagA bitmask.MaskBit = 1 << iota // 1 flagB // 2 + flagC // 4 + // ... ) const ( flagAB bitmask.MaskBit = flagA | flagB // 3 ) -Which is fine and dandy. But if you then have: +Which is fine, and the correct approach. +But if you then have: var myMask *bitmask.MaskBit = bitmask.NewMaskBit() myMask.AddFlag(flagA) -You may expect this call to [MaskBit.HasFlag]: +you may expect this call to [MaskBit.HasFlag]: myMask.HasFlag(flagAB) to be true, since flagA is "in" flagAB. + It will return false - HasFlag does strict comparisons. -It will only return true if you then ALSO do: - // This would require setting flagA first. - // The order of setting flagA/flagB doesn't matter, - // but you must have both set for HasFlag(flagAB) to return true. - myMask.AddFlag(flagB) +It would only return true if you did: -or if you do: - - // This can be done with or without additionally setting flagA. + // ... myMask.AddFlag(flagAB) -Instead, if you want to see if a mask has membership within a composite flag, -you can use [MaskBit.IsOneOf]. +or: + + // ... + myMask.AddFlag(flagA) + myMask.AddFlag(flagB) + +Instead, if you want to see if a mask has *at least one flag of* a composite flag, +you can use [MaskBit.HasOneOf]. # Other Options @@ -157,6 +230,6 @@ you may be interested in one of the following libraries: * [github.com/abice/go-enum] * [github.com/jeffreyrichter/enum/enum] -[exbibytes]: https://simple.wikipedia.org/wiki/Exbibyte +[dmflags]: https://doomwiki.org/wiki/DMFlags */ package bitmask diff --git a/bytesx/doc.go b/bytesx/doc.go new file mode 100644 index 0000000..0ec44bf --- /dev/null +++ b/bytesx/doc.go @@ -0,0 +1,6 @@ +/* +Package bytesx aims to extend functionality of the stdlib [bytes] module. + +TODO. +*/ +package bytesx diff --git a/encodingx/binaryx/doc.go b/encodingx/binaryx/doc.go new file mode 100644 index 0000000..c720517 --- /dev/null +++ b/encodingx/binaryx/doc.go @@ -0,0 +1,4 @@ +/* +Package binaryx aims to extend functionality of the stdlib [encoding/binary] module. +*/ +package binaryx diff --git a/encodingx/binaryx/funcs.go b/encodingx/binaryx/funcs.go new file mode 100644 index 0000000..1f591f3 --- /dev/null +++ b/encodingx/binaryx/funcs.go @@ -0,0 +1,122 @@ +package binaryx + +import ( + "bytes" + "encoding" + "encoding/binary" +) + +/* +Marshal provides a Golang convention marshaling function entry point +(e.g. like [encoding/json.Marshal], [encoding/xml.Marshal]) for arbitrary +binary data. + +It simply wraps [OrderedMarshal] with [encoding/binary.NativeEndian] +(which can differ from platform to platform) as the ord parameter to [OrderedMarshal]. + +If you need to use a different or explicit [encoding/binary.ByteOrder], +use [OrderedMarshal] directly instead. +*/ +func Marshal(v any) (data []byte, err error) { + + if data, err = OrderedMarshal(v, binary.NativeEndian); err != nil { + return + } + + return +} + +/* +OrderedMarshal provides a slightly more flexible Golang convention marshaling +function entry point (e.g. similar to [encoding/json.MarshalIndent], +[encoding/xml.MarshalIndent]) for arbitrary binary data. + +If v conforms to [encoding.BinaryMarshaler], then the marshal method will be called. + +Otherwise, it wraps [encoding/binary.Write] with an internal buffer using ord +as the [encoding/binary.ByteOrder] (endianness), so refer to that function +for all caveats and other details. +Note that [encoding/binary.Write] is *much* more strict than marshaling, +and requires very basic typing. + +If you have no need for a specific byte order/endianness or want to explicitly use this +system's native byte order/endianness, +use [Marshal] instead. +*/ +func OrderedMarshal(v any, ord binary.ByteOrder) (data []byte, err error) { + + var ok bool + var b binary.Marshaler + var buf *bytes.Buffer = new(bytes.Buffer) + + if b, ok = v.(encoding.BinaryMarshaler); ok { + if data, err = b.MarshalBinary(); err != nil { + return + } + return + } + + if err = binary.Write(buf, ord, v); err != nil { + return + } + + data = buf.Bytes() + + return +} + +/* +Unmarshal provides a Golang convention unmarshaling function entry point +(e.g. like [encoding/json.Unmarshal], [encoding/xml.Unmarshal]) for arbitrary +binary data. + +It simply wraps [OrderedUnmarshal] with [encoding/binary.NativeEndian] +(which can differ from platform to platform) as the ord parameter to [OrderedUnmarshal]. + +If you need to use a different or explicit [encoding/binary.ByteOrder], +use [OrderedUnmarshal] directly instead. +*/ +func Unmarshal(data []byte, v any) (err error) { + + if err = OrderedUnmarshal(data, v, binary.NativeEndian); err != nil { + return + } + + return +} + +/* +OrderedUnmarshal provides a slightly more flexible Golang convention unmarshaling +for arbitrary binary data. + +If v conforms to [encoding.BinaryUnmarshaler], then the unmarshal method will be called. + +Otherwise, it wraps [encoding/binary.Read] with an internal buffer using ord +as the [encoding/binary.ByteOrder] (endianness), so refer to that function +for all caveats and other details. +Note that [encoding/binary.Read] is *much* more strict than unmarshaling, +and requires very basic typing. + +If you have no need for a specific byte order/endianness or want to explicitly use this +system's native byte order/endianness, +use [Unmarshal] instead. +*/ +func OrderedUnmarshal(data []byte, v any, ord binary.ByteOrder) (err error) { + + var ok bool + var b encoding.BinaryUnmarshaler + var buf *bytes.Reader = bytes.NewReader(data) + + if b, ok = v.(encoding.BinaryUnmarshaler); ok { + if err = b.UnmarshalBinary(data); err != nil { + return + } + return + } + + if err = binary.Read(buf, ord, v); err != nil { + return + } + + return +} diff --git a/encodingx/doc.go b/encodingx/doc.go new file mode 100644 index 0000000..d423359 --- /dev/null +++ b/encodingx/doc.go @@ -0,0 +1,4 @@ +/* +Package encodingx aims to extend functionality of the stdlib [encoding] module. +*/ +package encodingx diff --git a/encodingx/hexx/doc.go b/encodingx/hexx/doc.go new file mode 100644 index 0000000..6fce384 --- /dev/null +++ b/encodingx/hexx/doc.go @@ -0,0 +1,4 @@ +/* +Package hexx aims to extend [encoding/hex] functionality. +*/ +package hexx diff --git a/encodingx/hexx/funcs.go b/encodingx/hexx/funcs.go new file mode 100644 index 0000000..f9d895b --- /dev/null +++ b/encodingx/hexx/funcs.go @@ -0,0 +1,30 @@ +package hexx + +import ( + `io` +) + +/* +HexString returns a custom-formatted hex representation of b. +*/ +func HexString(b []byte, opts ...hexStrFmtrOpt) (out string) { + + // TODO + + return +} + +/* +HexStringStream encodes a stream read from r and written into w. + +HexStringStream will return cleanly if r returns no more bytes or if an [io.EOF] is encountered (the [io.EOF] will not be returned). +Any other error will immediately halt reading/writing and will b returned in err. + +If w is of a fixed capacity, it must be at least 2x the size of r's capacity. +*/ +func HexStringStream(r io.Reader, w io.Writer, opts ...hexStrFmtrOpt) (read, wrtn uint64, err error) { + + // TODO + + return +} diff --git a/encodingx/hexx/funcs_hexstrfmtropt.go b/encodingx/hexx/funcs_hexstrfmtropt.go new file mode 100644 index 0000000..b21460f --- /dev/null +++ b/encodingx/hexx/funcs_hexstrfmtropt.go @@ -0,0 +1,67 @@ +package hexx + +/* +HexStrWithPrefix sets whether a prefix ("0x" by default, see [HexStrWithPrefixStr]) +*/ +func HexStrWithPrefix(pfx bool) (f hexStrFmtrOpt) { + + f = func(h *hexStrFmtr) { + if h.pfxStr == "" { + h.pfxStr = "0x" + } + h.pfx = pfx + } + + return +} + +/* +HexStrWithPrefixStr sets the prefix used if a prefix is to be included (see [HexStrWithPrefix]). + +The default is "0x". +*/ +func HexStrWithPrefixStr(pfx string) (f hexStrFmtrOpt) { return func(h *hexStrFmtr) { h.pfxStr = pfx } } + +/* +HexStrWithLower uses lowercase or uppercase hex character representation. The default is lowercase. + +To use uppercase, specify this option with lower == false. +*/ +func HexStrWithLower(lower bool) (f hexStrFmtrOpt) { return func(h *hexStrFmtr) { h.lower = lower } } + +/* +HexStrWithLeftPad specifies if left zero-padding should be used. + +The default is true. +*/ +func HexStrWithLeftPad(leftPad bool) (f hexStrFmtrOpt) { + return func(h *hexStrFmtr) { h.noLeftPad = !leftPad } +} + +/* +HexStrWithSegLeftPad specifies if left zero-padding should be used for each segment (see [HexStrWithSplit]). + +The default is true. +*/ +func HexStrWithSegLeftPad(segLeftPad bool) (f hexStrFmtrOpt) { + return func(h *hexStrFmtr) { h.noSegmentLeftPad = !segLeftPad } +} + +/* +HexStrWithSplit will split the hex string into "chunks" of numBytes bytes. + +For example: + numBytes == 0: + 0x0123456789abcdef + + numBytes == 1: + 0x01 0x23 0x45 0x67 0x89 0xab 0xcd 0xef + + numBytes == 2: + 0x0123 0x4567 0x89ab 0xcdef +*/ +func HexStrWithSplit(numBytes uint) (f hexStrFmtrOpt) { + return func(h *hexStrFmtr) { h.segmentBytes = numBytes } +} + +// TODO diff --git a/encodingx/hexx/types.go b/encodingx/hexx/types.go new file mode 100644 index 0000000..e9931d7 --- /dev/null +++ b/encodingx/hexx/types.go @@ -0,0 +1,16 @@ +package hexx + +type ( + hexStrFmtrOpt func(h *hexStrFmtr) + + hexStrFmtr struct { + pfx bool + pfxStr string + lower bool + noLeftPad bool + noSegmentLeftPad bool + segmentBytes uint + segmentSep string + newlineBytes uint + } +) diff --git a/go.mod b/go.mod index 731964a..603a222 100644 --- a/go.mod +++ b/go.mod @@ -1,35 +1,47 @@ module r00t2.io/goutils -go 1.25 +go 1.25.0 require ( github.com/Masterminds/sprig/v3 v3.3.0 github.com/coreos/go-systemd/v22 v22.7.0 github.com/davecgh/go-spew v1.1.1 github.com/google/uuid v1.6.0 - github.com/shirou/gopsutil/v4 v4.25.12 + github.com/olekukonko/tablewriter v1.1.4 + github.com/shirou/gopsutil/v4 v4.26.5 go4.org/netipx v0.0.0-20231129151722-fdeea329fbba - golang.org/x/sys v0.40.0 + golang.org/x/sys v0.46.0 r00t2.io/sysutils v1.16.2 ) require ( dario.cat/mergo v1.0.2 // indirect github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.4.0 // indirect + github.com/Masterminds/semver/v3 v3.5.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/clipperhouse/displaywidth v0.11.0 // indirect + github.com/clipperhouse/uax29/v2 v2.7.0 // indirect github.com/djherbis/times v1.6.0 // indirect - github.com/ebitengine/purego v0.9.1 // indirect + github.com/ebitengine/purego v0.10.1 // indirect + github.com/fatih/color v1.19.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect + github.com/goccy/go-json v0.10.6 // indirect github.com/huandu/xstrings v1.5.0 // indirect - github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect + github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e // indirect + github.com/mattn/go-colorable v0.1.15 // indirect + github.com/mattn/go-isatty v0.0.22 // indirect + github.com/mattn/go-runewidth v0.0.24 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect + github.com/olekukonko/errors v1.3.0 // indirect + github.com/olekukonko/ll v0.1.8 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/spf13/cast v1.10.0 // indirect - github.com/tklauser/go-sysconf v0.3.16 // indirect - github.com/tklauser/numcpus v0.11.0 // indirect + github.com/tklauser/go-sysconf v0.4.0 // indirect + github.com/tklauser/numcpus v0.12.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - golang.org/x/crypto v0.47.0 // indirect - golang.org/x/sync v0.19.0 // indirect + golang.org/x/crypto v0.53.0 // indirect + golang.org/x/sync v0.21.0 // indirect ) diff --git a/go.sum b/go.sum index 34e829b..52e2f44 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,16 @@ github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJ github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/semver/v3 v3.5.0 h1:kQceYJfbupGfZOKZQg0kou0DgAKhzDg2NZPAwZ/2OOE= +github.com/Masterminds/semver/v3 v3.5.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8= +github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= +github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= +github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= github.com/coreos/go-systemd/v22 v22.7.0 h1:LAEzFkke61DFROc7zNLX/WA2i5J8gYqe0rSj9KI28KA= github.com/coreos/go-systemd/v22 v22.7.0/go.mod h1:xNUYtjHu2EDXbsxz1i41wouACIwT7Ybq9o0BQhMwD0w= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -14,11 +22,19 @@ github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c= github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0= github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A= github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU= +github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/ebitengine/purego v0.10.1 h1:dewVBCBT2GaMu1SrNTYxQhgQBethzfhiwvZiLGP/qyY= +github.com/ebitengine/purego v0.10.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= +github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU= +github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -31,10 +47,28 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 h1:PwQumkgq4/acIiZhtifTV5OUqqiP82UAl0h87xj/l9k= github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= +github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 h1:PTw+yKnXcOFCR6+8hHTyWBeQ/P4Nb7dd4/0ohEcWQuM= +github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= +github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e h1:Q6MvJtQK/iRcRtzAscm/zF23XxJlbECiGPyRicsX+Ak= +github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= +github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= +github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= +github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU= +github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc= +github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0= +github.com/olekukonko/errors v1.3.0 h1:teJvgLGUEqMzBUms+Dj3/3szNqCG/Jdw9iDbum8fR6U= +github.com/olekukonko/errors v1.3.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= +github.com/olekukonko/ll v0.1.8 h1:ysHCJRGHYKzmBSdz9w5AySztx7lG8SQY+naTGYUbsz8= +github.com/olekukonko/ll v0.1.8/go.mod h1:RPRC6UcscfFZgjo1nulkfMH5IM0QAYim0LfnMvUuozw= +github.com/olekukonko/tablewriter v1.1.4 h1:ORUMI3dXbMnRlRggJX3+q7OzQFDdvgbN9nVWj1drm6I= +github.com/olekukonko/tablewriter v1.1.4/go.mod h1:+kedxuyTtgoZLwif3P1Em4hARJs+mVnzKxmsCL/C5RY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= @@ -43,6 +77,10 @@ github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZV github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/shirou/gopsutil/v4 v4.25.12 h1:e7PvW/0RmJ8p8vPGJH4jvNkOyLmbkXgXW4m6ZPic6CY= github.com/shirou/gopsutil/v4 v4.25.12/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU= +github.com/shirou/gopsutil/v4 v4.26.2 h1:X8i6sicvUFih4BmYIGT1m2wwgw2VG9YgrDTi7cIRGUI= +github.com/shirou/gopsutil/v4 v4.26.2/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= +github.com/shirou/gopsutil/v4 v4.26.5 h1:RPcBXkpz7kOj9PqGFQOlBPZHsyaPvPVQc098y9RmCNM= +github.com/shirou/gopsutil/v4 v4.26.5/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= @@ -51,22 +89,37 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI= +github.com/tklauser/go-sysconf v0.4.0 h1:7H0uAN+7RkwWRaxhYXDLqa5V3LPrJeV8wmD9dRUgPQU= +github.com/tklauser/go-sysconf v0.4.0/go.mod h1:8mTNWyog7H+MpKijp4VmKJAd2bbYQ2zuUwkYRbUArPI= github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw= github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ= +github.com/tklauser/numcpus v0.12.0 h1:NR85qdvHA9pFse3x3weVZ0r0ST8R6l5RHbZrlRaqob4= +github.com/tklauser/numcpus v0.12.0/go.mod h1:ABHeXzJnr/qqwguhClkZKT1/8VABcYrsyUiUGobwWJg= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= +golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= +golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= +golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= +golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= +golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +r00t2.io/sysutils v1.16.2 h1:wI01UwZ/bXn/lzBiCpqDmzZCOWiK87kz04SB4xRw+W0= r00t2.io/sysutils v1.16.2/go.mod h1:iXK+ALOwIdRKjAJIE5USlkZ669SVDHBNNuYhunsznH8= diff --git a/iox/funcs_ctxio.go b/iox/funcs_ctxio.go index fc3d0d3..c4f1ef5 100644 --- a/iox/funcs_ctxio.go +++ b/iox/funcs_ctxio.go @@ -26,6 +26,10 @@ func (c *CtxIO) GetChunkLen() (size uint) { return c.l.GetChunkLen() } +func (c *CtxIO) Len() (unread int) { + return c.buf.Len() +} + func (c *CtxIO) Read(p []byte) (n int, err error) { var nr int64 diff --git a/iox/types.go b/iox/types.go index 17ddd90..6b857ce 100644 --- a/iox/types.go +++ b/iox/types.go @@ -147,6 +147,17 @@ type ( ContextReader ContextWriter } + + /* + LenReader allows one to read bytes (conforming to [io.Reader]), + and also provides a Len() method which returns an int of remaining unread bytes. + [bytes.Buffer] and [bytes.Reader] conforms to this, but see [CtxIO] for + a package-provided type. + */ + LenReader interface { + io.Reader + Len() (unread int) + } ) type ( @@ -172,6 +183,7 @@ type ( * [ChunkReadWriter] * [ContextReadWriter] * [SizedCopyBufferer] + * [LenReader] Unlike [XIO], it must be non-nil (see [NewCtxIO]) since it maintains state (though technically, one does not need to call [NewCtxIO] if they call diff --git a/logging/TODO b/logging/TODO index 1b026a0..c512059 100644 --- a/logging/TODO +++ b/logging/TODO @@ -1,3 +1,5 @@ +- ScopedLogger, take an io.Writer for each log level + - logging probably needs mutexes - macOS support beyond the legacy NIX stuff. it apparently uses something called "ULS", "Unified Logging System". @@ -16,7 +18,7 @@ -- log.LlongFile and log.Lshortfile flags don't currently work properly for StdLogger/FileLogger; they refer to the file in logging package rather than the caller. -- ZeroLog seems to be able to do it, take a peek there. -- StdLogger2; where stdout and stderr are both logged to depending on severity level. +- StdLvlLogger; where stdout and stderr are both logged to depending on severity level. - make configurable via OR bitmask - Suport remote loggers? (eventlog, syslog, journald) diff --git a/netx/consts.go b/netx/consts.go new file mode 100644 index 0000000..4f5c113 --- /dev/null +++ b/netx/consts.go @@ -0,0 +1,10 @@ +package netx + +import ( + `net/netip` +) + +var ( + ip4In6Legacy netip.Prefix = netip.MustParsePrefix("::/96") + ip4In6Modern netip.Prefix = netip.MustParsePrefix("::ffff:0:0/96") +) diff --git a/netx/doc.go b/netx/doc.go new file mode 100644 index 0000000..9178273 --- /dev/null +++ b/netx/doc.go @@ -0,0 +1,4 @@ +/* +Package netx includes extensions to the stdlib [net] module. +*/ +package netx diff --git a/netx/docs.go b/netx/docs.go deleted file mode 100644 index 584e11d..0000000 --- a/netx/docs.go +++ /dev/null @@ -1,4 +0,0 @@ -/* -Package netx includes extensions to the stdlib `net` module. -*/ -package netx diff --git a/netx/funcs.go b/netx/funcs.go index 5aea8f8..2c7216c 100644 --- a/netx/funcs.go +++ b/netx/funcs.go @@ -455,6 +455,82 @@ func IsPrefixNet(s string) (isNet bool) { return } +/* +IsPublic returns true if ALL of the following conditions are *true* for ip: + + * [net/netip.Addr.IsGlobalUnicast] + * [net/netip.Addr.IsValid] + * (IPv4) Is not in 192.0.2.0/24, 198.51.100.0/24, or 203.0.113.0/24 ([RFC 5737]) + * (IPv6) Is not in 2001:db8::/32 or 3fff::/20 ([RFC 3849], [RFC 9637]) + +AND ALL of the following conditions are *false* for ip: + + * [net/netip.Addr.IsLinkLocalMulticast] + * [net/netip.Addr.IsInterfaceLocalMulticast] + * [net/netip.Addr.IsLinkLocalUnicast] + * [net/netip.Addr.IsMulticast] + * [net/netip.Addr.IsLoopback] + * [net/netip.Addr.IsPrivate] + * [net/netip.Addr.IsUnspecified] + +4-in-6 addresses (::0:0/96, "IPv4-Compatible IPv6 Address" [RFC 4291 § 2.5.5.1] (Legacy/Obsolete); +::ffff:0:0/96, "IPv4-Mapped IPv6" [RFC 4291 § 2.5.5.2]) will be internally +"unwrapped" back to native IPv4 before performing conditional checks. + +[RFC 5737]: https://datatracker.ietf.org/doc/html/rfc5737 +[RFC 4291 § 2.5.5.1]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.1 +[RFC 4291 § 2.5.5.2]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2 +[RFC 3849]: https://datatracker.ietf.org/doc/html/rfc3849 +[RFC 9637]: https://datatracker.ietf.org/doc/html/rfc9637 +*/ +func IsPublic(ip netip.Addr) (isPub bool) { + + var err error + var v bool + var addr netip.Addr + + // Clone to avoid modification to the passed in value. + if addr, err = netip.ParseAddr(ip.String()); err != nil { + return + } + addr = addr.Unmap() + + // Short-circuit on invalid first to avoid any possible logic oddness. + if !addr.IsValid() { + return + } + // Following must be FALSE + for _, v = range []bool{ + addr.IsLinkLocalMulticast(), + addr.IsInterfaceLocalMulticast(), + addr.IsLinkLocalUnicast(), + addr.IsMulticast(), + addr.IsLoopback(), + addr.IsPrivate(), + addr.IsUnspecified(), + // these are in the FALSE to keep syntax pattern but it's cleaner to doc as if it's a ! in TRUE. + ip4In6Legacy.Contains(ip), + ip4In6Modern.Contains(ip), + } { + if v { + return + } + } + // Following must be TRUE + for _, v = range []bool{ + addr.IsGlobalUnicast(), + } { + if !v { + return + } + } + + // All conditions pass + isPub = true + + return +} + /* Mask4ToCidr converts an IPv4 netmask *in bitmask form* to a CIDR prefix size/bit size/bit length. diff --git a/netx/internal/README b/netx/internal/README new file mode 100644 index 0000000..56d8aa1 --- /dev/null +++ b/netx/internal/README @@ -0,0 +1 @@ +This is mostly just for generating some reference. It's not really intended for public consumption. diff --git a/netx/internal/go.mod b/netx/internal/go.mod new file mode 100644 index 0000000..ff63f76 --- /dev/null +++ b/netx/internal/go.mod @@ -0,0 +1,20 @@ +module r00t2.io/goutils/netx/internal + +go 1.26.4 + +require github.com/olekukonko/tablewriter v1.1.4 + +require ( + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/clipperhouse/displaywidth v0.11.0 // indirect + github.com/clipperhouse/uax29/v2 v2.7.0 // indirect + github.com/fatih/color v1.19.0 // indirect + github.com/goccy/go-json v0.10.6 // indirect + github.com/mattn/go-colorable v0.1.15 // indirect + github.com/mattn/go-isatty v0.0.22 // indirect + github.com/mattn/go-runewidth v0.0.24 // indirect + github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect + github.com/olekukonko/errors v1.3.0 // indirect + github.com/olekukonko/ll v0.1.8 // indirect + golang.org/x/sys v0.46.0 // indirect +) diff --git a/netx/internal/go.sum b/netx/internal/go.sum new file mode 100644 index 0000000..368040d --- /dev/null +++ b/netx/internal/go.sum @@ -0,0 +1,45 @@ +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/clipperhouse/displaywidth v0.10.0 h1:GhBG8WuerxjFQQYeuZAeVTuyxuX+UraiZGD4HJQ3Y8g= +github.com/clipperhouse/displaywidth v0.10.0/go.mod h1:XqJajYsaiEwkxOj4bowCTMcT1SgvHo9flfF3jQasdbs= +github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8= +github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= +github.com/clipperhouse/uax29/v2 v2.6.0 h1:z0cDbUV+aPASdFb2/ndFnS9ts/WNXgTNNGFoKXuhpos= +github.com/clipperhouse/uax29/v2 v2.6.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= +github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= +github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= +github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= +github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU= +github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= +github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= +github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= +github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU= +github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc= +github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0= +github.com/olekukonko/errors v1.2.0 h1:10Zcn4GeV59t/EGqJc8fUjtFT/FuUh5bTMzZ1XwmCRo= +github.com/olekukonko/errors v1.2.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= +github.com/olekukonko/errors v1.3.0 h1:teJvgLGUEqMzBUms+Dj3/3szNqCG/Jdw9iDbum8fR6U= +github.com/olekukonko/errors v1.3.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= +github.com/olekukonko/ll v0.1.6 h1:lGVTHO+Qc4Qm+fce/2h2m5y9LvqaW+DCN7xW9hsU3uA= +github.com/olekukonko/ll v0.1.6/go.mod h1:NVUmjBb/aCtUpjKk75BhWrOlARz3dqsM+OtszpY4o88= +github.com/olekukonko/ll v0.1.8 h1:ysHCJRGHYKzmBSdz9w5AySztx7lG8SQY+naTGYUbsz8= +github.com/olekukonko/ll v0.1.8/go.mod h1:RPRC6UcscfFZgjo1nulkfMH5IM0QAYim0LfnMvUuozw= +github.com/olekukonko/tablewriter v1.1.4 h1:ORUMI3dXbMnRlRggJX3+q7OzQFDdvgbN9nVWj1drm6I= +github.com/olekukonko/tablewriter v1.1.4/go.mod h1:+kedxuyTtgoZLwif3P1Em4hARJs+mVnzKxmsCL/C5RY= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= diff --git a/netx/internal/main.go b/netx/internal/main.go new file mode 100644 index 0000000..2631a95 --- /dev/null +++ b/netx/internal/main.go @@ -0,0 +1,295 @@ +package main + +import ( + "bytes" + "fmt" + "log" + "net/netip" + "strconv" + "strings" + + "github.com/olekukonko/tablewriter" + "github.com/olekukonko/tablewriter/tw" +) + +const ( + sectBordChar string = "#" + sectBordWdth int = 2 + sectSpcPad int = 1 + + sectSidePad int = sectBordWdth + sectSpcPad + sectBothPad int = sectSidePad * 2 +) + +type ( + IpInfo struct { + // Desc string + Index int + // IP netip.Addr + Is4 bool + Is4In6 bool + Is6 bool + IsGlobalUnicast bool + IsLinkLocalUnicast bool + IsInterfaceLocalMulticast bool + IsLinkLocalMulticast bool + IsMulticast bool + IsLoopback bool + IsPrivate bool + IsUnspecified bool + IsValid bool + } +) + +var ( + datHdrsFunc []string = []string{ + "-", + ".Is4", ".Is4In6()", ".Is6()", + ".IsGlobalUnicast()", ".IsLinkLocalUnicast()", + ".IsInterfaceLocalMulticast()", ".IsLinkLocalMulticast()", ".IsMulticast()", + ".IsLoopback()", + ".IsPrivate()", + ".IsUnspecified()", ".IsValid()", + } + + datHdrsKey []string = []string{ + "Address Index (See Fig. 3)", + "IPv4", "4-in-6", "IPv6", + "Global Unicast", "Link-Local Unicast", + "Interface Local Multicast", "Link-Local Multicast", "Multicast", + "Loopback", + "Private/LAN", + "\"Unspecified\" Address", "Valid Address", + } + + datHdrsShort = []string{ + "IDX", + "4", "6(4)", "6", + "GU", "LLU", + "ILM", "LLM", "M", + "LO", + "P", + "U", "V", + } + + exampleAddrs [][2]string = [][2]string{ + [2]string{"IPv4", "203.0.113.10"}, // RFC 5737 address (https://datatracker.ietf.org/doc/html/rfc5737) + [2]string{"IPv4 Unspecified", "0.0.0.0"}, // Generally used to represent all of IPv4 address space + [2]string{"IPv4 Global Unicast", "173.230.132.76"}, // r00t2.io + [2]string{"IPv4 Multicast (All) (RFC 1112 § 4)", "224.0.0.1"}, // Should encompass all the multicast below. 224.0.0.0 is reserved. + [2]string{"IPv4 Multicast (Reserved) (RFC 1112 § 4)", "224.0.0.0"}, // Reserved per RFC but it should still report multicast. + [2]string{"IPv4 Multicast (Link-Local Multicast/Local Network Control Block) (RFC 5771 § 4)", "224.0.0.18"}, // https://datatracker.ietf.org/doc/html/rfc5771#section-4 (VRRP multicast addr) + [2]string{"IPv4 Multicast (Internetwork Control Block) (RFC 5771 § 5)", "224.0.1.68"}, // https://datatracker.ietf.org/doc/html/rfc5771#section-5 (mdhcpdiscover, RFC 2730) + [2]string{"IPv4 Multicast (AD-HOC I) (RFC 5771 § 6)", "224.0.2.10"}, // https://datatracker.ietf.org/doc/html/rfc5771#section-6 + [2]string{"IPv4 Multicast (SDP/SAP) (RFC 5771 § 7)", "224.2.0.10"}, // https://datatracker.ietf.org/doc/html/rfc5771#section-7 + [2]string{"IPv4 Multicast (AD-HOC II) (RFC 5771 § 6)", "224.3.0.10"}, // (above) + [2]string{"IPv4 Multicast (Source-Specific) (RFC 5771 § 8)", "232.0.0.10"}, // https://datatracker.ietf.org/doc/html/rfc5771#section-8 + [2]string{"IPv4 Multicast (GLOP) (RFC 5771 § 9)", "233.0.0.10"}, // https://datatracker.ietf.org/doc/html/rfc5771#section-9 + [2]string{"IPv4 Multicast (AD-HOC III) (RFC 5771 § 6)", "233.252.0.10"}, // (above) + [2]string{"IPv4 Multicast (Administrative) (RFC 5771 § 10)", "239.0.0.10"}, // https://datatracker.ietf.org/doc/html/rfc5771#section-10 + [2]string{"IPv4 Link-Local Unicast (RFC 3927 § 2.1)", "169.254.1.10"}, // https://datatracker.ietf.org/doc/html/rfc3927#section-2.1 + [2]string{"IPv4 Loopback", "127.0.1.10"}, // It's actually 127/8. Cannot believe how many people do not know this. + [2]string{"IPv4 Private (RFC 1918)", "10.0.0.10"}, // https://datatracker.ietf.org/doc/html/rfc1918 + [2]string{"4-in-6 (RFC 4291 § 2.5.5.1)", "::203.0.113.10"}, // https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.1 + [2]string{"4-in-6 (RFC 4291 § 2.5.5.1) (Native)", "::cb00:710a"}, // "" + [2]string{"4-in-6 (RFC 4291 § 2.5.5.2)", "::ffff:203.0.113.10"}, // https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2 + [2]string{"4-in-6 (RFC 4291 § 2.5.5.2) (Native)", "::ffff:cb00:710a"}, // "" + [2]string{"IPv6", "2001:db8::cb00:710a"}, // RFC 3849 (https://datatracker.ietf.org/doc/html/rfc3849) / RFC 9637 (https://datatracker.ietf.org/doc/html/rfc9637) address + [2]string{"IPv6 Unspecified", "::"}, // Generally used to represent all of IPv6 address space + [2]string{"IPv6 Global Unicast", "2600:3c02::f03c:91ff:fe93:c0a7"}, // r00t2.io + [2]string{"IPv6 Multicast (RFC 4291 § 2.7.1) (Reserved Net)", "ff00::"}, // https://datatracker.ietf.org/doc/html/rfc4291#section-2.7.1 + [2]string{"IPv6 Multicast (RFC 4291 § 2.7.1) (Reserved)", "ff00::1"}, // "" + [2]string{"IPv6 Multicast (RFC 4291 § 2.7.1) (All Nodes) (Interface-Local)", "ff01::1"}, // "" + [2]string{"IPv6 Multicast (RFC 4291 § 2.7.1) (All Nodes) (Link-Local)", "ff02::1"}, // "" + [2]string{"IPv6 Multicast (RFC 4291 § 2.7.1) (All Routers) (Interface-Local)", "ff01::2"}, // "" + [2]string{"IPv6 Multicast (RFC 4291 § 2.7.1) (All Routers) (Link-Local)", "ff02::2"}, // "" + [2]string{"IPv6 Multicast (RFC 4291 § 2.7.1) (All Routers) (Admin-Local)", "ff04::2"}, // "" + [2]string{"IPv6 Multicast (RFC 4291 § 2.7.1) (All Routers) (Site-Local)", "ff05::2"}, // "" + [2]string{"IPv6 Multicast (RFC 4291 § 2.7.1) (All Routers) (Org-Local)", "ff08::2"}, // "" + [2]string{"IPv6 Multicast (RFC 4291 § 2.7.1) (All Routers) (Internet/Global)", "ff0e::2"}, // "" + [2]string{"IPv6 Multicast (RFC 4291 § 2.7.1) (Solicited Node)", "ff02::1:ff00:10"}, // "" + [2]string{"IPv6 Link-Local Unicast (RFC 4291 § 2.5.6)", "fe80::cb00:710a"}, // https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.6 + [2]string{"IPv6 Loopback", "::1"}, // It's explicitly always a /128 with the address ::1 per RFC 4291 § 2.5.3. + [2]string{"IPv6 Private (Unique-Local Addresses) (RFC 4193) (Reserved)", "fc00::10"}, // https://datatracker.ietf.org/doc/html/rfc4193 + [2]string{"IPv6 Private (Unique-Local Addresses) (RFC 4193) (Valid)", "fd00::10"}, // "" + } + + descs []string = make([]string, len(exampleAddrs)) + ips []netip.Addr = make([]netip.Addr, len(exampleAddrs)) + + sectSep string = "\n" + strings.Repeat("-", 80) + "\n" +) + +func genHdr(sectNm string) (s string) { + + // Wish I finished stringsx.Banner at time of writing this... + var fillLen int = sectBothPad + len(sectNm) + + s = fmt.Sprintf( + "%s\n"+ // top border + // begin title line + "%-*s"+ // left-justify/right-pad + "%s"+ // sectNm text + "%[2]*[3]s\n"+ // one-indexed; repeat pad num and pad str from left border as right border + // end title line + "%[1]s\n", // bottom border + strings.Repeat(sectBordChar, fillLen), // top and bottom (bottom uses index) + sectSidePad, strings.Repeat(sectBordChar, sectBordWdth), // title left and right borders (right uses index) + sectNm, // title text + ) + + return +} + +func main() { + + var err error + var idx int + var s string + var desc string + var pair [2]string + var buf *bytes.Buffer = new(bytes.Buffer) + + var tbl *tablewriter.Table = tablewriter.NewTable( + buf, + tablewriter.WithConfig( + tablewriter.Config{ + Header: tw.CellConfig{ + Formatting: tw.CellFormatting{ + AutoFormat: tw.Off, + }, + }, + }, + ), + // requires .Batch(), and the autoheader forces all caps. + // https://github.com/olekukonko/tablewriter/issues/143 + // https://github.com/olekukonko/tablewriter/issues/190 + /* + tablewriter.WithBehavior( + tw.Behavior{ + Structs: tw.Struct{ + AutoHeader: tw.On, + }, + }, + ), + */ + tablewriter.WithRendition( + tw.Rendition{ + Settings: tw.Settings{ + Separators: tw.Separators{BetweenRows: tw.On}, + }, + }, + ), + ) + + defer func() { + var tErr error + if tbl != nil { + if tErr = tbl.Close(); tErr != nil { + log.Printf("Error closing table: %v", tErr) + } + } + }() + + buf.WriteString(genHdr("Fig. 1: Address Evaluations")) + buf.WriteString("(See Fig. 2 for a key of header symbols to names)\n\n") + + tbl.Header(datHdrsShort) + for idx, pair = range exampleAddrs { + desc, s = pair[0], pair[1] + descs[idx] = desc + if ips[idx], err = netip.ParseAddr(s); err != nil { + log.Panicln(err) + } + // Currently no way to skip cols etc. https://github.com/olekukonko/tablewriter/issues/317 + // rows[idx] = IpInfo{ + if err = tbl.Append( + IpInfo{ + // Desc: desc, + Index: idx, + // IP: ip, + Is4: ips[idx].Is4(), + Is4In6: ips[idx].Is4In6(), + Is6: ips[idx].Is6(), + IsGlobalUnicast: ips[idx].IsGlobalUnicast(), + IsLinkLocalUnicast: ips[idx].IsLinkLocalUnicast(), + IsInterfaceLocalMulticast: ips[idx].IsInterfaceLocalMulticast(), + IsLinkLocalMulticast: ips[idx].IsLinkLocalMulticast(), + IsMulticast: ips[idx].IsMulticast(), + IsLoopback: ips[idx].IsLoopback(), + IsPrivate: ips[idx].IsPrivate(), + IsUnspecified: ips[idx].IsUnspecified(), + IsValid: ips[idx].IsValid(), + }, + ); err != nil { + log.Panicln(err) + } + } + /* + if err = tbl.Bulk(rows); err != nil { + log.Panicln(err) + } + */ + if err = tbl.Render(); err != nil { + log.Panicln(err) + } + + buf.WriteString(sectSep) + buf.WriteString(genHdr("Fig. 2: Headers Key for Fig. 1")) + tbl.Reset() + tbl.Header("Symbol", "Description", "net/netip.Addr Method") + for idx = range datHdrsKey { + if err = tbl.Append( + []string{ + datHdrsShort[idx], + datHdrsKey[idx], + datHdrsFunc[idx], + }, + ); err != nil { + log.Panicln(err) + } + } + if err = tbl.Render(); err != nil { + log.Panicln(err) + } + + buf.WriteString(sectSep) + buf.WriteString(genHdr("Fig. 3: Test/Example IP Address Reference/Lookup for Fig. 1")) + buf.WriteString("(See Fig. 4 for Descriptions/Detailed Information)\n\n") + tbl.Reset() + tbl.Header("Index", "Address (Raw)", "Address (Parsed)") + for idx = range exampleAddrs { + if err = tbl.Append( + []string{ + strconv.Itoa(idx), + exampleAddrs[idx][1], + ips[idx].String(), + }, + ); err != nil { + log.Panicln(err) + } + } + if err = tbl.Render(); err != nil { + log.Panicln(err) + } + + buf.WriteString(sectSep) + buf.WriteString(genHdr("Fig. 4: Extended Information for Fig. 3")) + tbl.Reset() + tbl.Header("Index", "Description") + for idx = range exampleAddrs { + if err = tbl.Append( + []string{ + strconv.Itoa(idx), + descs[idx], + }, + ); err != nil { + log.Panicln(err) + } + } + if err = tbl.Render(); err != nil { + log.Panicln(err) + } + + fmt.Println(buf.String()) +} diff --git a/netx/internal/main.go.orig b/netx/internal/main.go.orig new file mode 100644 index 0000000..9ce196e --- /dev/null +++ b/netx/internal/main.go.orig @@ -0,0 +1,147 @@ +package main + +import ( + "log" + "maps" + "net/netip" + `os` + "slices" + + "github.com/olekukonko/tablewriter" + `github.com/olekukonko/tablewriter/tw` +) + +type ( + IpInfo struct { + Desc string `r:"-"` + IP netip.Addr `r:"-"` + Is4 bool + Is4In6 bool + Is6 bool + IsGlobalUnicast bool + IsInterfaceLocalMulticast bool + IsLinkLocalMulticast bool + IsLinkLocalUnicast bool + IsLoopback bool + IsMulticast bool + IsPrivate bool + IsUnspecified bool + IsValid bool + } +) + +func main() { + + var err error + var s string + var idx int + var desc string + var ip netip.Addr + var rows []IpInfo + /* + var typ reflect.Type + var val reflect.Value + var fieldVal reflect.Value + var field reflect.StructField + */ + var exampleAddrs map[string]string + var tbl *tablewriter.Table = tablewriter.NewTable( + os.Stdout, + tablewriter.WithBehavior( + tw.Behavior{ + Structs: tw.Struct{ + AutoHeader: tw.On, + }, + }, + ), + tablewriter.WithRendition( + tw.Rendition{ + Settings: tw.Settings{ + Separators: tw.Separators{BetweenRows: tw.On}, + }, + }, + ), + ) + + defer func() { + var tErr error + if tbl != nil { + if tErr = tbl.Close(); tErr != nil { + log.Printf("Error closing table: %v", tErr) + } + } + }() + + exampleAddrs = map[string]string{ + "IPv4": "203.0.113.10", // RFC 5737 address (https://datatracker.ietf.org/doc/html/rfc5737) + "IPv4 Unspecified": "0.0.0.0", + "IPv4 Global Unicast": "173.230.132.76", // r00t2.io + "IPv4 Multicast (All) (RFC 1112 § 4)": "224.0.0.1", // Should encompass all the multicast below. 224.0.0.0 is reserved. + "IPv4 Multicast (Reserved) (RFC 1112 § 4)": "224.0.0.0", // Reserved per RFC but it should still report multicast. + "IPv4 Multicast (Link-Local Multicast/Local Network Control Block) (RFC 5771 § 4)": "224.0.0.18", // https://datatracker.ietf.org/doc/html/rfc5771#section-4 (VRRP multicast addr) + "IPv4 Multicast (Internetwork Control Block) (RFC 5771 § 5)": "224.0.1.68", // https://datatracker.ietf.org/doc/html/rfc5771#section-5 (mdhcpdiscover, RFC 2730) + "IPv4 Multicast (AD-HOC I) (RFC 5771 § 6)": "224.0.2.10", // https://datatracker.ietf.org/doc/html/rfc5771#section-6 + "IPv4 Multicast (SDP/SAP) (RFC 5771 § 7)": "224.2.0.10", // https://datatracker.ietf.org/doc/html/rfc5771#section-7 + "IPv4 Multicast (AD-HOC II) (RFC 5771 § 6)": "224.3.0.10", // (above) + "IPv4 Multicast (Source-Specific) (RFC 5771 § 8)": "232.0.0.10", // https://datatracker.ietf.org/doc/html/rfc5771#section-8 + "IPv4 Multicast (GLOP) (RFC 5771 § 9)": "233.0.0.10", // https://datatracker.ietf.org/doc/html/rfc5771#section-9 + "IPv4 Multicast (AD-HOC III) (RFC 5771 § 6)": "233.252.0.10", // (above) + "IPv4 Multicast (Administrative) (RFC 5771 § 10)": "239.0.0.10", // https://datatracker.ietf.org/doc/html/rfc5771#section-10 + "IPv4 Link-Local Unicast (RFC 3927 § 2.1)": "169.254.1.10", // https://datatracker.ietf.org/doc/html/rfc3927#section-2.1 + "IPv4 Loopback": "127.0.1.10", // It's actually 127/8. Cannot believe how many people do not know this. + "IPv4 Private (RFC 1918)": "10.0.0.10", // https://datatracker.ietf.org/doc/html/rfc1918 + "4-in-6 (RFC 4291 § 2.5.5.1)": "::203.0.113.10", // https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.1 + "4-in-6 (RFC 4291 § 2.5.5.1) (Native)": "::cb00:710a", // "" + "4-in-6 (RFC 4291 § 2.5.5.2)": "::ffff:203.0.113.10", // https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2 + "4-in-6 (RFC 4291 § 2.5.5.2) (Native)": "::ffff:cb00:710a", // "" + "IPv6": "2001:db8::cb00:710a", // RFC 3849 (https://datatracker.ietf.org/doc/html/rfc3849) / RFC 9637 (https://datatracker.ietf.org/doc/html/rfc9637) address + "IPv6 Unspecified": "::", + "IPv6 Global Unicast": "2600:3c02::f03c:91ff:fe93:c0a7", // r00t2.io + "IPv6 Multicast (RFC 4291 § 2.7.1) (Reserved Net)": "ff00::", // https://datatracker.ietf.org/doc/html/rfc4291#section-2.7.1 + "IPv6 Multicast (RFC 4291 § 2.7.1) (Reserved)": "ff00::1", // "" + "IPv6 Multicast (RFC 4291 § 2.7.1) (All Nodes) (Interface-Local)": "ff01::1", // "" + "IPv6 Multicast (RFC 4291 § 2.7.1) (All Nodes) (Link-Local)": "ff02::1", // "" + "IPv6 Multicast (RFC 4291 § 2.7.1) (All Routers) (Interface-Local)": "ff01::2", // "" + "IPv6 Multicast (RFC 4291 § 2.7.1) (All Routers) (Link-Local)": "ff02::2", // "" + "IPv6 Multicast (RFC 4291 § 2.7.1) (All Routers) (Admin-Local)": "ff04::2", // "" + "IPv6 Multicast (RFC 4291 § 2.7.1) (All Routers) (Site-Local)": "ff05::2", // "" + "IPv6 Multicast (RFC 4291 § 2.7.1) (All Routers) (Org-Local)": "ff08::2", // "" + "IPv6 Multicast (RFC 4291 § 2.7.1) (All Routers) (Internet/Global)": "ff0e::2", // "" + "IPv6 Multicast (RFC 4291 § 2.7.1) (Solicited Node)": "ff02::1:ff00:10", // "" + "IPv6 Link-Local Unicast (RFC 4291 § 2.5.6)": "fe80::cb00:710a", // https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.6 + "IPv6 Loopback": "::1", // It's explicitly always a /128 with the address ::1 per RFC 4291 § 2.5.3. + "IPv6 Private (Unique-Local Addresses) (RFC 4193) (Reserved)": "fc00::10", // https://datatracker.ietf.org/doc/html/rfc4193 + "IPv6 Private (Unique-Local Addresses) (RFC 4193) (Valid)": "fd00::10", // "" + } + rows = make([]IpInfo, len(exampleAddrs)) + + for idx, desc = range slices.Sorted(maps.Keys(exampleAddrs)) { + s = exampleAddrs[desc] + if ip, err = netip.ParseAddr(s); err != nil { + log.Panicln(err) + } + // Currently no way to skip cols etc. https://github.com/olekukonko/tablewriter/issues/317 + rows[idx] = IpInfo{ + Desc: desc, + IP: ip, + Is4: ip.Is4(), + Is4In6: ip.Is4In6(), + Is6: ip.Is6(), + IsGlobalUnicast: ip.IsGlobalUnicast(), + IsInterfaceLocalMulticast: ip.IsInterfaceLocalMulticast(), + IsLinkLocalMulticast: ip.IsLinkLocalMulticast(), + IsLinkLocalUnicast: ip.IsLinkLocalUnicast(), + IsLoopback: ip.IsLoopback(), + IsMulticast: ip.IsMulticast(), + IsPrivate: ip.IsPrivate(), + IsUnspecified: ip.IsUnspecified(), + IsValid: ip.IsValid(), + } + } + if err = tbl.Bulk(rows); err != nil { + log.Panicln(err) + } + if err = tbl.Render(); err != nil { + log.Panicln(err) + } +} diff --git a/regexpx/TODO b/regexpx/TODO new file mode 100644 index 0000000..6b8e4f6 --- /dev/null +++ b/regexpx/TODO @@ -0,0 +1,57 @@ +- write a flag parser/converter for github.com/scorpionknifes/go-pcre (and github.com/GRbit/go-pcre) : +---- +// i CASELESS +// m MULTILINE +// s DOTALL +// x EXTENDED +// U UNGREEDY +// 8 UTF8 (non-standard flag letter; standard PCRE uses (*UTF8) outside (?...) syntax) +// +// Flags after a '-' inside group disable associated flag and are ignored +// (applies inside the regex engine once prefix is stripped). +// pattern, flags := ParsePrefixFlags(`(?im)^hello`) +// re := pcre.MustCompile(pattern, flags) +func ParsePrefixFlags(pattern string) (string, int) { + if !strings.HasPrefix(pattern, "(?") { + return pattern, 0 + } + + end := strings.IndexByte(pattern, ')') + if end < 0 { + return pattern, 0 + } + + inner := pattern[2:end] // everything between "(?" and ")" + + for _, ch := range inner { + if !strings.ContainsRune("imsxU8-", ch) { + return pattern, 0 + } + } + + positive := inner + if dash := strings.IndexByte(inner, '-'); dash >= 0 { + positive = inner[:dash] + } + + var flags int + for _, ch := range positive { + switch ch { + case 'i': + flags |= pcre.CASELESS + case 'm': + flags |= pcre.MULTILINE + case 's': + flags |= pcre.DOTALL + case 'x': + flags |= pcre.EXTENDED + case 'U': + flags |= pcre.UNGREEDY + case '8': + flags |= pcre.UTF8 + } + } + + return pattern[end+1:], flags +} +---- diff --git a/stringsx/TODO b/stringsx/TODO index f35a1bd..931cedc 100644 --- a/stringsx/TODO +++ b/stringsx/TODO @@ -2,4 +2,14 @@ -- draw border around multiline s -- i have a version in python somewhere that does this, should dig that up +- Tokenize() (new function) +-- PosixFilename() (new function) -- https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_282 +-- strings.ToLower() +-- compact consecutive: +--- whitespace +--- . +--- , +-- set custom replacement string (defaults to "_") +-- replace whitespace (after/during compact) with _ (customizable?) + - create bytesx package that duplicates the functions here? diff --git a/stringsx/funcs.go b/stringsx/funcs.go index 9397573..e1b0184 100644 --- a/stringsx/funcs.go +++ b/stringsx/funcs.go @@ -10,6 +10,53 @@ import ( `unicode` ) +/* +HasBookend returns true if string s both begins AND ends with sym. + +It is more strict than [HasBoundary] (which only requires +that s has sym at the beginning OR the end.) + +Examples: + HasBookend("|foo|", "|") → true + HasBookend("|foo", "|") → false + HasBookend("foo|", "|") → false + HasBookend("fo|o", "|") → false + HasBookend("|foo| ", "|") → false // Whitespace prevents match + HasBookend(" |foo| ", "|") → false + +sym may be a multi-rune string. +If sym is empty, HasBookend will *always* return true. +*/ +func HasBookend(s, sym string) (bounded bool) { + + bounded = strings.HasPrefix(s, sym) && strings.HasSuffix(s, sym) + + return +} + +/* +HasBoundary returns true if string s starts OR ends with symbol sym. + +Examples: + HasBoundary("|foo|", "|") → true + HasBoundary("|foo", "|") → true + HasBoundary("foo|", "|") → true + HasBoundary("fo|o", "|") → false + HasBoundary("|foo| ", "|") → true + HasBoundary(" |foo| ", "|") → false // Whitespace prevents match + +sym may be a multi-rune string. +If sym is empty, HasBoundary will *always* return true. + +If you instead require string s to be *enclosed* by sym, see [HasBookend]. +*/ +func HasBoundary(s, sym string) (bounded bool) { + + bounded = strings.HasPrefix(s, sym) || strings.HasSuffix(s, sym) + + return +} + /* IsAscii returns true if all characters in string s are ASCII. diff --git a/tplx/sprigx/README.adoc b/tplx/sprigx/README.adoc index c7372ce..9ae7b77 100644 --- a/tplx/sprigx/README.adoc +++ b/tplx/sprigx/README.adoc @@ -37,6 +37,23 @@ Last rendered {localdatetime} :import_me: {mod_me}/{pkg_me} :godoc_me: {godoc_root}/{import_me} :godoc_sprig: {godoc_root}/{import_sprig} +:funcsig_tpl: ./_docs/includes/funcsig.adoc +// Gorram it AsciiDoc stop snarfing whitespace +//// +These are only currently used by extIndent and strsxIsAsciiSpcl, +but there's no way to get rid of the blank lines/extra newlines. + +If I specify it without the plus, it just renders the tabs in indnt. +If I specify it without the slash, I can't enxapsulate the newline. +If I specify the source block in the include without +post_replacements, it leaves the plus signs in. +If I specifiy it with, it double-spaces the thing. +Oh well. +TODO: File a bug for that nonsense. +//// +:tab: pass:[ ] +:nl: pass:[ + \ +] +:indnt: pass:a[{nl}{tab}{tab}] // END variable attributes [id="wat"] @@ -108,7 +125,7 @@ The same way you would `sprig`! [%collapsible] .Like this. ==== -[source,go,subs="attributes"] +[source,go,subs="attributes",opts=novalidate] ---- package main @@ -139,7 +156,7 @@ They can even be combined/used together, [%collapsible] .like this. ==== -[source,go,subs="attributes"] +[source,go,subs="attributes",opts=novalidate] ---- package main @@ -181,7 +198,7 @@ For example, if both `sprig` and `sprigx` provide a function `foo`: [%collapsible] .this will use `foo` from `sprigx` ==== -[source,go,subs="attributes"] +[source,go,subs="attributes",opts=novalidate] ---- package main @@ -211,7 +228,7 @@ var ( [%collapsible] .whereas this will use `foo` from `sprig` ==== -[source,go,subs="attributes"] +[source,go,subs="attributes",opts=novalidate] ---- package main @@ -245,7 +262,7 @@ and a function can even be explicitly [[override]]overridden, ==== This would override a function `foo` and `foo2` in `sprigx` from `foo` and `foo2` from `sprig`, but leave all other `sprig` functions untouched. -[source,go,subs="attributes"] +[source,go,subs="attributes",opts=novalidate] ---- package main @@ -287,11 +304,9 @@ These are generally intended to be used *outside* the template in the actual Go [id="lib_cmbfmap"] === `CombinedFuncMap` -[source,go] -.Function Signature ----- -func CombinedFuncMap(preferSprigX bool) (fmap map[string]any) ----- +:func: CombinedFuncMap +:sig: (preferSprigX bool) (fmap map[string]any) +include::{funcsig_tpl}[] This function returns a generic function map (like <>) combined with {godoc_sprig}#GenericFuncMap[`{import_sprig}.GenericFuncMap`^]. @@ -304,11 +319,9 @@ as they wrap this with the appropriate type. [id="lib_cmbhfmap"] === `CombinedHtmlFuncMap` -[source,go] -.Function Signature ----- -func CombinedHtmlFuncMap(preferSprigX bool) (fmap template.FuncMap) ----- +:func: CombinedHtmlFuncMap +:sig: (preferSprigX bool) (fmap template.FuncMap) +include::{funcsig_tpl}[] This function returns an {godoc_root}/html/template#FuncMap[`html/template.FuncMap`] function map (like <>) combined with {godoc_sprig}#HtmlFuncMap[`{import_sprig}.HtmlFuncMap`^]. @@ -318,11 +331,9 @@ If false, Sprig functions will override conflicting SprigX functions with the sa [id="lib_cmbtfmap"] === `CombinedTxtFuncMap` -[source,go] -.Function Signature ----- -func CombinedTxtFuncMap(preferSprigX bool) (fmap template.FuncMap) ----- +:func: CombinedTxtFuncMap +:sig: (preferSprigX bool) (fmap template.FuncMap) +include::{funcsig_tpl}[] This function returns a {godoc_root}/text/template#FuncMap[`text/template.FuncMap`] function map (like <>) combined with {godoc_sprig}#TxtFuncMap[`{import_sprig}.TxtFuncMap`^]. @@ -332,11 +343,9 @@ If false, Sprig functions will override conflicting SprigX functions with the sa [id="lib_fmap"] === `FuncMap` -[source,go] -.Function Signature ----- -func FuncMap() (fmap map[string]any) ----- +:func: FuncMap +:sig: () (fmap map[string]any) +include::{funcsig_tpl}[] This function returns a generic SprigX function map. @@ -345,21 +354,17 @@ as they wrap this with the appropriate type. [id="lib_hfmap"] === `HtmlFuncMap` -[source,go] -.Function Signature ----- -func HtmlFuncMap() (fmap template.FuncMap) ----- +:func: HtmlFuncMap +:sig: () (fmap template.FuncMap) +include::{funcsig_tpl}[] This function returns a SprigX {godoc_root}/html/template#FuncMap[`html/template.FuncMap`^]. [id="lib_nop"] === `Nop` -[source,go] -.Function Signature ----- -func Nop(obj ...any) (s string) ----- +:func: Nop +:sig: (obj ...any) (s string) +include::{funcsig_tpl}[] `Nop` is a NO-OP function that one can use in an <> to explicitly disable certain Sprig/SprigX functions that may be deemed "unsafe" and/or to sanitize templates from untrusted input. @@ -368,11 +373,9 @@ It will *never* error or panic, and `s` is *always* an empty string. [id="lib_tfmap"] === `TxtFuncMap` -[source,go] -.Function Signature ----- -func TxtFuncMap() (fmap template.FuncMap) ----- +:func: TxtFuncMap +:sig: () (fmap template.FuncMap) +include::{funcsig_tpl}[] This function returns a SprigX {godoc_root}/text/template#FuncMap[`text/template.FuncMap`^]. @@ -395,11 +398,9 @@ you can easily determine whether a function can return an error or not by simply [id="fn_dbg_dump"] ==== `dump` -[source,go] -.Function Signature ----- -func dump(a ...interface{}) (out string) ----- +:func: dump +:sig: (a ...interface{}) (out string) +include::{funcsig_tpl}[] The `dump` function directly calls {godoc_root}/davecgh/go-spew/spew#Sdump[`github.com/davecgh/go-spew/spew.Sdump`^] for whatever object(s) is/are passed to it. @@ -409,23 +410,23 @@ for whatever object(s) is/are passed to it. [id="fn_meta_isnil"] ==== `metaIsNil` -[source,go] -.Function Signature ----- -func metaIsNil(obj any) (isNil bool) ----- +:func: metaIsNil +:sig: (obj any) (isNil bool) +include::{funcsig_tpl}[] `metaIsNil` returns `true` if `obj` is explicitly nil, otherwise it returns false. This function fills in the gap that {godoc_root}/text/template#IsTrue[`text/template.IsTrue`^] and {godoc_root}/html/template#IsTrue[`html/template.IsTrue`^] (expressed in templates as `{{ if ... }}`) leaves, as those functions/expressions return false for e.g. `false` booleans AND nils. -[id="fn_net_all"] + [id="fn_net_all"] === Networking These template functions use capabilities from: * <> * <> * <> +* <> +* <> The function prefix is used to indicate which module/package a function is added from. @@ -435,71 +436,57 @@ These template functions contain capabilities from {godoc_root}/net[`net`^]. [id="fn_net_cidrmask"] ===== `netCidrMask` -[source,go] -.Function Signature ----- -func netCidrMask(ones, bits int) (mask net.IPMask) ----- +:func: netCidrMask +:sig: (ones, bits int) (mask net.IPMask) +include::{funcsig_tpl}[] `netCidrMask` directly calls {godoc_root}/net#CIDRMask[`net.CIDRMask`^]. [id="fn_net_cidra"] ===== `netExtractAddr` -[source,go] -.Function Signature ----- -func netExtractAddr(s string) (addr net.IP, err error) ----- +:func: netExtractAddr +:sig: (s string) (addr net.IP, err error) +include::{funcsig_tpl}[] `netExtractAddr` wraps {godoc_root}/net#ParseCIDR[`net.ParseCIDR`^] and returns the {godoc_root}/net#IP[`net.IP`^] component. [id="fn_net_hph"] ===== `netExtractHost` -[source,go] -.Function Signature ----- -func netExtractHost(hostPort string) (host string, err error) ----- +:func: netExtractHost +:sig: (hostPort string) (host string, err error) +include::{funcsig_tpl}[] `netExtractHost` wraps {godoc_root}/net#SplitHostPort[`net.SplitHostPort`^] and returns the host component (as a string). [id="fn_net_cidrn"] ===== `netExtractIpnet` -[source,go] -.Function Signature ----- -func netExtractIpnet(s string) (ipNet *net.IPNet, err error) ----- +:func: netExtractIpnet +:sig: (s string) (ipNet *net.IPNet, err error) +include::{funcsig_tpl}[] `netExtractIpnet` wraps {godoc_root}/net#ParseCIDR[`net.ParseCIDR`^] and returns the {godoc_root}/net#IPNet[`net.IPNet`^] component. [id="fn_net_hpp"] ===== `netExtractPort` -[source,go] -.Function Signature ----- -func netExtractPort(hostPort string) (port uint16, err error) ----- +:func: netExtractPort +:sig: (hostPort string) (port uint16, err error) +include::{funcsig_tpl}[] `netExtractPort` wraps {godoc_root}/net#SplitHostPort[`net.SplitHostPort`^] and returns the port component (as a uint16). [id='fn_net_ifaces'] ===== `netIfaces` -[source,go] -.Function Signature ----- -func netIfaces() (ifaces []net.Interface, err error) ----- +:func: netIfaces +:sig: () (ifaces []net.Interface, err error) +include::{funcsig_tpl}[] `netIfaces` directly calls {godoc_root}/net#Interfaces[`net.Interfaces`^]. [id="fn_net_ip4mask"] ===== `netIp4Mask` -[source,go] -.Function Signature ----- -func netIp4Mask(a, b, c, d any) (mask net.IPMask, err error) ----- +:func: netIp4Mask +:sig: (a, b, c, d any) (mask net.IPMask, err error) +include::{funcsig_tpl}[] `netIp4Mask` wraps {godoc_root}/net#IPv4Mask[`net.IPv4Mask`^]. @@ -533,21 +520,17 @@ or even a mix: [id="fn_net_jhp"] ===== `netJoinHostPort` -[source,go] -.Function Signature ----- -func netJoinHostPort(host, port string) (out string) ----- +:func: netJoinHostPort +:sig: (host, port string) (out string) +include::{funcsig_tpl}[] `netJoinHostPort` directly calls {godoc_root}/net#JoinHostPort[`net.JoinHostPort`^]. [id="fn_net_parseip"] ===== `netParseIP` -[source,go] -.Function Signature ----- -func netParseIP(s string) (ip net.IP) ----- +:func: netParseIP +:sig: (s string) (ip net.IP) +include::{funcsig_tpl}[] `netParseIP` directly calls {godoc_root}/net#ParseIP[`net.ParseIP`^]. @@ -557,51 +540,41 @@ These template functions contain capabilities from {godoc_root}/net/netip[`net/n [id="fn_netip_addrport"] ===== `netipAddrPort` -[source,go] -.Function Signature ----- -func netipAddrPort(ip netip.Addr, port uint16) (addrPort netip.AddrPort) ----- +:func: netipAddrPort +:sig: (ip netip.Addr, port uint16) (addrPort netip.AddrPort) +include::{funcsig_tpl}[] `netipAddrPort` directly calls {godoc_root}/net/netip#AddrPortFrom[`net/netip.AddrPortFrom`^]. [id="fn_netip_parseaddr"] ===== `netipParseAddr` -[source,go] -.Function Signature ----- -func netipParseAddr(s string) (addr netip.Addr, err error) ----- +:func: netipParseAddr +:sig: (s string) (addr netip.Addr, err error) +include::{funcsig_tpl}[] `netipParseAddr` directly calls {godoc_root}/net/netip#ParseAddr[`net/netip.ParseAddr`^]. [id="fn_netip_pap"] ===== `netipParseAddrPort` -[source,go] -.Function Signature ----- -func netipParseAddrPort(s string) (addrPort netip.AddrPort, err error) ----- +:func: netipParseAddrPort +:sig: (s string) (addrPort netip.AddrPort, err error) +include::{funcsig_tpl}[] `netipParseAddrPort` directly calls {godoc_root}/net/netip#ParseAddrPort[`net/netip.ParseAddrPort`^]. [id="fn_netip_parsepfx"] ===== `netipParsePrefix` -[source,go] -.Function Signature ----- -func netipParsePrefix(s string) (pfx netip.Prefix, err error) ----- +:func: netipParsePrefix +:sig: (s string) (pfx netip.Prefix, err error) +include::{funcsig_tpl}[] `netipParsePrefix` directly calls {godoc_root}/net/netip#ParsePrefix[`net/netip.ParsePrefix`^]. [id="fn_netip_pfx"] ===== `netipPrefix` -[source,go] -.Function Signature ----- -func netipPrefix(ip netip.Addr, bits int) (pfx netip.Prefix) ----- +:func: netipPrefix +:sig: (ip netip.Addr, bits int) (pfx netip.Prefix) +include::{funcsig_tpl}[] `netipPrefix` directly calls {godoc_root}/net/netip#PrefixFrom[`net/netip.PrefixFrom`^]. @@ -611,280 +584,412 @@ These template functions contain capabilities from {godoc_root}/go4.org/netipx[` [id="fn_netipx_addripnet"] ===== `netipxAddrIpNet` -[source,go] -.Function Signature ----- -func netipxAddrIpNet(addr netip.Addr) (ipNet *net.IPNet) ----- +:func: netipxAddrIpNet +:sig: (addr netip.Addr) (ipNet *net.IPNet) +include::{funcsig_tpl}[] `netipxAddrIpNet` directly calls {godoc_root}/go4.org/netipx#AddrIPNet[`go4.org/netipx.AddrIPNet`^]. [id="fn_netipx_cmppfx"] ===== `netipxCmpPfx` -[source,go] -.Function Signature ----- -func netipxCmpPfx(a, b netip.Prefix) (cmp int) ----- +:func: netipxCmpPfx +:sig: (a, b netip.Prefix) (cmp int) +include::{funcsig_tpl}[] `netipxCmpPfx` directly calls {godoc_root}/go4.org/netipx#ComparePrefix[`go4.org/netipx.ComparePrefix`^]. [id="fn_netipx_fromstdaddr"] ===== `netipxFromStdAddr` -[source,go] -.Function Signature ----- -func netipxFromStdAddr(ip net.IP, port int, zone string) (addrPort netip.AddrPort, err error) ----- +:func: netipxFromStdAddr +:sig: (ip net.IP, port int, zone string) (addrPort netip.AddrPort, err error) +include::{funcsig_tpl}[] `netipxFromStdAddr` wraps {godoc_root}/go4.org/netipx#FromStdAddr[`go4.org/netipx.FromStdAddr`^]. Instead of returning a boolean as the second value, it will instead be an error if the wrapped boolean is false. [id="fn_netipx_fromip"] ===== `netipxFromIp` -[source,go] -.Function Signature ----- -func netipxFromIp(ip net.IP) (addr netip.Addr, err error) ----- +:func: netipxFromIp +:sig: (ip net.IP) (addr netip.Addr, err error) +include::{funcsig_tpl}[] `netipxFromIp` wraps {godoc_root}/go4.org/netipx#FromStdIP[`go4.org/netipx.FromStdIP`^]. Instead of returning a boolean as the second value, it will instead be an error if the wrapped boolean is false. [id="fn_netipx_fromipnet"] ===== `netipxFromIpNet` -[source,go] -.Function Signature ----- -func netipxFromIpNet(ipNet *net.IPNet) (pfx netip.Prefix, err error) ----- +:func: netipxFromIpNet +:sig: (ipNet *net.IPNet) (pfx netip.Prefix, err error) +include::{funcsig_tpl}[] `netipxFromIpNet` wraps {godoc_root}/go4.org/netipx#FromStdIPNet[`go4.org/netipx.FromStdIPNet`^]. Instead of returning a boolean as the second value, it will instead be an error if the wrapped boolean is false. [id="fn_netipx_parserange"] ===== `netipxParseRange` -[source,go] -.Function Signature ----- -func netipxParseRange(s string) (ipRange netipx.IPRange, err error) ----- +:func: netipxParseRange +:sig: (s string) (ipRange netipx.IPRange, err error) +include::{funcsig_tpl}[] -`netipxRange` directly calls {godoc_root}/go4.org/netipx#ParseIPRange[`go4.org/netipx.ParseIPRange`^]. +`netipxParseRange` directly calls {godoc_root}/go4.org/netipx#ParseIPRange[`go4.org/netipx.ParseIPRange`^]. [id="fn_netipx_pfxaddr"] ===== `netipxPfxAddr` -[source,go] -.Function Signature ----- -func netipxPfxAddr(s string) (addr netip.Addr, err error) ----- +:func: netipxPfxAddr +:sig: (s string) (addr netip.Addr, err error) +include::{funcsig_tpl}[] `netipxPfxAddr` directly calls {godoc_root}/go4.org/netipx#ParsePrefixOrAddr[`go4.org/netipx.ParsePrefixOrAddr`^]. [id="fn_netipx_pfxipnet"] ===== `netipxPfxIpNet` -[source,go] -.Function Signature ----- -func netipxPfxIpNet(pfx netip.Prefix) (ipNet *net.IPNet) ----- +:func: netipxPfxIpNet +:sig: (pfx netip.Prefix) (ipNet *net.IPNet) +include::{funcsig_tpl}[] `netipxPfxIpNet` directly calls {godoc_root}/go4.org/netipx#PrefixIPNet[`go4.org/netipx.PrefixIPNet`^]. [id="fn_netipx_pfxlast"] ===== `netipxPfxLast` -[source,go] -.Function Signature ----- -func netipxPfxLast(pfx netip.Prefix) (addr netip.Addr) ----- +:func: netipxPfxLast +:sig: (pfx netip.Prefix) (addr netip.Addr) +include::{funcsig_tpl}[] `netipxPfxLast` directly calls {godoc_root}/go4.org/netipx#PrefixLastIP[`go4.org/netipx.PrefixLastIP`^]. [id="fn_netipx_pfxrange"] ===== `netipxPfxRange` -[source,go] -.Function Signature ----- -func netipxPfxRange(pfx netip.Prefix) (ipRange netipx.IPRange) ----- +:func: netipxPfxRange +:sig: (pfx netip.Prefix) (ipRange netipx.IPRange) +include::{funcsig_tpl}[] `netipxPfxRange` directly calls {godoc_root}/go4.org/netipx#RangeOfPrefix[`go4.org/netipx.RangeOfPrefix`^]. [id="fn_netipx_range"] ===== `netipxRange` -[source,go] -.Function Signature ----- -func netipxRange(from, to netip.Addr) (ipRange netipx.IPRange) ----- +:func: netipxRange +:sig: (from, to netip.Addr) (ipRange netipx.IPRange) +include::{funcsig_tpl}[] `netipxRange` directly calls {godoc_root}/go4.org/netipx#IPRangeFrom[`go4.org/netipx.IPRangeFrom`^]. [id="fn_netx"] -==== `netx` +==== `r00t2.io/goutils/netx` These template functions contain capabilities from {godoc_root}/{mod_me}/netx[`{mod_me}/netx`^]. [id="fn_netx_addrrfc"] ===== `netxAddrRfc` -[source,go] -.Function Signature ----- -func netxAddrRfc(addr netip.Addr) (rfcStr string) ----- +:func: netxAddrRfc +:sig: (addr netip.Addr) (rfcStr string) +include::{funcsig_tpl}[] `netxAddrRfc` directly calls {godoc_root}/{mod_me}/netx#AddrRfc[`{mod_me}/netx.AddrRfc`^]. [id="fn_netx_cidr4ipmask"] -===== `netxCidr4IpMask` -[source,go] -.Function Signature ----- -func netxCidr4IpMask(cidr uint8) (ipMask net.IPMask, err error) ----- +===== `netxAddrRfc` +:func: netxAddrRfc +:sig: (cidr uint8) (ipMask net.IPMask, err error) +include::{funcsig_tpl}[] `netxCidr4IpMask` directly calls {godoc_root}/{mod_me}/netx#Cidr4ToIPMask[`{mod_me}/netx.Cidr4ToIPMask`^]. [id="fn_netx_cidr4mask"] ===== `netxCidr4Mask` -[source,go] -.Function Signature ----- -func netxCidr4Mask(cidr uint8) (mask uint32, err error) ----- +:func: netxCidr4Mask +:sig: (cidr uint8) (mask uint32, err error) +include::{funcsig_tpl}[] `netxCidr4IpMask` directly calls {godoc_root}/{mod_me}/netx#Cidr4ToMask[`{mod_me}/netx.Cidr4ToMask`^]. [id="fn_netx_cidr4str"] ===== `netxCidr4Str` -[source,go] -.Function Signature ----- -func netxCidr4Str(cidr uint8) (maskStr string, err error) ----- +:func: netxCidr4Str +:sig: (cidr uint8) (maskStr string, err error) +include::{funcsig_tpl}[] `netxCidr4Str` directly calls {godoc_root}/{mod_me}/netx#Cidr4ToStr[`{mod_me}/netx.Cidr4ToStr`^]. [id="fn_netx_familyver"] ===== `netxFamilyVer` -[source,go] -.Function Signature ----- -func netxFamilyVer(family uint16) (ipVer int) ----- +:func: netxFamilyVer +:sig: (family uint16) (ipVer int) +include::{funcsig_tpl}[] `netxFamilyVer` directly calls {godoc_root}/{mod_me}/netx#FamilyToVer[`{mod_me}/netx.FamilyToVer`^]. [id="fn_netx_getaddrfam"] ===== `netxGetAddrFam` -[source,go] -.Function Signature ----- -func netxGetAddrFam(addr netip.Addr) (family uint16) ----- +:func: netxGetAddrFam +:sig: (addr netip.Addr) (family uint16) +include::{funcsig_tpl}[] `netxGetAddrFam` directly calls {godoc_root}/{mod_me}/netx#GetAddrFamily[`{mod_me}/netx.GetAddrFamily`^]. [id="fn_netx_getipfam"] ===== `netxGetIpFam` -[source,go] -.Function Signature ----- -func netxGetIpFam(ip net.IP) (family uint16) ----- +:func: netxGetIpFam +:sig: (ip net.IP) (family uint16) +include::{funcsig_tpl}[] `netxGetIpFam` directly calls {godoc_root}/{mod_me}/netx#GetAddrFamily[`{mod_me}/netx.GetIpFamily`^]. [id="fn_netx_iprfc"] ===== `netxIpRfc` -[source,go] -.Function Signature ----- -func netxIpRfc(ip net.IP) (rfcStr string) ----- +:func: netxIpRfc +:sig: (ip net.IP) (rfcStr string) +include::{funcsig_tpl}[] `netxIpRfc` directly calls {godoc_root}/{mod_me}/netx#IpRfc[`{mod_me}/netx.IpRfc`^]. [id="fn_netx_iprfcstr"] ===== `netxIpRfcStr` -[source,go] -.Function Signature ----- -func netxIpRfcStr(s string) (rfcStr string) ----- +:func: netxIpRfcStr +:sig: (s string) (rfcStr string) +include::{funcsig_tpl}[] `netxIpRfcStr` directly calls {godoc_root}/{mod_me}/netx#IpRfcStr[`{mod_me}/netx.IpRfcStr`^]. [id="fn_netx_ipstriprfc"] ===== `netxIpStripRfc` -[source,go] -.Function Signature ----- -func netxIpStripRfc(s string) (stripStr string) ----- +:func: netxIpStripRfc +:sig: (s string) (stripStr string) +include::{funcsig_tpl}[] `netxIpStripRfc` directly calls {godoc_root}/{mod_me}/netx#IpStripRfcStr[`{mod_me}/netx.IpStripRfcStr`^]. [id="fn_netx_ip4maskcidr"] ===== `netxIp4MaskCidr` -[source,go] -.Function Signature ----- -func netxIp4MaskCidr(ipMask net.IPMask) (cidr uint8, err error) ----- +:func: netxIp4MaskCidr +:sig: (ipMask net.IPMask) (cidr uint8, err error) +include::{funcsig_tpl}[] `netxIp4MaskCidr` directly calls {godoc_root}/{mod_me}/netx#IPMask4ToCidr[`{mod_me}/netx.IPMask4ToCidr`^]. [id="fn_netx_ip4maskmask"] ===== `netxIp4MaskMask` -[source,go] -.Function Signature ----- -func netxIp4MaskMask(ipMask net.IPMask) (mask uint32, err error) ----- +:func: netxIp4MaskMask +:sig: (ipMask net.IPMask) (mask uint32, err error) +include::{funcsig_tpl}[] `netxIp4MaskMask` directly calls {godoc_root}/{mod_me}/netx#IPMask4ToMask[`{mod_me}/netx.IPMask4ToMask`^]. -// TODO +[id="fn_netx_ip4maskstr"] +===== `netxIp4MaskStr` +:func: netxIp4MaskStr +:sig: (ipMask net.IPMask) (maskStr string, err error) +include::{funcsig_tpl}[] + +`netxIp4MaskStr` directly calls {godoc_root}/{mod_me}/netx#IPMask4ToStr[`{mod_me}/netx.IPMask4ToStr`^]. + +[id="fn_netx_ipverstr"] +===== `netxIpVerStr` +:func: netxIpVerStr +:sig: (s string) (ipVer int) +include::{funcsig_tpl}[] + +`netxIpVerStr` directly calls {godoc_root}/{mod_me}/netx#IpVerStr[`{mod_me}/netx.IpVerStr`^]. + +[id="fn_netx_isbrktd6"] +===== `netxIsBrktd6` +:func: netxIsBrktd6 +:sig: (s string) (isBrktdIp bool) +include::{funcsig_tpl}[] + +`netxIsBrktd6` directly calls {godoc_root}/{mod_me}/netx#IsBracketedIp6[`{mod_me}/netx.IsBracketedIp6`^]. + +[id="fn_netx_isip"] +===== `netxIsIp` +:func: netxIsIp +:sig: (s string) (isIp bool) +include::{funcsig_tpl}[] + +`netxIsIp` directly calls {godoc_root}/{mod_me}/netx#IsIpAddr[`{mod_me}/netx.IsIpAddr`^]. + +[id="fn_netx_ispfx"] +===== `netxIsPfx` +:func: netxIsPfx +:sig: (s string) (isNet bool) +include::{funcsig_tpl}[] + +`netxIsPfx` directly calls {godoc_root}/{mod_me}/netx#IsPrefixNet[`{mod_me}/netx.IsPrefixNet`^]. + +[id="fn_netx_mask4cidr"] +===== `netxMask4Cidr` +:func: netxMask4Cidr +:sig: (mask uint32) (cidr uint8, err error) +include::{funcsig_tpl}[] + +`netxMask4Cidr` directly calls {godoc_root}/{mod_me}/netx#Mask4ToCidr[`{mod_me}/netx.Mask4ToCidr`^]. + +[id="fn_netx_mask4Strcidr"] +===== `netxMask4StrCidr` +:func: netxMask4StrCidr +:sig: (maskStr string) (cidr uint8, err error) +include::{funcsig_tpl}[] + +`netxMask4StrCidr` directly calls {godoc_root}/{mod_me}/netx#Mask4StrToCidr[`{mod_me}/netx.Mask4StrToCidr`^]. + +[id="fn_netx_mask4stripmask"] +===== `netxMask4StrIpMask` +:func: netxMask4StrIpMask +:sig: (maskStr string) (mask net.IPMask, err error) +include::{funcsig_tpl}[] + +`netxMask4StrIpMask` directly calls {godoc_root}/{mod_me}/netx#Mask4StrToIPMask[`{mod_me}/netx.Mask4StrToIPMask`^]. + +[id="fn_netx_mask4strmask"] +===== `netxMask4StrMask` +:func: netxMask4StrMask +:sig: (maskStr string) (mask uint32, err error) +include::{funcsig_tpl}[] + +`netxMask4StrMask` directly calls {godoc_root}/{mod_me}/netx#Mask4StrToMask[`{mod_me}/netx.Mask4StrToMask`^]. + +[id="fn_netx_ver2fam"] +===== `netxVerFamily` +:func: netxVerFamily +:sig: (ipVer int) (family uint16) +include::{funcsig_tpl}[] + +`netxVerFamily` directly calls {godoc_root}/{mod_me}/netx#VerToFamily[`{mod_me}/netx.VerToFamily`^]. + +[id="fn_dnsx"] +==== `r00t2.io/goutils/netx/dnsx` +These template functions contain capabilities from {godoc_root}/{import_me}/netx/dnsx[`{import_me}/netx/dnsx`^]. + +[id="fn_dnsx_ptraddr"] +===== `dnsxPtrAddr` +:func: dnsxPtrAddr +:sig: (s string) (ip netip.Addr, err error) +include::{funcsig_tpl}[] + +`dnsxPtrAddr` directly calls {godoc_root}/{import_me}/netx/dnsx#AddrFromPtr[`{import_me}/netx/dnsx.AddrFromPtr`^]. + +[id="fn_dnsx_addrptr"] +===== `dnsxAddrPtr` +:func: dnsxAddrPtr +:sig: (ip netip.Addr) (s string) +include::{funcsig_tpl}[] + +`dnsxAddrPtr` directly calls {godoc_root}/{import_me}/netx/dnsx#AddrToPtr[`{import_me}/netx/dnsx.AddrToPtr`^]. + +[id="fn_dnsx_str2wire"] +===== `dnsxStrWire` +:func: dnsxStrWire +:sig: (recordNm string) (recordNmBytes []byte, err error) +include::{funcsig_tpl}[] + +`dnsxStrWire` directly calls {godoc_root}/{import_me}/netx/dnsx#DnsStrToWire[`{import_me}/netx/dnsx.DnsStrToWire`^]. + +[id="fn_dnsx_wire2str"] +===== `dnsxWireStr` +:func: dnsxWireStr +:sig: (recordNmBytes []byte) (recordNm string, err error) +include::{funcsig_tpl}[] + +`dnsxWireStr` directly calls {godoc_root}/{import_me}/netx/dnsx#DnsWireToStr[`{import_me}/netx/dnsx.DnsWireToStr`^]. + +[id="fn_dnsx_ptrip"] +===== `dnsxPtrIp` +:func: dnsxPtrIp +:sig: (s string) (ip net.IP, err error) +include::{funcsig_tpl}[] + +`dnsxPtrIp` directly calls {godoc_root}/{import_me}/netx/dnsx#IpFromPtr[`{import_me}/netx/dnsx.IpFromPtr`^]. + +[id="fn_dnsx_ipptr"] +===== `dnsxIpPtr` +:func: dnsxIpPtr +:sig: (ip net.IP) (s string) +include::{funcsig_tpl}[] + +`dnsxIpPtr` directly calls {godoc_root}/{import_me}/netx/dnsx#IpToPtr[`{import_me}/netx/dnsx.IpToPtr`^]. + +[id="fn_dnsx_isfqdn"] +===== `dnsxIsFqdn` +:func: dnsxIsFqdn +:sig: (s string) (fqdn bool) +include::{funcsig_tpl}[] + +`dnsxIsFqdn` directly calls {godoc_root}/{import_me}/netx/dnsx#IsFqdn[`{import_me}/netx/dnsx.IsFqdn`^]. + +[id="fn_dnsx_istxt"] +===== `dnsxIsTxt` +:func: dnsxIsTxt +:sig: (fqdn string) (isOk bool) +include::{funcsig_tpl}[] + +`dnsxIsTxt` directly calls {godoc_root}/{import_me}/netx/dnsx#IsFqdnDefinedTxt[`{import_me}/netx/dnsx.IsFqdnDefinedTxt`^]. + +[id="fn_dnsx_isnsec3"] +===== `dnsxIsNsec3` +:func: dnsxIsNsec3 +:sig: (s string) (maybeNsec3 bool) +include::{funcsig_tpl}[] + +`dnsxIsNsec3` directly calls {godoc_root}/{import_me}/netx/dnsx#IsFqdnNsec3[`{import_me}/netx/dnsx.IsFqdnNsec3`^]. + +[id="fn_dnsx_issrv"] +===== `dnsxIsSrv` +:func: dnsxIsSrv +:sig: (s string) (srv bool) +include::{funcsig_tpl}[] + +`dnsxIsSrv` directly calls {godoc_root}/{import_me}/netx/dnsx#IsFqdnSrv[`{import_me}/netx/dnsx.IsFqdnSrv`^]. + +[id="fn_dnsx_iswild"] +===== `dnsxIsWild` +:func: dnsxIsWild +:sig: (s string) (wildcard bool) +include::{funcsig_tpl}[] + +`dnsxIsWild` directly calls {godoc_root}/{import_me}/netx/dnsx#IsFqdnWildcard[`{import_me}/netx/dnsx.IsFqdnWildcard`^]. + +[id="fn_dnsx_islbl"] +===== `dnsxIsLbl` +:func: dnsxIsLbl +:sig: (s string) (isLbl bool) +include::{funcsig_tpl}[] + +`dnsxIsLbl` directly calls {godoc_root}/{import_me}/netx/dnsx#IsLabel[`{import_me}/netx/dnsx.IsLabel`^]. + +[id="fn_dnsx_isptr"] +===== `dnsxIsPtr` +:func: dnsxIsPtr +:sig: (s string) (isPtr bool, addr net.IP) +include::{funcsig_tpl}[] + +`dnsxIsPtr` directly calls {godoc_root}/{import_me}/netx/dnsx#IsPtr[`{import_me}/netx/dnsx.IsPtr`^]. [id="fn_num"] === Numbers/Math [id="fn_num_f32s"] ==== `numFloat32Str` -[source,go] -.Function Signature ----- -func numFloat32Str(f float32) (s string) ----- +:func: numFloat32Str +:sig: (f float32) (s string) +include::{funcsig_tpl}[] `numFloat32Str` returns a *complete* non-truncated non-right-padded string representation of a `float32`. [id="fn_num_f64"] ==== `numFloat64` -[source,go] -.Function Signature ----- -func numFloat64(val any) (f float64, err error) ----- +:func: numFloat64 +:sig: (val any) (f float64, err error) +include::{funcsig_tpl}[] `numFloat64` returns any string representation of a numeric value or any type of numeric value to a `float64`. [id="fn_num_f64s"] ==== `numFloat64Str` -[source,go] -.Function Signature ----- -func numFloat64Str(f float64) (s string) ----- +:func: numFloat64Str +:sig: (f float64) (s string) +include::{funcsig_tpl}[] `numFloat64Str` returns a *complete* non-truncated non-right-padded string representation of a `float64`. [id="fn_num_fs"] ==== `numFloatStr` -[source,go] -.Function Signature ----- -func numFloatStr(val any) (s string, err error) ----- +:func: numFloatStr +:sig: (val any) (s string, err error) +include::{funcsig_tpl}[] `numFloatStr` wraps <> and <>. @@ -895,11 +1000,9 @@ func numFloatStr(val any) (s string, err error) [id="fn_os_fqdn"] ==== `osFQDN` -[source,go] -.Function Signature ----- -func osFQDN() (fqdn string, err error) ----- +:func: osFQDN +:sig: () (fqdn string, err error) +include::{funcsig_tpl}[] `osFQDN` currently just directly calls {godoc_root}/os#Hostname[`os.Hostname`^]. @@ -914,11 +1017,9 @@ To directly/predictably use {godoc_root}/os#Hostname[`os.Hostname`^], use <>. [id="fn_os_hstnm"] ==== `osHostname` -[source,go] -.Function Signature ----- -func osHostname() (out string, err error) ----- +:func: osHostname +:sig: () (out string, err error) +include::{funcsig_tpl}[] `osHostname` directly calls {godoc_root}/os#Hostname[`os.Hostname`^]. [id="fn_os_idst"] ==== `osIdState` -[source,go] -.Function Signature ----- -func osIdState() (idst sysutils.IDState) ----- +:func: osIdState +:sig: () (idst sysutils.IDState) +include::{funcsig_tpl}[] `osIdState` returns the current runtime process' {godoc_root}/r00t2.io/sysutils#IDState[`r00t2.io/sysutils.IDState`^]. @@ -995,11 +1088,9 @@ This is more or less useless on Windows; it returns only a dummy struct for cros [id="fn_os_usr"] ==== `osUser` -[source,go] -.Function Signature ----- -func osUser() (u *user.User, err error) ----- +:func: osUser +:sig: () (u *user.User, err error) +include::{funcsig_tpl}[] `osUser` returns the current runtime process' {godoc_root}/os/user#User[`os/user.User`^]. @@ -1007,11 +1098,9 @@ It directly calls {godoc_root}/os/user#Current[`os/user.Current`^]. [id="fn_os_usrid"] ==== `osUserById` -[source,go] -.Function Signature ----- -func osUserById[T string | int](uid T) (u *user.User, err error) ----- +:func: osUserById +:sig: [T string | int](uid T) (u *user.User, err error) +include::{funcsig_tpl}[] `osUserById` returns an {godoc_root}/os/user#User[`os/user.User`^] from a given user ID/UID. @@ -1020,11 +1109,9 @@ except it will accept either a `string` *or* an `int` as the UID. [id="fn_os_usrnm"] ==== `osUserByName` -[source,go] -.Function Signature ----- -func osUserByName(userNm string) (u *user.User, err error) ----- +:func: osUserByName +:sig: (userNm string) (u *user.User, err error) +include::{funcsig_tpl}[] `osUserByName` returns an {godoc_root}/os/user#User[`os/user.User`^] from a given username. @@ -1039,11 +1126,9 @@ These operate similar to {godoc_root}/path[the `path` stdlib library^] and use a [id="fn_path_gnrc_pj"] ===== `pathJoin` -[source,go] -.Function Signature ----- -func pathJoin(elem ...string) (out string) ----- +:func: pathJoin +:sig: (elem ...string) (out string) +include::{funcsig_tpl}[] `pathJoin` directly calls {godoc_root}/path#Join[`path.Join`^]. @@ -1071,11 +1156,9 @@ a/b/c [id="fn_path_gnrc_ppj"] ===== `pathPipeJoin` -[source,go] -.Function Signature ----- -func pathPipeJoin(elems ...string) (out string) ----- +:func: pathPipeJoin +:sig: (elems ...string) (out string) +include::{funcsig_tpl}[] `pathPipeJoin` operates like <> with one deviation: the root/base path is expected to be *last* in the arguments. @@ -1101,11 +1184,9 @@ a/b/c [id="fn_path_gnrc_psj"] ===== `pathSliceJoin` -[source,go] -.Function Signature ----- -func pathSliceJoin(sl []string) (out string) ----- +:func: pathSliceJoin +:sig: (sl []string) (out string) +include::{funcsig_tpl}[] `pathSliceJoin` joins a slice of path segment strings (`[]string`) instead of a variadic sequence of strings. @@ -1133,15 +1214,14 @@ a/b/c [id="fn_path_gnrc_pspj"] ===== `pathSlicePipeJoin` -[source,go] -.Function Signature ----- -func pathSlicePipeJoin(sl []string, root string) (out string) ----- +:func: pathSlicePipeJoin +:sig: (sl []string, root string) (out string) +include::{funcsig_tpl}[] -`pathSlicePipeJoin` operates like <> in that it is suitable for pipeline use in which the root/base path is passed in -from the pipeline, but it is like <> in that it then also accepts a slice of -path segments (`[]string`) to append to that base path. +`pathSlicePipeJoin` operates like a hybrid of <> and <>: + +* Like <>, it is suitable for pipeline use -- the root/base path is passed in from the pipeline +* Like <>, it *also* accepts a slice of path segments (`[]string`) to append to that base path [TIP] ==== @@ -1166,11 +1246,9 @@ renders as: [id="fn_path_gnrc_psubj"] ===== `pathSubJoin` -[source,go] -.Function Signature ----- -func pathSubJoin(root string, elems ...string) (out string) ----- +:func: pathSubJoin +:sig: (root string, elems ...string) (out string) +include::{funcsig_tpl}[] `pathSubJoin` operates like <> but it expects an explicit root/base path. @@ -1205,11 +1283,9 @@ It is recommended to make use of <> to conditionally format path base [id="fn_path_os_pj"] ===== `osPathJoin` -[source,go] -.Function Signature ----- -func osPathJoin(elem ...string) (out string) ----- +:func: osPathJoin +:sig: (elem ...string) (out string) +include::{funcsig_tpl}[] `osPathJoin` directly calls {godoc_root}/path/filepath#Join[`path/filepath.Join`^]. @@ -1252,11 +1328,9 @@ C:/a/b/c [id="fn_path_os_ppj"] ===== `osPathPipeJoin` -[source,go] -.Function Signature ----- -func osPathPipeJoin(elems ...string) (out string) ----- +:func: osPathJoin +:sig: (elems ...string) (out string) +include::{funcsig_tpl}[] `osPathPipeJoin` operates like <> (except using OS-specific path separators). @@ -1293,11 +1367,9 @@ a/b/c [id="fn_path_ossep"] ===== `osPathSep` -[source,go] -.Function Signature ----- -func osPathSep() (out string) ----- +:func: osPathSep +:sig: () (out string) +include::{funcsig_tpl}[] `osPathSep` returns the {godoc_root}/os#PathSeparator[`os.PathSeparator`^] for this OS. @@ -1324,11 +1396,9 @@ renders as: [id="fn_path_os_psj"] ===== `osPathSliceJoin` -[source,go] -.Function Signature ----- -func osPathSliceJoin(sl []string) (out string) ----- +:func: osPathSliceJoin +:sig: (sl []string) (out string) +include::{funcsig_tpl}[] `osPathSliceJoin` operates like <> but with OS-specific path separators. @@ -1367,11 +1437,9 @@ a/b/c [id="fn_path_os_pspj"] ===== `osPathSlicePipeJoin` -[source,go] -.Function Signature ----- -func osPathSlicePipeJoin(sl []string, root string) (out string) ----- +:func: osPathSlicePipeJoin +:sig: (sl []string, root string) (out string) +include::{funcsig_tpl}[] `osPathSlicePipeJoin` operates like <> but with OS-specific separators. @@ -1408,11 +1476,9 @@ renders as: [id="fn_path_os_psubj"] ===== `osPathSubJoin` -[source,go] -.Function Signature ----- -func osPathSubJoin(root string, elems ...string) (out string) ----- +:func: osPathSubJoin +:sig: (root string, elems ...string) (out string) +include::{funcsig_tpl}[] `osPathSubJoin` operates like <> but with OS-specific separators. @@ -1454,41 +1520,33 @@ These are functions from {godoc_root}/{mod_psutil}[`{mod_psutil}`^] packages. [id="fn_ps_cpu_cnts"] ===== `psCpuCnts` -[source,go] -.Function Signature ----- -func psCpuCnts(logical bool) (numCpu int, err error) ----- +:func: psCpuCnts +:sig: (logical bool) (numCpu int, err error) +include::{funcsig_tpl}[] `psCpuCnts` directly calls {godoc_root}/{mod_psutil}/cpu#Counts[`{mod_psutil}/cpu.Counts`^]. [id="fn_ps_cpu_info"] ===== `psCpuInfo` -[source,go] -.Function Signature ----- -func psCpuInfo() (cpuInfo []cpu.Info, err error) ----- +:func: psCpuInfo +:sig: () (cpuInfo []cpu.Info, err error) +include::{funcsig_tpl}[] `psCpuInfo` directly calls {godoc_root}/{mod_psutil}/cpu#Info[`{mod_psutil}/cpu.Info`^]. [id="fn_ps_cpu_pct"] ===== `psCpuPct` -[source,go] -.Function Signature ----- -func psCpuPct(interval time.Duration, percpu bool) (pcts []float64, err error) ----- +:func: psCpuPct +:sig: (interval time.Duration, percpu bool) (pcts []float64, err error) +include::{funcsig_tpl}[] `psCpuPct` directly calls {godoc_root}/{mod_psutil}/cpu#Percent[`{mod_psutil}/cpu.Percent`^]. [id="fn_ps_cpu_tms"] ===== `psCpuTimes` -[source,go] -.Function Signature ----- -func psCpuTimes(percpu bool) (cpuTimes []cpu.TimesStat, err error) ----- +:func: psCpuTimes +:sig: (percpu bool) (cpuTimes []cpu.TimesStat, err error) +include::{funcsig_tpl}[] `psCpuTimes` directly calls {godoc_root}/{mod_psutil}/cpu#Times[`{mod_psutil}/cpu.Times`^]. @@ -1497,51 +1555,41 @@ func psCpuTimes(percpu bool) (cpuTimes []cpu.TimesStat, err error) [id="fn_ps_dsk_iocnts"] ===== `psDiskIoCnts` -[source,go] -.Function Signature ----- -func psDiskIoCnts(names ...string) (stats map[string]disk.IOCountersStat, err error) ----- +:func: psDiskIoCnts +:sig: (names ...string) (stats map[string]disk.IOCountersStat, err error) +include::{funcsig_tpl}[] `psDiskIoCnts` directly calls {godoc_root}/{mod_psutil}/disk#IOCounters[`{mod_psutil}/disk.IOCounters`^]. [id="fn_ps_dsk_lbl"] ===== `psDiskLabel` -[source,go] -.Function Signature ----- -func psDiskLabel(name string) (label string, err error) ----- +:func: psDiskLabel +:sig: (name string) (label string, err error) +include::{funcsig_tpl}[] `psDiskLabel` directly calls {godoc_root}/{mod_psutil}/disk#Label[`{mod_psutil}/disk.Label`^]. [id="fn_ps_dsk_parts"] ===== `psDiskParts` -[source,go] -.Function Signature ----- -func psDiskParts(all bool) (parts []disk.PartitionStat, err error) ----- +:func: psDiskParts +:sig: (all bool) (parts []disk.PartitionStat, err error) +include::{funcsig_tpl}[] `psDiskParts` directly calls {godoc_root}/{mod_psutil}/disk#Partitions[`{mod_psutil}/disk.Partitions`^]. [id="fn_ps_dsk_srl"] ===== `psDiskSerial` -[source,go] -.Function Signature ----- -func psDiskSerial(name string) (serial string, err error) ----- +:func: psDiskSerial +:sig: (name string) (serial string, err error) +include::{funcsig_tpl}[] `psDiskSerial` directly calls {godoc_root}/{mod_psutil}/disk#SerialNumber[`{mod_psutil}/disk.SerialNumber`^]. [id="fn_ps_dsk_usg"] ===== `psDiskUsage` -[source,go] -.Function Signature ----- -func psDiskUsage(path string) (usage *disk.UsageStat, err error) ----- +:func: psDiskUsage +:sig: (path string) (usage *disk.UsageStat, err error) +include::{funcsig_tpl}[] `psDiskUsage` directly calls {godoc_root}/{mod_psutil}/disk#Usage[`{mod_psutil}/disk.Usage`^]. @@ -1550,61 +1598,49 @@ func psDiskUsage(path string) (usage *disk.UsageStat, err error) [id="fn_ps_hst_boot"] ===== `psHostBoot` -[source,go] -.Function Signature ----- -func psHostBoot() (bootEpoch uint64, err error) ----- +:func: psHostBoot +:sig: () (bootEpoch uint64, err error) +include::{funcsig_tpl}[] `psHostBoot` directly calls {godoc_root}/{mod_psutil}/host#BootTime[`{mod_psutil}/host.BootTime`^]. [id="fn_ps_hst_id"] ===== `psHostId` -[source,go] -.Function Signature ----- -func psHostId() (hostId string, err error) ----- +:func: psHostId +:sig: () (hostId string, err error) +include::{funcsig_tpl}[] `psHostId` directly calls {godoc_root}/{mod_psutil}/host#HostID[`{mod_psutil}/host.HostID`^]. [id="fn_ps_hst_info"] ===== `psHostInfo` -[source,go] -.Function Signature ----- -func psHostInfo() (info *host.InfoStat, err error) ----- +:func: psHostInfo +:sig: () (info *host.InfoStat, err error) +include::{funcsig_tpl}[] `psHostInfo` directly calls {godoc_root}/{mod_psutil}/host#Info[`{mod_psutil}/host.Info`^]. [id="fn_ps_hst_krnarch"] ===== `psHostKernArch` -[source,go] -.Function Signature ----- -func psHostKernArch() (arch string, err error) ----- +:func: psHostKernArch +:sig: () (arch string, err error) +include::{funcsig_tpl}[] `psHostKernArch` directly calls {godoc_root}/{mod_psutil}/host#KernelArch[`{mod_psutil}/host.KernelArch`^]. [id="fn_ps_hst_krnver"] ===== `psHostKernVer` -[source,go] -.Function Signature ----- -func psHostKernVer() (ver string, err error) ----- +:func: psHostKernVer +:sig: () (ver string, err error) +include::{funcsig_tpl}[] `psHostKernVer` directly calls {godoc_root}/{mod_psutil}/host#KernelVersion[`{mod_psutil}/host.KernelVersion`^]. [id="fn_ps_hst_plat"] ===== `psHostPlatInfo` -[source,go] -.Function Signature ----- -func psHostPlatInfo() (platInfo [3]string, err error) ----- +:func: psHostPlatInfo +:sig: () (platInfo [3]string, err error) +include::{funcsig_tpl}[] `psHostPlatInfo` wraps {godoc_root}/{mod_psutil}/host#PlatformInformation[`{mod_psutil}/host.PlatformInformation`^]. @@ -1612,31 +1648,25 @@ It is necessary to wrap because the function normally returns `(string, string, [id="fn_ps_hst_uptm"] ===== `psHostPlatUptime` -[source,go] -.Function Signature ----- -func psHostPlatUptime() (uptimeSecs uint64, err error) ----- +:func: psHostPlatUptime +:sig: () (uptimeSecs uint64, err error) +include::{funcsig_tpl}[] `psHostPlatUptime` directly calls {godoc_root}/{mod_psutil}/host#Uptime[`{mod_psutil}/host.Uptime`^]. [id="fn_ps_hst_usrs"] ===== `psHostUsers` -[source,go] -.Function Signature ----- -func psHostUsers() (users []host.UserStat, err error) ----- +:func: psHostUsers +:sig: () (users []host.UserStat, err error) +include::{funcsig_tpl}[] `psHostUsers` directly calls {godoc_root}/{mod_psutil}/host#Users[`{mod_psutil}/host.Users`^]. [id="fn_ps_hst_virt"] ===== `psHostPlatVirt` -[source,go] -.Function Signature ----- -func psHostVirt() (virtInfo [2]string, err error) ----- +:func: psHostPlatVirt +:sig: () (virtInfo [2]string, err error) +include::{funcsig_tpl}[] `psHostPlatVirt` wraps {godoc_root}/{mod_psutil}/host#Virtualization[`{mod_psutil}/host.Virtualization`^]. @@ -1647,21 +1677,17 @@ It is necessary to wrap because the function normally returns `(string, string, [id="fn_ps_ld_avg"] ===== `psLoadAvg` -[source,go] -.Function Signature ----- -func psLoadAvg() (avg *load.AvgStat, err error) ----- +:func: psLoadAvg +:sig: () (avg *load.AvgStat, err error) +include::{funcsig_tpl}[] `psLoadAvg` directly calls {godoc_root}/{mod_psutil}/load#Avg[`{mod_psutil}/load.Avg`^]. [id="fn_ps_ld_misc"] ===== `psLoadMisc` -[source,go] -.Function Signature ----- -func psLoadMisc() (misc *load.MiscStat, err error) ----- +:func: psLoadMisc +:sig: () (misc *load.MiscStat, err error) +include::{funcsig_tpl}[] `psLoadMisc` directly calls {godoc_root}/{mod_psutil}/load#Misc[`{mod_psutil}/load.Misc`^]. @@ -1670,11 +1696,9 @@ func psLoadMisc() (misc *load.MiscStat, err error) [id="fn_ps_mem_exvmem"] ===== `psMemExVMem` -[source,go] -.Function Signature ----- -func psMemExVMem() (exVMem *mem.ExVirtualMemory, err error) ----- +:func: psMemExVMem +:sig: () (exVMem *mem.ExVirtualMemory, err error) +include::{funcsig_tpl}[] [WARNING] ==== @@ -1694,31 +1718,25 @@ link:{godoc_root}/{mod_psutil}/mem?GOOS=windows#NewExWindows[`{mod_psutil}/mem.N [id="fn_ps_mem_swap"] ===== `psMemSwap` -[source,go] -.Function Signature ----- -func psMemSwap() (swap *mem.SwapMemoryStat, err error) ----- +:func: psMemSwap +:sig: () (swap *mem.SwapMemoryStat, err error) +include::{funcsig_tpl}[] `psMemSwap` directly calls {godoc_root}/{mod_psutil}/mem#SwapMemory[`{mod_psutil}/mem.SwapMemory`^]. [id="fn_ps_mem_swapdevs"] ===== `psMemSwapDevs` -[source,go] -.Function Signature ----- -func psMemSwapDevs() (swapDevs []*mem.SwapDevice, err error) ----- +:func: psMemSwapDevs +:sig: () (swapDevs []*mem.SwapDevice, err error) +include::{funcsig_tpl}[] `psMemSwapDevs` directly calls {godoc_root}/{mod_psutil}/mem#SwapDevices[`{mod_psutil}/mem.SwapDevices`^]. [id="fn_ps_mem_vmem"] ===== `psMemVMem` -[source,go] -.Function Signature ----- -func psMemVMem() (vmem *mem.VirtualMemoryStat, err error) ----- +:func: psMemVMem +:sig: () (vmem *mem.VirtualMemoryStat, err error) +include::{funcsig_tpl}[] `psMemVMem` directly calls {godoc_root}/{mod_psutil}/mem#VirtualMemory[`{mod_psutil}/mem.VirtualMemory`^]. @@ -1727,121 +1745,97 @@ func psMemVMem() (vmem *mem.VirtualMemoryStat, err error) [id="fn_ps_net_conns"] ===== `psNetConns` -[source,go] -.Function Signature ----- -func psNetConns(kind string) (conns []net.ConnectionStat, err error) ----- +:func: psNetConns +:sig: (kind string) (conns []net.ConnectionStat, err error) +include::{funcsig_tpl}[] `psNetConns` directly calls {godoc_root}/{mod_psutil}/net#Connections[`{mod_psutil}/net.Connections`^]. [id="fn_ps_net_connsmax"] ===== `psNetConnsMax` -[source,go] -.Function Signature ----- -func psNetConnsMax(kind string, maxConn int) (conns []net.ConnectionStat, err error) ----- +:func: psNetConnsMax +:sig: (kind string, maxConn int) (conns []net.ConnectionStat, err error) +include::{funcsig_tpl}[] `psNetConnsMax` directly calls {godoc_root}/{mod_psutil}/net#ConnectionsMax[`{mod_psutil}/net.ConnectionsMax`^]. [id="fn_ps_net_connspid"] ===== `psNetConnsPid` -[source,go] -.Function Signature ----- -func psNetConnsPid(kind string, pid int32) (conns []net.ConnectionStat, err error) ----- +:func: psNetConnsPid +:sig: (kind string, pid int32) (conns []net.ConnectionStat, err error) +include::{funcsig_tpl}[] `psNetConnsPid` directly calls {godoc_root}/{mod_psutil}/net#ConnectionsPid[`{mod_psutil}/net.ConnectionsPid`^]. [id="fn_ps_net_connspidmax"] ===== `psNetConnsPidMax` -[source,go] -.Function Signature ----- -func psNetConnsPidMax(kind string, pid int32, maxConn int) (conns []net.ConnectionStat, err error) ----- +:func: psNetConnsPidMax +:sig: (kind string, pid int32, maxConn int) (conns []net.ConnectionStat, err error) +include::{funcsig_tpl}[] `psNetConnsPidMax` directly calls {godoc_root}/{mod_psutil}/net#ConnectionsPidMax[`{mod_psutil}/net.ConnectionsPidMax`^]. [id="fn_ps_net_ct"] ===== `psNetCTStats` -[source,go] -.Function Signature ----- -func psNetCTStats(percCpu bool) (ctStats []net.ConntrackStat, err error) ----- +:func: psNetCTStats +:sig: (percCpu bool) (ctStats []net.ConntrackStat, err error) +include::{funcsig_tpl}[] `psNetCTStats` directly calls {godoc_root}/{mod_psutil}/net#ConntrackStats[`{mod_psutil}/net.ConntrackStats`^]. [id="fn_ps_net_ctlist"] ===== `psNetCTStatList` -[source,go] -.Function Signature ----- -func psNetCTStatList() (ctStats *net.ConntrackStatList, err error) ----- +:func: psNetCTStatList +:sig: () (ctStats *net.ConntrackStatList, err error) +include::{funcsig_tpl}[] `psNetCTStatList` directly calls {godoc_root}/{mod_psutil}/net#ConntrackStatList[`{mod_psutil}/net.ConntrackStatList`^]. [id="fn_ps_net_fltcnt"] ===== `psNetFilterCnts` -[source,go] -.Function Signature ----- -func psNetFilterCnts() (filterCnts []net.FilterStat, err error) ----- +:func: psNetFilterCnts +:sig: () (filterCnts []net.FilterStat, err error) +include::{funcsig_tpl}[] `psNetFilterCnts` directly calls {godoc_root}/{mod_psutil}/net#FilterCounters[`{mod_psutil}/net.FilterCounters`^]. [id="fn_ps_net_iocnts"] ===== `psNetIoCnts` -[source,go] -.Function Signature ----- -func psNetIoCnts(perNIC bool) (ioCnts []net.IOCountersStat, err error) ----- +:func: psNetIoCnts +:sig: (perNIC bool) (ioCnts []net.IOCountersStat, err error) +include::{funcsig_tpl}[] `psNetIoCnts` directly calls {godoc_root}/{mod_psutil}/net#IOCounters[`{mod_psutil}/net.IOCounters`^]. [id="fn_ps_net_iocntsfl"] ===== `psNetIoCntsFile` -[source,go] -.Function Signature ----- -func psNetIoCntsFile(perNIC bool, filepath string) (ioCnts []net.IOCountersStat, err error) ----- +:func: psNetIoCntsFile +:sig: (perNIC bool, filepath string) (ioCnts []net.IOCountersStat, err error) +include::{funcsig_tpl}[] `psNetIoCntsFile` directly calls {godoc_root}/{mod_psutil}/net#IOCountersByFile[`{mod_psutil}/net.IOCountersByFile`^]. [id="fn_ps_net_ifaces"] ===== `psNetIfaces` -[source,go] -.Function Signature ----- -func psNetIfaces() (ioCnts []net.InterfaceStatList, err error) ----- +:func: psNetIfaces +:sig: () (ioCnts []net.InterfaceStatList, err error) +include::{funcsig_tpl}[] `psNetIfaces` directly calls {godoc_root}/{mod_psutil}/net#Interfaces[`{mod_psutil}/net.Interfaces`^]. [id="fn_ps_net_pids"] ===== `psNetPids` -[source,go] -.Function Signature ----- -func psNetPids() (pids []int32, err error) ----- +:func: psNetPids +:sig: () (pids []int32, err error) +include::{funcsig_tpl}[] `psNetPids` directly calls {godoc_root}/{mod_psutil}/net#Pids[`{mod_psutil}/net.Pids`^]. [id="fn_ps_net_protocnts"] ===== `psNetProtoCnt` -[source,go] -.Function Signature ----- -func psNetProtoCnt(protos []string) (protoCnts []net.ProtoCountersStat, err error) ----- +:func: psNetProtoCnt +:sig: (protos []string) (protoCnts []net.ProtoCountersStat, err error) +include::{funcsig_tpl}[] [WARNING] ==== @@ -1852,11 +1846,9 @@ This only works properly on Linux currently per upstream. [id="fn_ps_net_rev"] ===== `psNetRev` -[source,go] -.Function Signature ----- -func psNetRev(b []byte) (out []byte) ----- +:func: psNetRev +:sig: (b []byte) (out []byte) +include::{funcsig_tpl}[] [WARNING] ==== @@ -1870,41 +1862,33 @@ This function only exists on Linux. [id="fn_ps_procs_procs"] ===== `psProcs` -[source,go] -.Function Signature ----- -func psProcs(pid int32) (procs []*process.Process, err error) ----- +:func: psProcs +:sig: (pid int32) (procs []*process.Process, err error) +include::{funcsig_tpl}[] `psProcs` directly calls {godoc_root}/{mod_psutil}/process#Processes[`{mod_psutil}/proc.Processes`^]. [id="fn_ps_proc_new"] ===== `psProcNew` -[source,go] -.Function Signature ----- -func psProcNew(pid int32) (proc *process.Process, err error) ----- +:func: psProcNew +:sig: (pid int32) (proc *process.Process, err error) +include::{funcsig_tpl}[] `psProcNew` directly calls {godoc_root}/{mod_psutil}/process#NewProcess[`{mod_psutil}/proc.NewProcess`^]. [id="fn_ps_proc_pids"] ===== `psProcPids` -[source,go] -.Function Signature ----- -func psProcPids() (pids []int32, err error) ----- +:func: psProcPids +:sig: () (pids []int32, err error) +include::{funcsig_tpl}[] `psProcPids` directly calls {godoc_root}/{mod_psutil}/process#Pids[`{mod_psutil}/proc.Pids`^]. [id="fn_ps_proc_pidxst"] ===== `psProcPidExists` -[source,go] -.Function Signature ----- -func psProcPidExists(pid int32) (exists bool, err error) ----- +:func: psProcPidExists +:sig: (pid int32) (exists bool, err error) +include::{funcsig_tpl}[] `psProcPidExists` directly calls {godoc_root}/{mod_psutil}/process#PidExists[`{mod_psutil}/proc.PidExists`^]. @@ -1913,11 +1897,9 @@ func psProcPidExists(pid int32) (exists bool, err error) [id="fn_ps_sns_extemp"] ===== `psSensorExTemp` -[source,go] -.Function Signature ----- -func psSensorExTemp() (temps []sensors.ExTemperature, err error) ----- +:func: psSensorExTemp +:sig: () (temps []sensors.ExTemperature, err error) +include::{funcsig_tpl}[] [WARNING] ==== @@ -1928,11 +1910,9 @@ This function only exists on Linux. [id="fn_ps_sns_temps"] ===== `psSensorTemps` -[source,go] -.Function Signature ----- -func psSensorTemps() (temps []sensors.TemperatureStat, err error) ----- +:func: psSensorTemps +:sig: () (temps []sensors.TemperatureStat, err error) +include::{funcsig_tpl}[] `psSensorTemps` directly calls {godoc_root}/{mod_psutil}/sensors#SensorsTemperatures[`{mod_psutil}/sensors.SensorsTemperatures`^]. @@ -1946,11 +1926,9 @@ All of these functions are only available on Windows. [id="fn_ps_winsvc_list"] ===== `psWinsvcList` -[source,go] -.Function Signature ----- -func psWinsvcList() (svcs []winservices.Service, err error) ----- +:func: psWinsvcList +:sig: () (svcs []winservices.Service, err error) +include::{funcsig_tpl}[] [WARNING] ==== @@ -1961,11 +1939,9 @@ This function is only available on Windows. [id="fn_ps_winsvc_new"] ===== `psWinsvcNew` -[source,go] -.Function Signature ----- -func psWinsvcNew(svcName string) (svc *winservices.Service, err error) ----- +:func: psWinsvcNew +:sig: (svcName string) (svc *winservices.Service, err error) +include::{funcsig_tpl}[] [WARNING] ==== @@ -1977,17 +1953,22 @@ This function is only available on Windows. [id="fn_str"] === Strings -[id="fn_str_extindent"] -==== `extIndent` -[source,go] -.Function Signature ----- -func extIndent( - levels int, - skipFirst, skipEmpty, skipWhitespace bool, - indentString, input string, - ) (out string) ----- +These template functions use capabilities from: + +* <> +* <> + +[id="fn_str_stnd"] +==== Standalone + +These functions are standalone developed purely for this library. +For legacy reasons, these have the special prefix `ext`. + +[id="fn_str_stnd_extindent"] +===== `extIndent` +:func: extIndent +:sig: ({indnt}levels int,{indnt}skipFirst, skipEmpty, skipWhitespace bool,{indnt}indentString, input string,{nl}) (out string) +include::{funcsig_tpl}[] `extIndent` allows for a MUCH more flexible indenter than the `sprig` `indent` function. @@ -2012,46 +1993,138 @@ It has quite a few arguments, however: | input | string | The text to be indented. Because it is the last argument, `extIndent` works with pipelined text as well. |=== +[id="fn_str_strsx"] +==== `r00t2.io/goutils/stringsx` +These template functions contain capabilities from {godoc_root}/{mod_me}/netx[`{mod_me}/stringsx`^]. + +[id="fn_str_strsx_isascii"] +===== `strsxIsAscii` +:func: strsxIsAscii +:sig: (s string, allowCtl, allowExt bool) (isAscii bool, err error) +include::{funcsig_tpl}[] + +`strsxIsAscii` directly calls {godoc_root}/{import_me}/stringsx#IsAscii[`{import_me}/stringsx.IsAscii`^]. + +[id="fn_str_strsx_isasciibuf"] +===== `strsxIsAsciiBuf` +:func: strsxIsAsciiBuf +:sig: (r io.RuneReader, allowCtl, allowExt bool) (isAscii bool, err error) +include::{funcsig_tpl}[] + +`strsxIsAsciiBuf` directly calls {godoc_root}/{import_me}/stringsx#IsAsciiBuf[`{import_me}/stringsx.IsAsciiBuf`^]. + +[id="fn_str_strsx_isasciispcl"] +===== `strsxIsAsciiSpcl` +:func: strsxIsAsciiSpcl +:sig: ({indnt}s string,{indnt}allowCtl, allowPrint, allowExt, allowWs bool,{indnt}incl, excl []byte{nl}) (isAscii bool, err error) +include::{funcsig_tpl}[] + +`strsxIsAsciiSpcl` directly calls {godoc_root}/{import_me}/stringsx#IsAsciiSpecial[`{import_me}/stringsx.IsAsciiSpecial`^]. + +[id="fn_str_strsx_isasciibufspcl"] +===== `strsxIsAsciiBufSpcl` +:func: strsxIsAsciiBufSpcl +:sig: ({indnt}r io.RuneReader,{indnt}allowCtl, allowPrint, allowExt, allowWs bool,{indnt}incl, excl []byte{nl}) (isAscii bool, err error) +include::{funcsig_tpl}[] + +`strsxIsAsciiBufSpcl` directly calls {godoc_root}/{import_me}/stringsx#IsAsciiSpecial[`{import_me}/stringsx.IsAsciiSpecial`^]. + +[id="fn_str_strsx_lenspl"] +===== `strsxLenSpl` +:func: strsxLenSpl +:sig: (s string, width uint) (out []string) +include::{funcsig_tpl}[] + +`strsxLenSpl` directly calls {godoc_root}/{import_me}/stringsx#LenSplit[`{import_me}/stringsx.LenSplit`^]. + +[id="fn_str_strsx_lensplstr"] +===== `strsxLenSplStr` +:func: strsxLenSplStr +:sig: (s string, width uint, winNewline bool) (out string) +include::{funcsig_tpl}[] + +`strsxLenSplStr` directly calls {godoc_root}/{import_me}/stringsx#LenSplitStr[`{import_me}/stringsx.LenSplitStr`^]. + +[id="fn_str_strsx_pad"] +===== `strsxPad` +:func: strsxPad +:sig: (s []string, width uint, pad string, leftPad bool) (out []string) +include::{funcsig_tpl}[] + +`strsxPad` directly calls {godoc_root}/{import_me}/stringsx#Pad[`{import_me}/stringsx.Pad`^]. + +[id="fn_str_strsx_rdct"] +===== `strsxRedact` +:func: strsxRedact +:sig: (s, maskStr string, leading, trailing uint, newlines bool) (redacted string) +include::{funcsig_tpl}[] + +`strsxRedact` directly calls {godoc_root}/{import_me}/stringsx#Redact[`{import_me}/stringsx.Redact`^]. + +[id="fn_str_strsx_rev"] +===== `strsxRev` +:func: strsxRev +:sig: (s string) (revS string) +include::{funcsig_tpl}[] + +`strsxRev` directly calls {godoc_root}/{import_me}/stringsx#Reverse[`{import_me}/stringsx.Reverse`^]. + +[id="fn_str_strsx_trimlns"] +===== `strsxTrimLns` +:func: strsxTrimLns +:sig: (s string, left, right bool) (trimmed string) +include::{funcsig_tpl}[] + +`strsxTrimLns` directly calls {godoc_root}/{import_me}/stringsx#TrimLines[`{import_me}/stringsx.TrimLines`^]. + +[id="fn_str_strsx_trimspcl"] +===== `strsxTrimSpcLft` +:func: strsxTrimSpcLft +:sig: (s string) (trimmed string) +include::{funcsig_tpl}[] + +`strsxTrimSpcLft` directly calls {godoc_root}/{import_me}/stringsx#TrimSpaceLeft[`{import_me}/stringsx.TrimSpaceLeft`^]. + +[id="fn_str_strsx_trimspcr"] +===== `strsxTrimSpcRt` +:func: strsxTrimSpcRt +:sig: (s string) (trimmed string) +include::{funcsig_tpl}[] + +`strsxTrimSpcRt` directly calls {godoc_root}/{import_me}/stringsx#TrimSpaceRight[`{import_me}/stringsx.TrimSpaceRight`^]. + [id="fn_sys"] === System/Platform/Architecture [id="fn_sys_arch"] ==== `sysArch` -[source,go] -.Function Signature ----- -func sysArch() (out string) ----- +:func: sysArch +:sig: () (out string) +include::{funcsig_tpl}[] Returns the {godoc_root}/runtime#GOARCH[`runtime.GOARCH`^] constant. [id="fn_sys_numcpu"] ==== `sysNumCpu` -[source,go] -.Function Signature ----- -func sysNumCpu() (cnt int) ----- +:func: sysNumCpu +:sig: () (cnt int) +include::{funcsig_tpl}[] `sysNumCpu` directly calls {godoc_root}/runtime#NumCPU[`runtime.NumCPU`^]. [id="fn_sys_os"] ==== `sysOsName` -[source,go] -.Function Signature ----- -func sysOsNm() (out string) ----- +:func: sysOsName +:sig: () (out string) +include::{funcsig_tpl}[] Returns the {godoc_root}/runtime#GOOS[`runtime.GOOS`^] constant. [id="fn_sys_rntm"] ==== `sysRuntime` -[source,go] -.Function Signature ----- -func sysRuntime() (out map[string]string) ----- +:func: sysRuntime +:sig: () (out map[string]string) +include::{funcsig_tpl}[] This function returns a `map[string]string` of various information from the {godoc_root}/runtime[`runtime` stdlib library^]. @@ -2097,61 +2170,49 @@ Care has been taken to name these functions differently from the Sprig functions [id="fn_tm_date"] ==== `tmDate` -[source,go] -.Function Signature ----- -func tmDate(year int, month time.Month, day, hour, min, sec, nsec int, loc *time.Location) (date time.Time) ----- +:func: tmDate +:sig: (year int, month time.Month, day, hour, min, sec, nsec int, loc *time.Location) (date time.Time) +include::{funcsig_tpl}[] `tmDate` directly calls {godoc_root}/time#Date[`time.Date`^]. [id="fn_tm_fltmic"] ==== `tmFloatMicro` -[source,go] -.Function Signature ----- -func tmFloatMicro(t time.Time) (f64 float64) ----- +:func: tmFloatMicro +:sig: (t time.Time) (f64 float64) +include::{funcsig_tpl}[] `tmFloatMicro` directly calls {godoc_root}/r00t2.io/goutils/timex#F64Microseconds[`(r00t2.io/goutils/timex).F64Microseconds`^]. [id="fn_tm_fltmill"] ==== `tmFloatMilli` -[source,go] -.Function Signature ----- -func tmFloatMilli(t time.Time) (f64 float64) ----- +:func: tmFloatMilli +:sig: (t time.Time) (f64 float64) +include::{funcsig_tpl}[] `tmFloatMilli` directly calls {godoc_root}/r00t2.io/goutils/timex#F64Milliseconds[`(r00t2.io/goutils/timex).F64Milliseconds`^]. [id="fn_tm_fltnano"] ==== `tmFloatNano` -[source,go] -.Function Signature ----- -func tmFloatNano(t time.Time) (f64 float64) ----- +:func: tmFloatNano +:sig: (t time.Time) (f64 float64) +include::{funcsig_tpl}[] `tmFloatNano` directly calls {godoc_root}/r00t2.io/goutils/timex#F64Nanoseconds[`(r00t2.io/goutils/timex).F64Nanoseconds`^]. [id="fn_tm_flt"] ==== `tmFloat` -[source,go] -.Function Signature ----- -func tmFloat(t time.Time) (f64 float64) ----- +:func: tmFloat +:sig: (t time.Time) (f64 float64) +include::{funcsig_tpl}[] `tmFloat` directly calls {godoc_root}/r00t2.io/goutils/timex#F64Seconds[`(r00t2.io/goutils/timex).F64Seconds`^]. [id="fn_tm_fmt"] ==== `tmFmt` -[source,go] -.Function Signature ----- -func tmFmt(fstr string, t time.Time) (out string) ----- +:func: tmFmt +:sig: (fstr string, t time.Time) (out string) +include::{funcsig_tpl}[] `tmFormat` provides a more pipeline-friendly alternative to calling e.g. @@ -2163,41 +2224,33 @@ func tmFmt(fstr string, t time.Time) (out string) [id="fn_tm_now"] ==== `tmNow` -[source,go] -.Function Signature ----- -func tmNow() (now time.Time) ----- +:func: tmNow +:sig: () (now time.Time) +include::{funcsig_tpl}[] `tmNow` directly calls {godoc_root}/time#Now[`time.Now`^]. [id="fn_tm_pdur8n"] ==== `tmParseDur8n` -[source,go] -.Function Signature ----- -func tmParseDur8n(s string) (d time.Duration, err error) ----- +:func: tmParseDur8n +:sig: (s string) (d time.Duration, err error) +include::{funcsig_tpl}[] `tmParseDur8n` directly calls {godoc_root}/time#ParseDuration[`time.ParseDuration`^]. [id="fn_tm_pmnth"] ==== `tmParseMonth` -[source,go] -.Function Signature ----- -func tmParseMonth(v any) (mon time.Month, err error) ----- +:func: tmParseMonth +:sig: (v any) (mon time.Month, err error) +include::{funcsig_tpl}[] `tmParseMonth` attempts to first try <> and then tries <> if `v` is not "numeric". [id="fn_tm_pmnthi"] ==== `tmParseMonthInt` -[source,go] -.Function Signature ----- -func tmParseMonthInt(n any) (mon time.Month, err error) ----- +:func: tmParseMonthInt +:sig: (n any) (mon time.Month, err error) +include::{funcsig_tpl}[] `tmParseMonthInt` parses a number representation of month `n` to a {godoc_root}/time#Month[`time.Month`^]. `n` may be any numeric type or a string representation of a number (or a custom type derived from those). @@ -2227,11 +2280,9 @@ If `n` resolves to > `12`, `err` will be `sprigx.ErrBadMonth` (though be sure to [id="fn_tm_pmnths"] ==== `tmParseMonthStr` -[source,go] -.Function Signature ----- -func tmParseMonthStr(s string) (mon time.Month, err error) ----- +:func: tmParseMonthStr +:sig: (s string) (mon time.Month, err error) +include::{funcsig_tpl}[] `tmParseMonthStr` parses a string representation `s` of a month to a {godoc_root}/time#Month[`time.Month`^]. @@ -2242,12 +2293,128 @@ An empty (or whitespace-only) string will use the current month (as determined b [id="fn_tm_ptm"] ==== `tmParseTime` -[source,go] -.Function Signature ----- -func tmParseTime(layout, value string) (t time.Time, err error) ----- +:func: tmParseTime +:sig: (layout, value string) (t time.Time, err error) +include::{funcsig_tpl}[] `tmParseTime` directly calls {godoc_root}/time#Parse[`time.Parse`^]. Be sure that `layout` is a properly parseable {godoc_root}/time#Layout[layout format^]. + +[id="todo"] +== TODO/Wishlist + +[id="todo_collctns"] +=== Function Collections +Functions should be split into more granular function maps that allows a conusmer to only load a certain subset of relevant functions to reduce surface - string functions, network functions, etc. + +This would ideally also allow for e.g. FuncMap "generators" that would return a FuncMap of methods bound to a struct with certain contextual settings (e.g. a root path restriction for <>). + +[id="todo_fallible"] +=== Fallibility +Requires <> first. + +Modeled after Vector's VRL concept of https://vector.dev/docs/reference/vrl/#fallibility[_Fallibility_^] (https://vector.dev/docs/reference/vrl/expressions/#function-fallibility[see also^]). + +Functions should be grouped/selectable by "fallibility" - if they are guaranteed to return a *meaningful* value always, if they are guaranteed to return a value that *may be empty* but no error will be returned, or if a function *may* return an error. + +[id="todo_safe"] +=== Function Scope Segregation +Requires <> first. + +Modeled (slightly) after Vector's VRL concept of https://vector.dev/docs/reference/vrl/expressions/#purity[purity^]. + +As more functions get added (and even with the present function set), it may be desired that only functions that work only with provided data are exposed to templates. + +The goal is to scope/separate functions in such a way that they are "tagged" with multiple attributes/characteristics: + +* <> +* External Read (e.g. <>) +* Internal Modify (would potentially transform source data/data structures) +* External Modify (would affect the invoking system, e.g. <>) +* Arbitrary Execution (e.g. `osExec` -- see <>) +* Network Access (e.g. would involve creating network connections instead of operating on provided data locally) + +A risk "score" from 1-10 should also be implemented with the above scopes/classes for further/alternative filtering by consumers. + +[id="todo_os"] +=== Extend OS functions +Requires <> first. (Not technically, but can provide a pretty big risk of not split out first.) + +[id="todo_os_fs"] +Adding the ability to read files from the filesystem should be added. As part of this, however, a package-level variable should be implemented +(or <>) that can restrict reading to a specific prefix. + +Off the top of my head: + +* `osReadFile` +** Returns an `*os.File`. +** Closing the handler gets tricky, though... it can be done from within the template, but templates also have no `defer` to my knowledge. Caveat emptor. +* `osReadFileBuf` +** Will return a `*bytes.Buffer` with the contents of a file. +** A little safer than `osReadFile` as it's backed by a static set of bytes and doesn't need to be ``.Close()``'d. +* `osReadFileBytes` +** Should include an optional length limiter, so data from e.g. `/dev/urandom` can be read from. +* `osReadFileStr` +** Would return `string` instead of `[]byte`. +* `osReadDir` +** Returns a `[]fs.DirEntry` of a given path via `os.ReadDir`. +* `osStat` +** Returns an `fs.FileInfo` from an `os.Stat` or `os.LStat` (controlled by tpl function parameter) +* `osExec` +** Exactly what you'd think. Returns a command via an `os/exec.Cmd`, with params passed to `os/exec.Command` (plus ``*bytes.Buffer``s set to `.Stdin` and `.Stdout`). + +These obviously have the potential to be *incredibly* dangerous if using untrusted template strings. + +[id="todo_os_env"] +==== Environment Variables + +* `osEnvGet` (`os.Getenv`) +* `osEnvs` (returns `os.Environ` result) +* `osEnvsMap` and other https://pkg.go.dev/r00t2.io/sysutils/envs[`r00t2.io/sysutils/envs`^] funcs + +[id="todo_sys"] +=== System Functions +This would be... particularly tricky. + +I essentially want to expose a large amount of functionality from https://pkg.go.dev/golang.org/x/sys/unix[`golang.org/x/sys/unix`^] and https://pkg.go.dev/golang.org/x/sys@v0.46.0/windows[`golang.org/x/sys/windows`^] +(and its https://pkg.go.dev/golang.org/x/sys@v0.46.0/windows#section-directories[subpackages^]). + +At the least I should have a way to (attempt to) convert/coerce an `fs.FileInfo.Sys()` into the platform-appropriate definite object +(e.g. a https://pkg.go.dev/golang.org/x/sys/unix#Stat_t[`golang.org/x/sys/unix.Stat_t`^] and/or +https://pkg.go.dev/golang.org/x/sys/unix#Statx_t[`golang.org/x/sys/unix.Statx_t`^], +or a https://pkg.go.dev/golang.org/x/sys/windows#Win32FileAttributeData[`golang.org/x/sys/windows.Win32FileAttributeData`^]). + +[id="todo_encode"] +=== Encoding Functions +Should require <> first (at least for grouping). + +* `hex*` functions ({godoc_root}/encoding/hex[`encoding/hex`^]) +** Technically hex is "base16" +* `hexx*` functions ({godoc_root}/r00t2.io/goutils/encodingx/hexx[`r00t2.io/goutils/encodingx/hexx`^]) +* `b64*` functions ({godoc_root}/encoding/base64[`encoding/base64`^]) + +[id="todo_uuid"] +=== UUID Functions +Should require <> first (at least for grouping). + +* `uuid*` functions for {godoc_root}/github.com/google/uuid[`github.com/google/uuid`^] +* `uuidx*` functions for {godoc_root}/r00t2.io/goutils/uuidx[`r00t2.io/goutils/uuidx`^] + +[id="todo_url"] +=== URL Functions +Expose {godoc_root}net/url/[`net/url`^] functions to derive URLs. + +[id="todo_net"] +=== Live Networking Functions +Requires <> first. + +Sometimes networking data lookup is needed at time of render/contextual to render. + +* `dns*` (DNS lookup options from {godoc_root}/[`net`^]) +** With the ability to use a custom resolver (would need <>) +* `http*` functions +** `httpReq` for a {godoc_root}/net/http#Request[`net/http.Request`^] +** `http` for a shorthand/one-shot version of `httpReq` above +** `resty*` functions for {godoc_root}/resty.dev/v3[`resty.dev/v3`^]? +*** Maybe via a configured <> instead diff --git a/tplx/sprigx/README.html b/tplx/sprigx/README.html index 24e2880..e605c8c 100644 --- a/tplx/sprigx/README.html +++ b/tplx/sprigx/README.html @@ -636,7 +636,7 @@ pre.rouge .gs {
Brent Saner

-Last rendered 2026-02-24 17:42:00 -0500 +Last rendered 2026-06-22 18:51:24 -0400
Table of Contents
@@ -670,223 +670,283 @@ pre.rouge .gs {
  • 5.2. "Meta"/Template Helpers +
  • +
  • 5.3. Numbers/Math -
  • -
  • 5.4. Numbers/Math +
  • 5.4. Operating System
  • -
  • 5.5. Operating System +
  • 5.5. Paths +
  • +
  • 5.6. PSUtil
  • -
  • 5.7. PSUtil +
  • 5.7. Strings
  • -
  • 5.8. Strings +
  • 5.8. System/Platform/Architecture
  • -
  • 5.9. System/Platform/Architecture +
  • 5.9. Time/Dates/Timestamps
  • -
  • 5.10. Time/Dates/Timestamps + +
  • +
  • 6. TODO/Wishlist +
  • @@ -1184,7 +1244,7 @@ var (
    Function Signature
    -
    func CombinedFuncMap(preferSprigX bool) (fmap map[string]any)
    +
    func CombinedFuncMap(preferSprigX bool) (fmap map[string]any)
    @@ -1205,7 +1265,7 @@ as they wrap this with the appropriate type.

    Function Signature
    -
    func CombinedHtmlFuncMap(preferSprigX bool) (fmap template.FuncMap)
    +
    func CombinedHtmlFuncMap(preferSprigX bool) (fmap template.FuncMap)
    @@ -1222,7 +1282,7 @@ If false, Sprig functions will override conflicting SprigX functions with the sa
    Function Signature
    -
    func CombinedTxtFuncMap(preferSprigX bool) (fmap template.FuncMap)
    +
    func CombinedTxtFuncMap(preferSprigX bool) (fmap template.FuncMap)
    @@ -1239,7 +1299,7 @@ If false, Sprig functions will override conflicting SprigX functions with the sa
    Function Signature
    -
    func FuncMap() (fmap map[string]any)
    +
    func FuncMap() (fmap map[string]any)
    @@ -1255,7 +1315,7 @@ as they wrap this with the appropriate type.

    Function Signature
    -
    func HtmlFuncMap() (fmap template.FuncMap)
    +
    func HtmlFuncMap() (fmap template.FuncMap)
    @@ -1267,7 +1327,7 @@ as they wrap this with the appropriate type.

    Function Signature
    -
    func Nop(obj ...any) (s string)
    +
    func Nop(obj ...any) (s string)
    @@ -1283,7 +1343,7 @@ certain Sprig/SprigX functions that may be deemed "unsafe" and/or to sanitize te
    Function Signature
    -
    func TxtFuncMap() (fmap template.FuncMap)
    +
    func TxtFuncMap() (fmap template.FuncMap)
    @@ -1325,7 +1385,7 @@ what it returns, and the returned value(s) type(s).

    Function Signature
    -
    func dump(a ...interface{}) (out string)
    +
    func dump(a ...interface{}) (out string)
    @@ -1341,7 +1401,7 @@ for whatever object(s) is/are passed to it.

    Function Signature
    -
    func metaIsNil(obj any) (isNil bool)
    +
    func metaIsNil(obj any) (isNil bool)
    @@ -1350,13 +1410,13 @@ for whatever object(s) is/are passed to it.

    This function fills in the gap that text/template.IsTrue and html/template.IsTrue (expressed in templates as {{ if …​ }}) leaves, as those functions/expressions return false for e.g. false booleans AND nils.

    +
    +
    +
    	[id="fn_net_all"]
    +=== Networking
    +These template functions use capabilities from:
    -
    -

    5.3. Networking

    -
    -

    These template functions use capabilities from:

    -

    The function prefix is used to indicate which module/package a function is added from.

    +
    -

    5.3.1. net

    +

    5.2.2. net

    These template functions contain capabilities from net.

    -
    5.3.1.1. netCidrMask
    +
    5.2.2.1. netCidrMask
    Function Signature
    -
    func netCidrMask(ones, bits int) (mask net.IPMask)
    +
    func netCidrMask(ones, bits int) (mask net.IPMask)
    @@ -1391,11 +1458,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.1.2. netExtractAddr
    +
    5.2.2.2. netExtractAddr
    Function Signature
    -
    func netExtractAddr(s string) (addr net.IP, err error)
    +
    func netExtractAddr(s string) (addr net.IP, err error)
    @@ -1403,11 +1470,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.1.3. netExtractHost
    +
    5.2.2.3. netExtractHost
    Function Signature
    -
    func netExtractHost(hostPort string) (host string, err error)
    +
    func netExtractHost(hostPort string) (host string, err error)
    @@ -1415,11 +1482,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.1.4. netExtractIpnet
    +
    5.2.2.4. netExtractIpnet
    Function Signature
    -
    func netExtractIpnet(s string) (ipNet *net.IPNet, err error)
    +
    func netExtractIpnet(s string) (ipNet *net.IPNet, err error)
    @@ -1427,11 +1494,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.1.5. netExtractPort
    +
    5.2.2.5. netExtractPort
    Function Signature
    -
    func netExtractPort(hostPort string) (port uint16, err error)
    +
    func netExtractPort(hostPort string) (port uint16, err error)
    @@ -1439,11 +1506,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.1.6. netIfaces
    +
    5.2.2.6. netIfaces
    Function Signature
    -
    func netIfaces() (ifaces []net.Interface, err error)
    +
    func netIfaces() (ifaces []net.Interface, err error)
    @@ -1451,11 +1518,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.1.7. netIp4Mask
    +
    5.2.2.7. netIp4Mask
    Function Signature
    -
    func netIp4Mask(a, b, c, d any) (mask net.IPMask, err error)
    +
    func netIp4Mask(a, b, c, d any) (mask net.IPMask, err error)
    @@ -1495,11 +1562,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.1.8. netJoinHostPort
    +
    5.2.2.8. netJoinHostPort
    Function Signature
    -
    func netJoinHostPort(host, port string) (out string)
    +
    func netJoinHostPort(host, port string) (out string)
    @@ -1507,11 +1574,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.1.9. netParseIP
    +
    5.2.2.9. netParseIP
    Function Signature
    -
    func netParseIP(s string) (ip net.IP)
    +
    func netParseIP(s string) (ip net.IP)
    @@ -1520,16 +1587,16 @@ for whatever object(s) is/are passed to it.

    -

    5.3.2. net/netip

    +

    5.2.3. net/netip

    These template functions contain capabilities from net/netip.

    -
    5.3.2.1. netipAddrPort
    +
    5.2.3.1. netipAddrPort
    Function Signature
    -
    func netipAddrPort(ip netip.Addr, port uint16) (addrPort netip.AddrPort)
    +
    func netipAddrPort(ip netip.Addr, port uint16) (addrPort netip.AddrPort)
    @@ -1537,11 +1604,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.2.2. netipParseAddr
    +
    5.2.3.2. netipParseAddr
    Function Signature
    -
    func netipParseAddr(s string) (addr netip.Addr, err error)
    +
    func netipParseAddr(s string) (addr netip.Addr, err error)
    @@ -1549,11 +1616,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.2.3. netipParseAddrPort
    +
    5.2.3.3. netipParseAddrPort
    Function Signature
    -
    func netipParseAddrPort(s string) (addrPort netip.AddrPort, err error)
    +
    func netipParseAddrPort(s string) (addrPort netip.AddrPort, err error)
    @@ -1561,11 +1628,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.2.4. netipParsePrefix
    +
    5.2.3.4. netipParsePrefix
    Function Signature
    -
    func netipParsePrefix(s string) (pfx netip.Prefix, err error)
    +
    func netipParsePrefix(s string) (pfx netip.Prefix, err error)
    @@ -1573,11 +1640,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.2.5. netipPrefix
    +
    5.2.3.5. netipPrefix
    Function Signature
    -
    func netipPrefix(ip netip.Addr, bits int) (pfx netip.Prefix)
    +
    func netipPrefix(ip netip.Addr, bits int) (pfx netip.Prefix)
    @@ -1586,16 +1653,16 @@ for whatever object(s) is/are passed to it.

    -

    5.3.3. go4.org/netipx

    +

    5.2.4. go4.org/netipx

    These template functions contain capabilities from go4.org/netipx.

    -
    5.3.3.1. netipxAddrIpNet
    +
    5.2.4.1. netipxAddrIpNet
    Function Signature
    -
    func netipxAddrIpNet(addr netip.Addr) (ipNet *net.IPNet)
    +
    func netipxAddrIpNet(addr netip.Addr) (ipNet *net.IPNet)
    @@ -1603,11 +1670,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.3.2. netipxCmpPfx
    +
    5.2.4.2. netipxCmpPfx
    Function Signature
    -
    func netipxCmpPfx(a, b netip.Prefix) (cmp int)
    +
    func netipxCmpPfx(a, b netip.Prefix) (cmp int)
    @@ -1615,11 +1682,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.3.3. netipxFromStdAddr
    +
    5.2.4.3. netipxFromStdAddr
    Function Signature
    -
    func netipxFromStdAddr(ip net.IP, port int, zone string) (addrPort netip.AddrPort, err error)
    +
    func netipxFromStdAddr(ip net.IP, port int, zone string) (addrPort netip.AddrPort, err error)
    @@ -1627,11 +1694,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.3.4. netipxFromIp
    +
    5.2.4.4. netipxFromIp
    Function Signature
    -
    func netipxFromIp(ip net.IP) (addr netip.Addr, err error)
    +
    func netipxFromIp(ip net.IP) (addr netip.Addr, err error)
    @@ -1639,11 +1706,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.3.5. netipxFromIpNet
    +
    5.2.4.5. netipxFromIpNet
    Function Signature
    -
    func netipxFromIpNet(ipNet *net.IPNet) (pfx netip.Prefix, err error)
    +
    func netipxFromIpNet(ipNet *net.IPNet) (pfx netip.Prefix, err error)
    @@ -1651,23 +1718,23 @@ for whatever object(s) is/are passed to it.

    -
    5.3.3.6. netipxParseRange
    +
    5.2.4.6. netipxParseRange
    Function Signature
    -
    func netipxParseRange(s string) (ipRange netipx.IPRange, err error)
    +
    func netipxParseRange(s string) (ipRange netipx.IPRange, err error)
    -

    netipxRange directly calls go4.org/netipx.ParseIPRange.

    +

    netipxParseRange directly calls go4.org/netipx.ParseIPRange.

    -
    5.3.3.7. netipxPfxAddr
    +
    5.2.4.7. netipxPfxAddr
    Function Signature
    -
    func netipxPfxAddr(s string) (addr netip.Addr, err error)
    +
    func netipxPfxAddr(s string) (addr netip.Addr, err error)
    @@ -1675,11 +1742,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.3.8. netipxPfxIpNet
    +
    5.2.4.8. netipxPfxIpNet
    Function Signature
    -
    func netipxPfxIpNet(pfx netip.Prefix) (ipNet *net.IPNet)
    +
    func netipxPfxIpNet(pfx netip.Prefix) (ipNet *net.IPNet)
    @@ -1687,11 +1754,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.3.9. netipxPfxLast
    +
    5.2.4.9. netipxPfxLast
    Function Signature
    -
    func netipxPfxLast(pfx netip.Prefix) (addr netip.Addr)
    +
    func netipxPfxLast(pfx netip.Prefix) (addr netip.Addr)
    @@ -1699,11 +1766,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.3.10. netipxPfxRange
    +
    5.2.4.10. netipxPfxRange
    Function Signature
    -
    func netipxPfxRange(pfx netip.Prefix) (ipRange netipx.IPRange)
    +
    func netipxPfxRange(pfx netip.Prefix) (ipRange netipx.IPRange)
    @@ -1711,11 +1778,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.3.11. netipxRange
    +
    5.2.4.11. netipxRange
    Function Signature
    -
    func netipxRange(from, to netip.Addr) (ipRange netipx.IPRange)
    +
    func netipxRange(from, to netip.Addr) (ipRange netipx.IPRange)
    @@ -1724,16 +1791,16 @@ for whatever object(s) is/are passed to it.

    -

    5.3.4. netx

    +

    5.2.5. r00t2.io/goutils/netx

    These template functions contain capabilities from r00t2.io/goutils/netx.

    -
    5.3.4.1. netxAddrRfc
    +
    5.2.5.1. netxAddrRfc
    Function Signature
    -
    func netxAddrRfc(addr netip.Addr) (rfcStr string)
    +
    func netxAddrRfc(addr netip.Addr) (rfcStr string)
    @@ -1741,11 +1808,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.4.2. netxCidr4IpMask
    +
    5.2.5.2. netxAddrRfc
    Function Signature
    -
    func netxCidr4IpMask(cidr uint8) (ipMask net.IPMask, err error)
    +
    func netxAddrRfc(cidr uint8) (ipMask net.IPMask, err error)
    @@ -1753,11 +1820,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.4.3. netxCidr4Mask
    +
    5.2.5.3. netxCidr4Mask
    Function Signature
    -
    func netxCidr4Mask(cidr uint8) (mask uint32, err error)
    +
    func netxCidr4Mask(cidr uint8) (mask uint32, err error)
    @@ -1765,11 +1832,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.4.4. netxCidr4Str
    +
    5.2.5.4. netxCidr4Str
    Function Signature
    -
    func netxCidr4Str(cidr uint8) (maskStr string, err error)
    +
    func netxCidr4Str(cidr uint8) (maskStr string, err error)
    @@ -1777,11 +1844,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.4.5. netxFamilyVer
    +
    5.2.5.5. netxFamilyVer
    Function Signature
    -
    func netxFamilyVer(family uint16) (ipVer int)
    +
    func netxFamilyVer(family uint16) (ipVer int)
    @@ -1789,11 +1856,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.4.6. netxGetAddrFam
    +
    5.2.5.6. netxGetAddrFam
    Function Signature
    -
    func netxGetAddrFam(addr netip.Addr) (family uint16)
    +
    func netxGetAddrFam(addr netip.Addr) (family uint16)
    @@ -1801,11 +1868,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.4.7. netxGetIpFam
    +
    5.2.5.7. netxGetIpFam
    Function Signature
    -
    func netxGetIpFam(ip net.IP) (family uint16)
    +
    func netxGetIpFam(ip net.IP) (family uint16)
    @@ -1813,11 +1880,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.4.8. netxIpRfc
    +
    5.2.5.8. netxIpRfc
    Function Signature
    -
    func netxIpRfc(ip net.IP) (rfcStr string)
    +
    func netxIpRfc(ip net.IP) (rfcStr string)
    @@ -1825,11 +1892,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.4.9. netxIpRfcStr
    +
    5.2.5.9. netxIpRfcStr
    Function Signature
    -
    func netxIpRfcStr(s string) (rfcStr string)
    +
    func netxIpRfcStr(s string) (rfcStr string)
    @@ -1837,11 +1904,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.4.10. netxIpStripRfc
    +
    5.2.5.10. netxIpStripRfc
    Function Signature
    -
    func netxIpStripRfc(s string) (stripStr string)
    +
    func netxIpStripRfc(s string) (stripStr string)
    @@ -1849,11 +1916,11 @@ for whatever object(s) is/are passed to it.

    -
    5.3.4.11. netxIp4MaskCidr
    +
    5.2.5.11. netxIp4MaskCidr
    Function Signature
    -
    func netxIp4MaskCidr(ipMask net.IPMask) (cidr uint8, err error)
    +
    func netxIp4MaskCidr(ipMask net.IPMask) (cidr uint8, err error)
    @@ -1861,27 +1928,309 @@ for whatever object(s) is/are passed to it.

    -
    5.3.4.12. netxIp4MaskMask
    +
    5.2.5.12. netxIp4MaskMask
    Function Signature
    -
    func netxIp4MaskMask(ipMask net.IPMask) (mask uint32, err error)
    +
    func netxIp4MaskMask(ipMask net.IPMask) (mask uint32, err error)

    netxIp4MaskMask directly calls r00t2.io/goutils/netx.IPMask4ToMask.

    -
    -
    -
    -

    5.4. Numbers/Math

    -
    -

    5.4.1. numFloat32Str

    +
    +
    5.2.5.13. netxIp4MaskStr
    Function Signature
    -
    func numFloat32Str(f float32) (s string)
    +
    func netxIp4MaskStr(ipMask net.IPMask) (maskStr string, err error)
    +
    +
    +
    +

    netxIp4MaskStr directly calls r00t2.io/goutils/netx.IPMask4ToStr.

    +
    +
    +
    +
    5.2.5.14. netxIpVerStr
    +
    +
    Function Signature
    +
    +
    func netxIpVerStr(s string) (ipVer int)
    +
    +
    +
    +

    netxIpVerStr directly calls r00t2.io/goutils/netx.IpVerStr.

    +
    +
    +
    +
    5.2.5.15. netxIsBrktd6
    +
    +
    Function Signature
    +
    +
    func netxIsBrktd6(s string) (isBrktdIp bool)
    +
    +
    +
    +

    netxIsBrktd6 directly calls r00t2.io/goutils/netx.IsBracketedIp6.

    +
    +
    +
    +
    5.2.5.16. netxIsIp
    +
    +
    Function Signature
    +
    +
    func netxIsIp(s string) (isIp bool)
    +
    +
    +
    +

    netxIsIp directly calls r00t2.io/goutils/netx.IsIpAddr.

    +
    +
    +
    +
    5.2.5.17. netxIsPfx
    +
    +
    Function Signature
    +
    +
    func netxIsPfx(s string) (isNet bool)
    +
    +
    +
    +

    netxIsPfx directly calls r00t2.io/goutils/netx.IsPrefixNet.

    +
    +
    +
    +
    5.2.5.18. netxMask4Cidr
    +
    +
    Function Signature
    +
    +
    func netxMask4Cidr(mask uint32) (cidr uint8, err error)
    +
    +
    +
    +

    netxMask4Cidr directly calls r00t2.io/goutils/netx.Mask4ToCidr.

    +
    +
    +
    +
    5.2.5.19. netxMask4StrCidr
    +
    +
    Function Signature
    +
    +
    func netxMask4StrCidr(maskStr string) (cidr uint8, err error)
    +
    +
    +
    +

    netxMask4StrCidr directly calls r00t2.io/goutils/netx.Mask4StrToCidr.

    +
    +
    +
    +
    5.2.5.20. netxMask4StrIpMask
    +
    +
    Function Signature
    +
    +
    func netxMask4StrIpMask(maskStr string) (mask net.IPMask, err error)
    +
    +
    +
    +

    netxMask4StrIpMask directly calls r00t2.io/goutils/netx.Mask4StrToIPMask.

    +
    +
    +
    +
    5.2.5.21. netxMask4StrMask
    +
    +
    Function Signature
    +
    +
    func netxMask4StrMask(maskStr string) (mask uint32, err error)
    +
    +
    +
    +

    netxMask4StrMask directly calls r00t2.io/goutils/netx.Mask4StrToMask.

    +
    +
    +
    +
    5.2.5.22. netxVerFamily
    +
    +
    Function Signature
    +
    +
    func netxVerFamily(ipVer int) (family uint16)
    +
    +
    +
    +

    netxVerFamily directly calls r00t2.io/goutils/netx.VerToFamily.

    +
    +
    +
    +
    +

    5.2.6. r00t2.io/goutils/netx/dnsx

    +
    +

    These template functions contain capabilities from r00t2.io/goutils/tplx/sprigx/netx/dnsx.

    +
    +
    +
    5.2.6.1. dnsxPtrAddr
    +
    +
    Function Signature
    +
    +
    func dnsxPtrAddr(s string) (ip netip.Addr, err error)
    +
    +
    + +
    +
    +
    5.2.6.2. dnsxAddrPtr
    +
    +
    Function Signature
    +
    +
    func dnsxAddrPtr(ip netip.Addr) (s string)
    +
    +
    +
    +

    dnsxAddrPtr directly calls r00t2.io/goutils/tplx/sprigx/netx/dnsx.AddrToPtr.

    +
    +
    +
    +
    5.2.6.3. dnsxStrWire
    +
    +
    Function Signature
    +
    +
    func dnsxStrWire(recordNm string) (recordNmBytes []byte, err error)
    +
    +
    + +
    +
    +
    5.2.6.4. dnsxWireStr
    +
    +
    Function Signature
    +
    +
    func dnsxWireStr(recordNmBytes []byte) (recordNm string, err error)
    +
    +
    + +
    +
    +
    5.2.6.5. dnsxPtrIp
    +
    +
    Function Signature
    +
    +
    func dnsxPtrIp(s string) (ip net.IP, err error)
    +
    +
    + +
    +
    +
    5.2.6.6. dnsxIpPtr
    +
    +
    Function Signature
    +
    +
    func dnsxIpPtr(ip net.IP) (s string)
    +
    +
    + +
    +
    +
    5.2.6.7. dnsxIsFqdn
    +
    +
    Function Signature
    +
    +
    func dnsxIsFqdn(s string) (fqdn bool)
    +
    +
    +
    +

    dnsxIsFqdn directly calls r00t2.io/goutils/tplx/sprigx/netx/dnsx.IsFqdn.

    +
    +
    +
    +
    5.2.6.8. dnsxIsTxt
    +
    +
    Function Signature
    +
    +
    func dnsxIsTxt(fqdn string) (isOk bool)
    +
    +
    + +
    +
    +
    5.2.6.9. dnsxIsNsec3
    +
    +
    Function Signature
    +
    +
    func dnsxIsNsec3(s string) (maybeNsec3 bool)
    +
    +
    + +
    +
    +
    5.2.6.10. dnsxIsSrv
    +
    +
    Function Signature
    +
    +
    func dnsxIsSrv(s string) (srv bool)
    +
    +
    + +
    +
    +
    5.2.6.11. dnsxIsWild
    +
    +
    Function Signature
    +
    +
    func dnsxIsWild(s string) (wildcard bool)
    +
    +
    + +
    +
    +
    5.2.6.12. dnsxIsLbl
    +
    +
    Function Signature
    +
    +
    func dnsxIsLbl(s string) (isLbl bool)
    +
    +
    + +
    +
    +
    5.2.6.13. dnsxIsPtr
    +
    +
    Function Signature
    +
    +
    func dnsxIsPtr(s string) (isPtr bool, addr net.IP)
    +
    +
    +
    +

    dnsxIsPtr directly calls r00t2.io/goutils/tplx/sprigx/netx/dnsx.IsPtr.

    +
    +
    +
    +
    +
    +

    5.3. Numbers/Math

    +
    +

    5.3.1. numFloat32Str

    +
    +
    Function Signature
    +
    +
    func numFloat32Str(f float32) (s string)
    @@ -1889,11 +2238,11 @@ for whatever object(s) is/are passed to it.

    -

    5.4.2. numFloat64

    +

    5.3.2. numFloat64

    Function Signature
    -
    func numFloat64(val any) (f float64, err error)
    +
    func numFloat64(val any) (f float64, err error)
    @@ -1901,11 +2250,11 @@ for whatever object(s) is/are passed to it.

    -

    5.4.3. numFloat64Str

    +

    5.3.3. numFloat64Str

    Function Signature
    -
    func numFloat64Str(f float64) (s string)
    +
    func numFloat64Str(f float64) (s string)
    @@ -1913,11 +2262,11 @@ for whatever object(s) is/are passed to it.

    -

    5.4.4. numFloatStr

    +

    5.3.4. numFloatStr

    Function Signature
    -
    func numFloatStr(val any) (s string, err error)
    +
    func numFloatStr(val any) (s string, err error)
    @@ -1929,13 +2278,13 @@ for whatever object(s) is/are passed to it.

    -

    5.5. Operating System

    +

    5.4. Operating System

    -

    5.5.1. osFQDN

    +

    5.4.1. osFQDN

    Function Signature
    -
    func osFQDN() (fqdn string, err error)
    +
    func osFQDN() (fqdn string, err error)
    @@ -1955,11 +2304,11 @@ To directly/predictably use -

    5.5.2. osGroupById

    +

    5.4.2. osGroupById

    Function Signature
    -
    func osGroupById[T string | int](gid T) (g *user.Group, err error)
    +
    func osGroupById[T string | int](gid T) (g *user.Group, err error)
    @@ -1971,11 +2320,11 @@ except it will accept either a string or an
    -

    5.5.3. osGroupByName

    +

    5.4.3. osGroupByName

    Function Signature
    -
    func osGroupByName(grpNm string) (g *user.Group, err error)
    +
    func osGroupByName(grpNm string) (g *user.Group, err error)
    @@ -1986,11 +2335,11 @@ except it will accept either a string or an
    -

    5.5.4. osHost

    +

    5.4.4. osHost

    Function Signature
    -
    func osHost() (out string, err error)
    +
    func osHost() (out string, err error)
    @@ -2028,11 +2377,11 @@ To directly use -

    5.5.5. osHostname

    +

    5.4.5. osHostname

    Function Signature
    -
    func osHostname() (out string, err error)
    +
    func osHostname() (out string, err error)
    @@ -2040,11 +2389,11 @@ To directly use -

    5.5.6. osIdState

    +

    5.4.6. osIdState

    Function Signature
    -
    func osIdState() (idst sysutils.IDState)
    +
    func osIdState() (idst sysutils.IDState)
    @@ -2069,11 +2418,11 @@ To directly use -

    5.5.7. osUser

    +

    5.4.7. osUser

    Function Signature
    -
    func osUser() (u *user.User, err error)
    +
    func osUser() (u *user.User, err error)
    @@ -2084,11 +2433,11 @@ To directly use -

    5.5.8. osUserById

    +

    5.4.8. osUserById

    Function Signature
    -
    func osUserById[T string | int](uid T) (u *user.User, err error)
    +
    func osUserById[T string | int](uid T) (u *user.User, err error)
    @@ -2100,11 +2449,11 @@ except it will accept either a string or an
    -

    5.5.9. osUserByName

    +

    5.4.9. osUserByName

    Function Signature
    -
    func osUserByName(userNm string) (u *user.User, err error)
    +
    func osUserByName(userNm string) (u *user.User, err error)
    @@ -2116,18 +2465,18 @@ except it will accept either a string or an
    -

    5.6. Paths

    +

    5.5. Paths

    -

    5.6.1. Generic

    +

    5.5.1. Generic

    These operate similar to the path stdlib library and use a fixed / path separator.

    -
    5.6.1.1. pathJoin
    +
    5.5.1.1. pathJoin
    Function Signature
    -
    func pathJoin(elem ...string) (out string)
    +
    func pathJoin(elem ...string) (out string)
    @@ -2167,11 +2516,11 @@ unless you are explicitly appending a pipeline result to a path
    -
    5.6.1.2. pathPipeJoin
    +
    5.5.1.2. pathPipeJoin
    Function Signature
    -
    func pathPipeJoin(elems ...string) (out string)
    +
    func pathPipeJoin(elems ...string) (out string)
    @@ -2201,11 +2550,11 @@ as the last element to the next pipe function.

    -
    5.6.1.3. pathSliceJoin
    +
    5.5.1.3. pathSliceJoin
    Function Signature
    -
    func pathSliceJoin(sl []string) (out string)
    +
    func pathSliceJoin(sl []string) (out string)
    @@ -2245,17 +2594,25 @@ a/b/c
    -
    5.6.1.4. pathSlicePipeJoin
    +
    5.5.1.4. pathSlicePipeJoin
    Function Signature
    -
    func pathSlicePipeJoin(sl []string, root string) (out string)
    +
    func pathSlicePipeJoin(sl []string, root string) (out string)
    -

    pathSlicePipeJoin operates like pathPipeJoin in that it is suitable for pipeline use in which the root/base path is passed in -from the pipeline, but it is like pathSliceJoin in that it then also accepts a slice of -path segments ([]string) to append to that base path.

    +

    pathSlicePipeJoin operates like a hybrid of pathPipeJoin and pathSliceJoin:

    +
    +
    +
      +
    • +

      Like pathPipeJoin, it is suitable for pipeline use — the root/base path is passed in from the pipeline

      +
    • +
    • +

      Like pathSliceJoin, it also accepts a slice of path segments ([]string) to append to that base path

      +
    • +
    @@ -2290,11 +2647,11 @@ path segments ([]string) to append to that base path.

    -
    5.6.1.5. pathSubJoin
    +
    5.5.1.5. pathSubJoin
    Function Signature
    -
    func pathSubJoin(root string, elems ...string) (out string)
    +
    func pathSubJoin(root string, elems ...string) (out string)
    @@ -2323,7 +2680,7 @@ path segments ([]string) to append to that base path.

    -

    5.6.2. OS/Platform-Tailored

    +

    5.5.2. OS/Platform-Tailored

    These operate similar to the path/filepath stdlib library, and use the OS-specific os.PathSeparator.

    @@ -2345,11 +2702,11 @@ path segments ([]string) to append to that base path.

    -
    5.6.2.1. osPathJoin
    +
    5.5.2.1. osPathJoin
    Function Signature
    -
    func osPathJoin(elem ...string) (out string)
    +
    func osPathJoin(elem ...string) (out string)
    @@ -2420,11 +2777,11 @@ C:/a/b/c
    -
    5.6.2.2. osPathPipeJoin
    +
    5.5.2.2. osPathPipeJoin
    Function Signature
    -
    func osPathPipeJoin(elems ...string) (out string)
    +
    func osPathJoin(elems ...string) (out string)
    @@ -2481,11 +2838,11 @@ as the last argument to the next pipe function.

    -
    5.6.2.3. osPathSep
    +
    5.5.2.3. osPathSep
    Function Signature
    -
    func osPathSep() (out string)
    +
    func osPathSep() (out string)
    @@ -2531,11 +2888,11 @@ as the last argument to the next pipe function.

    -
    5.6.2.4. osPathSliceJoin
    +
    5.5.2.4. osPathSliceJoin
    Function Signature
    -
    func osPathSliceJoin(sl []string) (out string)
    +
    func osPathSliceJoin(sl []string) (out string)
    @@ -2602,11 +2959,11 @@ a/b/c
    -
    5.6.2.5. osPathSlicePipeJoin
    +
    5.5.2.5. osPathSlicePipeJoin
    Function Signature
    -
    func osPathSlicePipeJoin(sl []string, root string) (out string)
    +
    func osPathSlicePipeJoin(sl []string, root string) (out string)
    @@ -2671,11 +3028,11 @@ a/b/c
    -
    5.6.2.6. osPathSubJoin
    +
    5.5.2.6. osPathSubJoin
    Function Signature
    -
    func osPathSubJoin(root string, elems ...string) (out string)
    +
    func osPathSubJoin(root string, elems ...string) (out string)
    @@ -2732,18 +3089,18 @@ a/b/c
    -

    5.7. PSUtil

    +

    5.6. PSUtil

    These are functions from github.com/shirou/gopsutil/v4 packages.

    -

    5.7.1. CPU/Processor

    +

    5.6.1. CPU/Processor

    -
    5.7.1.1. psCpuCnts
    +
    5.6.1.1. psCpuCnts
    Function Signature
    -
    func psCpuCnts(logical bool) (numCpu int, err error)
    +
    func psCpuCnts(logical bool) (numCpu int, err error)
    @@ -2751,11 +3108,11 @@ a/b/c
    -
    5.7.1.2. psCpuInfo
    +
    5.6.1.2. psCpuInfo
    Function Signature
    -
    func psCpuInfo() (cpuInfo []cpu.Info, err error)
    +
    func psCpuInfo() (cpuInfo []cpu.Info, err error)
    @@ -2763,11 +3120,11 @@ a/b/c
    -
    5.7.1.3. psCpuPct
    +
    5.6.1.3. psCpuPct
    Function Signature
    -
    func psCpuPct(interval time.Duration, percpu bool) (pcts []float64, err error)
    +
    func psCpuPct(interval time.Duration, percpu bool) (pcts []float64, err error)
    @@ -2775,11 +3132,11 @@ a/b/c
    -
    5.7.1.4. psCpuTimes
    +
    5.6.1.4. psCpuTimes
    Function Signature
    -
    func psCpuTimes(percpu bool) (cpuTimes []cpu.TimesStat, err error)
    +
    func psCpuTimes(percpu bool) (cpuTimes []cpu.TimesStat, err error)
    @@ -2788,13 +3145,13 @@ a/b/c
    -

    5.7.2. Disk

    +

    5.6.2. Disk

    -
    5.7.2.1. psDiskIoCnts
    +
    5.6.2.1. psDiskIoCnts
    Function Signature
    -
    func psDiskIoCnts(names ...string) (stats map[string]disk.IOCountersStat, err error)
    +
    func psDiskIoCnts(names ...string) (stats map[string]disk.IOCountersStat, err error)
    @@ -2802,11 +3159,11 @@ a/b/c
    -
    5.7.2.2. psDiskLabel
    +
    5.6.2.2. psDiskLabel
    Function Signature
    -
    func psDiskLabel(name string) (label string, err error)
    +
    func psDiskLabel(name string) (label string, err error)
    @@ -2814,11 +3171,11 @@ a/b/c
    -
    5.7.2.3. psDiskParts
    +
    5.6.2.3. psDiskParts
    Function Signature
    -
    func psDiskParts(all bool) (parts []disk.PartitionStat, err error)
    +
    func psDiskParts(all bool) (parts []disk.PartitionStat, err error)
    @@ -2826,11 +3183,11 @@ a/b/c
    -
    5.7.2.4. psDiskSerial
    +
    5.6.2.4. psDiskSerial
    Function Signature
    -
    func psDiskSerial(name string) (serial string, err error)
    +
    func psDiskSerial(name string) (serial string, err error)
    @@ -2838,11 +3195,11 @@ a/b/c
    -
    5.7.2.5. psDiskUsage
    +
    5.6.2.5. psDiskUsage
    Function Signature
    -
    func psDiskUsage(path string) (usage *disk.UsageStat, err error)
    +
    func psDiskUsage(path string) (usage *disk.UsageStat, err error)
    @@ -2851,13 +3208,13 @@ a/b/c
    -

    5.7.3. Host

    +

    5.6.3. Host

    -
    5.7.3.1. psHostBoot
    +
    5.6.3.1. psHostBoot
    Function Signature
    -
    func psHostBoot() (bootEpoch uint64, err error)
    +
    func psHostBoot() (bootEpoch uint64, err error)
    @@ -2865,11 +3222,11 @@ a/b/c
    -
    5.7.3.2. psHostId
    +
    5.6.3.2. psHostId
    Function Signature
    -
    func psHostId() (hostId string, err error)
    +
    func psHostId() (hostId string, err error)
    @@ -2877,11 +3234,11 @@ a/b/c
    -
    5.7.3.3. psHostInfo
    +
    5.6.3.3. psHostInfo
    Function Signature
    -
    func psHostInfo() (info *host.InfoStat, err error)
    +
    func psHostInfo() (info *host.InfoStat, err error)
    @@ -2889,11 +3246,11 @@ a/b/c
    -
    5.7.3.4. psHostKernArch
    +
    5.6.3.4. psHostKernArch
    Function Signature
    -
    func psHostKernArch() (arch string, err error)
    +
    func psHostKernArch() (arch string, err error)
    @@ -2901,11 +3258,11 @@ a/b/c
    -
    5.7.3.5. psHostKernVer
    +
    5.6.3.5. psHostKernVer
    Function Signature
    -
    func psHostKernVer() (ver string, err error)
    +
    func psHostKernVer() (ver string, err error)
    @@ -2913,11 +3270,11 @@ a/b/c
    -
    5.7.3.6. psHostPlatInfo
    +
    5.6.3.6. psHostPlatInfo
    Function Signature
    -
    func psHostPlatInfo() (platInfo [3]string, err error)
    +
    func psHostPlatInfo() (platInfo [3]string, err error)
    @@ -2928,11 +3285,11 @@ a/b/c
    -
    5.7.3.7. psHostPlatUptime
    +
    5.6.3.7. psHostPlatUptime
    Function Signature
    -
    func psHostPlatUptime() (uptimeSecs uint64, err error)
    +
    func psHostPlatUptime() (uptimeSecs uint64, err error)
    @@ -2940,11 +3297,11 @@ a/b/c
    -
    5.7.3.8. psHostUsers
    +
    5.6.3.8. psHostUsers
    Function Signature
    -
    func psHostUsers() (users []host.UserStat, err error)
    +
    func psHostUsers() (users []host.UserStat, err error)
    @@ -2952,11 +3309,11 @@ a/b/c
    -
    5.7.3.9. psHostPlatVirt
    +
    5.6.3.9. psHostPlatVirt
    Function Signature
    -
    func psHostVirt() (virtInfo [2]string, err error)
    +
    func psHostPlatVirt() (virtInfo [2]string, err error)
    @@ -2968,13 +3325,13 @@ a/b/c
    -

    5.7.4. Load

    +

    5.6.4. Load

    -
    5.7.4.1. psLoadAvg
    +
    5.6.4.1. psLoadAvg
    Function Signature
    -
    func psLoadAvg() (avg *load.AvgStat, err error)
    +
    func psLoadAvg() (avg *load.AvgStat, err error)
    @@ -2982,11 +3339,11 @@ a/b/c
    -
    5.7.4.2. psLoadMisc
    +
    5.6.4.2. psLoadMisc
    Function Signature
    -
    func psLoadMisc() (misc *load.MiscStat, err error)
    +
    func psLoadMisc() (misc *load.MiscStat, err error)
    @@ -2995,13 +3352,13 @@ a/b/c
    -

    5.7.5. Memory

    +

    5.6.5. Memory

    -
    5.7.5.1. psMemExVMem
    +
    5.6.5.1. psMemExVMem
    Function Signature
    -
    func psMemExVMem() (exVMem *mem.ExVirtualMemory, err error)
    +
    func psMemExVMem() (exVMem *mem.ExVirtualMemory, err error)
    @@ -3048,11 +3405,11 @@ a/b/c
    -
    5.7.5.2. psMemSwap
    +
    5.6.5.2. psMemSwap
    Function Signature
    -
    func psMemSwap() (swap *mem.SwapMemoryStat, err error)
    +
    func psMemSwap() (swap *mem.SwapMemoryStat, err error)
    @@ -3060,11 +3417,11 @@ a/b/c
    -
    5.7.5.3. psMemSwapDevs
    +
    5.6.5.3. psMemSwapDevs
    Function Signature
    -
    func psMemSwapDevs() (swapDevs []*mem.SwapDevice, err error)
    +
    func psMemSwapDevs() (swapDevs []*mem.SwapDevice, err error)
    @@ -3072,11 +3429,11 @@ a/b/c
    -
    5.7.5.4. psMemVMem
    +
    5.6.5.4. psMemVMem
    Function Signature
    -
    func psMemVMem() (vmem *mem.VirtualMemoryStat, err error)
    +
    func psMemVMem() (vmem *mem.VirtualMemoryStat, err error)
    @@ -3085,13 +3442,13 @@ a/b/c
    -

    5.7.6. Network

    +

    5.6.6. Network

    -
    5.7.6.1. psNetConns
    +
    5.6.6.1. psNetConns
    Function Signature
    -
    func psNetConns(kind string) (conns []net.ConnectionStat, err error)
    +
    func psNetConns(kind string) (conns []net.ConnectionStat, err error)
    @@ -3099,11 +3456,11 @@ a/b/c
    -
    5.7.6.2. psNetConnsMax
    +
    5.6.6.2. psNetConnsMax
    Function Signature
    -
    func psNetConnsMax(kind string, maxConn int) (conns []net.ConnectionStat, err error)
    +
    func psNetConnsMax(kind string, maxConn int) (conns []net.ConnectionStat, err error)
    @@ -3111,11 +3468,11 @@ a/b/c
    -
    5.7.6.3. psNetConnsPid
    +
    5.6.6.3. psNetConnsPid
    Function Signature
    -
    func psNetConnsPid(kind string, pid int32) (conns []net.ConnectionStat, err error)
    +
    func psNetConnsPid(kind string, pid int32) (conns []net.ConnectionStat, err error)
    @@ -3123,11 +3480,11 @@ a/b/c
    -
    5.7.6.4. psNetConnsPidMax
    +
    5.6.6.4. psNetConnsPidMax
    Function Signature
    -
    func psNetConnsPidMax(kind string, pid int32, maxConn int) (conns []net.ConnectionStat, err error)
    +
    func psNetConnsPidMax(kind string, pid int32, maxConn int) (conns []net.ConnectionStat, err error)
    @@ -3135,11 +3492,11 @@ a/b/c
    -
    5.7.6.5. psNetCTStats
    +
    5.6.6.5. psNetCTStats
    Function Signature
    -
    func psNetCTStats(percCpu bool) (ctStats []net.ConntrackStat, err error)
    +
    func psNetCTStats(percCpu bool) (ctStats []net.ConntrackStat, err error)
    @@ -3147,11 +3504,11 @@ a/b/c
    -
    5.7.6.6. psNetCTStatList
    +
    5.6.6.6. psNetCTStatList
    Function Signature
    -
    func psNetCTStatList() (ctStats *net.ConntrackStatList, err error)
    +
    func psNetCTStatList() (ctStats *net.ConntrackStatList, err error)
    @@ -3159,11 +3516,11 @@ a/b/c
    -
    5.7.6.7. psNetFilterCnts
    +
    5.6.6.7. psNetFilterCnts
    Function Signature
    -
    func psNetFilterCnts() (filterCnts []net.FilterStat, err error)
    +
    func psNetFilterCnts() (filterCnts []net.FilterStat, err error)
    @@ -3171,11 +3528,11 @@ a/b/c
    -
    5.7.6.8. psNetIoCnts
    +
    5.6.6.8. psNetIoCnts
    Function Signature
    -
    func psNetIoCnts(perNIC bool) (ioCnts []net.IOCountersStat, err error)
    +
    func psNetIoCnts(perNIC bool) (ioCnts []net.IOCountersStat, err error)
    @@ -3183,11 +3540,11 @@ a/b/c
    -
    5.7.6.9. psNetIoCntsFile
    +
    5.6.6.9. psNetIoCntsFile
    Function Signature
    -
    func psNetIoCntsFile(perNIC bool, filepath string) (ioCnts []net.IOCountersStat, err error)
    +
    func psNetIoCntsFile(perNIC bool, filepath string) (ioCnts []net.IOCountersStat, err error)
    @@ -3195,11 +3552,11 @@ a/b/c
    -
    5.7.6.10. psNetIfaces
    +
    5.6.6.10. psNetIfaces
    Function Signature
    -
    func psNetIfaces() (ioCnts []net.InterfaceStatList, err error)
    +
    func psNetIfaces() (ioCnts []net.InterfaceStatList, err error)
    @@ -3207,11 +3564,11 @@ a/b/c
    -
    5.7.6.11. psNetPids
    +
    5.6.6.11. psNetPids
    Function Signature
    -
    func psNetPids() (pids []int32, err error)
    +
    func psNetPids() (pids []int32, err error)
    @@ -3219,11 +3576,11 @@ a/b/c
    -
    5.7.6.12. psNetProtoCnt
    +
    5.6.6.12. psNetProtoCnt
    Function Signature
    -
    func psNetProtoCnt(protos []string) (protoCnts []net.ProtoCountersStat, err error)
    +
    func psNetProtoCnt(protos []string) (protoCnts []net.ProtoCountersStat, err error)
    @@ -3245,11 +3602,11 @@ a/b/c
    -
    5.7.6.13. psNetRev
    +
    5.6.6.13. psNetRev
    Function Signature
    -
    func psNetRev(b []byte) (out []byte)
    +
    func psNetRev(b []byte) (out []byte)
    @@ -3272,13 +3629,13 @@ a/b/c
    -

    5.7.7. Processes

    +

    5.6.7. Processes

    -
    5.7.7.1. psProcs
    +
    5.6.7.1. psProcs
    Function Signature
    -
    func psProcs(pid int32) (procs []*process.Process, err error)
    +
    func psProcs(pid int32) (procs []*process.Process, err error)
    @@ -3286,11 +3643,11 @@ a/b/c
    -
    5.7.7.2. psProcNew
    +
    5.6.7.2. psProcNew
    Function Signature
    -
    func psProcNew(pid int32) (proc *process.Process, err error)
    +
    func psProcNew(pid int32) (proc *process.Process, err error)
    @@ -3298,11 +3655,11 @@ a/b/c
    -
    5.7.7.3. psProcPids
    +
    5.6.7.3. psProcPids
    Function Signature
    -
    func psProcPids() (pids []int32, err error)
    +
    func psProcPids() (pids []int32, err error)
    @@ -3310,11 +3667,11 @@ a/b/c
    -
    5.7.7.4. psProcPidExists
    +
    5.6.7.4. psProcPidExists
    Function Signature
    -
    func psProcPidExists(pid int32) (exists bool, err error)
    +
    func psProcPidExists(pid int32) (exists bool, err error)
    @@ -3323,13 +3680,13 @@ a/b/c
    -

    5.7.8. Sensors/Thermals

    +

    5.6.8. Sensors/Thermals

    -
    5.7.8.1. psSensorExTemp
    +
    5.6.8.1. psSensorExTemp
    Function Signature
    -
    func psSensorExTemp() (temps []sensors.ExTemperature, err error)
    +
    func psSensorExTemp() (temps []sensors.ExTemperature, err error)
    @@ -3351,11 +3708,11 @@ a/b/c
    -
    5.7.8.2. psSensorTemps
    +
    5.6.8.2. psSensorTemps
    Function Signature
    -
    func psSensorTemps() (temps []sensors.TemperatureStat, err error)
    +
    func psSensorTemps() (temps []sensors.TemperatureStat, err error)
    @@ -3364,7 +3721,7 @@ a/b/c
    -

    5.7.9. Windows Services

    +

    5.6.9. Windows Services

    @@ -3380,11 +3737,11 @@ a/b/c
    -
    5.7.9.1. psWinsvcList
    +
    5.6.9.1. psWinsvcList
    Function Signature
    -
    func psWinsvcList() (svcs []winservices.Service, err error)
    +
    func psWinsvcList() (svcs []winservices.Service, err error)
    @@ -3406,11 +3763,11 @@ a/b/c
    -
    5.7.9.2. psWinsvcNew
    +
    5.6.9.2. psWinsvcNew
    Function Signature
    -
    func psWinsvcNew(svcName string) (svc *winservices.Service, err error)
    +
    func psWinsvcNew(svcName string) (svc *winservices.Service, err error)
    @@ -3434,17 +3791,36 @@ a/b/c
    -

    5.8. Strings

    +

    5.7. Strings

    +
    +

    These template functions use capabilities from:

    +
    +
    -

    5.8.1. extIndent

    +

    5.7.1. Standalone

    +
    +

    These functions are standalone developed purely for this library. +For legacy reasons, these have the special prefix ext.

    +
    +
    +
    5.7.1.1. extIndent
    Function Signature
    -
    func extIndent(
    -		levels int,
    -		skipFirst, skipEmpty, skipWhitespace bool,
    -		indentString, input string,
    -	) (out string)
    +
    func extIndent(
    + levels int,
    + skipFirst, skipEmpty, skipWhitespace bool,
    + indentString, input string,
    +) (out string)
    @@ -3530,14 +3906,173 @@ a/b/c
    -
    -

    5.9. System/Platform/Architecture

    -

    5.9.1. sysArch

    +

    5.7.2. r00t2.io/goutils/stringsx

    +
    +

    These template functions contain capabilities from r00t2.io/goutils/stringsx.

    +
    +
    +
    5.7.2.1. strsxIsAscii
    Function Signature
    -
    func sysArch() (out string)
    +
    func strsxIsAscii(s string, allowCtl, allowExt bool) (isAscii bool, err error)
    +
    +
    +
    +

    strsxIsAscii directly calls r00t2.io/goutils/tplx/sprigx/stringsx.IsAscii.

    +
    +
    +
    +
    5.7.2.2. strsxIsAsciiBuf
    +
    +
    Function Signature
    +
    +
    func strsxIsAsciiBuf(r io.RuneReader, allowCtl, allowExt bool) (isAscii bool, err error)
    +
    +
    +
    +

    strsxIsAsciiBuf directly calls r00t2.io/goutils/tplx/sprigx/stringsx.IsAsciiBuf.

    +
    +
    +
    +
    5.7.2.3. strsxIsAsciiSpcl
    +
    +
    Function Signature
    +
    +
    func strsxIsAsciiSpcl(
    + s string,
    + allowCtl, allowPrint, allowExt, allowWs bool,
    + incl, excl []byte
    +) (isAscii bool, err error)
    +
    +
    +
    +

    strsxIsAsciiSpcl directly calls r00t2.io/goutils/tplx/sprigx/stringsx.IsAsciiSpecial.

    +
    +
    +
    +
    5.7.2.4. strsxIsAsciiBufSpcl
    +
    +
    Function Signature
    +
    +
    func strsxIsAsciiBufSpcl(
    + r io.RuneReader,
    + allowCtl, allowPrint, allowExt, allowWs bool,
    + incl, excl []byte
    +) (isAscii bool, err error)
    +
    +
    +
    +

    strsxIsAsciiBufSpcl directly calls r00t2.io/goutils/tplx/sprigx/stringsx.IsAsciiSpecial.

    +
    +
    +
    +
    5.7.2.5. strsxLenSpl
    +
    +
    Function Signature
    +
    +
    func strsxLenSpl(s string, width uint) (out []string)
    +
    +
    +
    +

    strsxLenSpl directly calls r00t2.io/goutils/tplx/sprigx/stringsx.LenSplit.

    +
    +
    +
    +
    5.7.2.6. strsxLenSplStr
    +
    +
    Function Signature
    +
    +
    func strsxLenSplStr(s string, width uint, winNewline bool) (out string)
    +
    +
    +
    +

    strsxLenSplStr directly calls r00t2.io/goutils/tplx/sprigx/stringsx.LenSplitStr.

    +
    +
    +
    +
    5.7.2.7. strsxPad
    +
    +
    Function Signature
    +
    +
    func strsxPad(s []string, width uint, pad string, leftPad bool) (out []string)
    +
    +
    +
    +

    strsxPad directly calls r00t2.io/goutils/tplx/sprigx/stringsx.Pad.

    +
    +
    +
    +
    5.7.2.8. strsxRedact
    +
    +
    Function Signature
    +
    +
    func strsxRedact(s, maskStr string, leading, trailing uint, newlines bool) (redacted string)
    +
    +
    +
    +

    strsxRedact directly calls r00t2.io/goutils/tplx/sprigx/stringsx.Redact.

    +
    +
    +
    +
    5.7.2.9. strsxRev
    +
    +
    Function Signature
    +
    +
    func strsxRev(s string) (revS string)
    +
    +
    + +
    +
    +
    5.7.2.10. strsxTrimLns
    +
    +
    Function Signature
    +
    +
    func strsxTrimLns(s string, left, right bool) (trimmed string)
    +
    +
    +
    +

    strsxTrimLns directly calls r00t2.io/goutils/tplx/sprigx/stringsx.TrimLines.

    +
    +
    +
    +
    5.7.2.11. strsxTrimSpcLft
    +
    +
    Function Signature
    +
    +
    func strsxTrimSpcLft(s string) (trimmed string)
    +
    +
    +
    +

    strsxTrimSpcLft directly calls r00t2.io/goutils/tplx/sprigx/stringsx.TrimSpaceLeft.

    +
    +
    +
    +
    5.7.2.12. strsxTrimSpcRt
    +
    +
    Function Signature
    +
    +
    func strsxTrimSpcRt(s string) (trimmed string)
    +
    +
    +
    +

    strsxTrimSpcRt directly calls r00t2.io/goutils/tplx/sprigx/stringsx.TrimSpaceRight.

    +
    +
    +
    +
    +
    +

    5.8. System/Platform/Architecture

    +
    +

    5.8.1. sysArch

    +
    +
    Function Signature
    +
    +
    func sysArch() (out string)
    @@ -3545,11 +4080,11 @@ a/b/c
    -

    5.9.2. sysNumCpu

    +

    5.8.2. sysNumCpu

    Function Signature
    -
    func sysNumCpu() (cnt int)
    +
    func sysNumCpu() (cnt int)
    @@ -3557,11 +4092,11 @@ a/b/c
    -

    5.9.3. sysOsName

    +

    5.8.3. sysOsName

    Function Signature
    -
    func sysOsNm() (out string)
    +
    func sysOsName() (out string)
    @@ -3569,11 +4104,11 @@ a/b/c
    -

    5.9.4. sysRuntime

    +

    5.8.4. sysRuntime

    Function Signature
    -
    func sysRuntime() (out map[string]string)
    +
    func sysRuntime() (out map[string]string)
    @@ -3665,7 +4200,7 @@ a/b/c
    -

    5.10. Time/Dates/Timestamps

    +

    5.9. Time/Dates/Timestamps

    @@ -3684,11 +4219,11 @@ a/b/c
    -

    5.10.1. tmDate

    +

    5.9.1. tmDate

    Function Signature
    -
    func tmDate(year int, month time.Month, day, hour, min, sec, nsec int, loc *time.Location) (date time.Time)
    +
    func tmDate(year int, month time.Month, day, hour, min, sec, nsec int, loc *time.Location) (date time.Time)
    @@ -3696,11 +4231,11 @@ a/b/c
    -

    5.10.2. tmFloatMicro

    +

    5.9.2. tmFloatMicro

    Function Signature
    -
    func tmFloatMicro(t time.Time) (f64 float64)
    +
    func tmFloatMicro(t time.Time) (f64 float64)
    @@ -3708,11 +4243,11 @@ a/b/c
    -

    5.10.3. tmFloatMilli

    +

    5.9.3. tmFloatMilli

    Function Signature
    -
    func tmFloatMilli(t time.Time) (f64 float64)
    +
    func tmFloatMilli(t time.Time) (f64 float64)
    @@ -3720,11 +4255,11 @@ a/b/c
    -

    5.10.4. tmFloatNano

    +

    5.9.4. tmFloatNano

    Function Signature
    -
    func tmFloatNano(t time.Time) (f64 float64)
    +
    func tmFloatNano(t time.Time) (f64 float64)
    @@ -3732,11 +4267,11 @@ a/b/c
    -

    5.10.5. tmFloat

    +

    5.9.5. tmFloat

    Function Signature
    -
    func tmFloat(t time.Time) (f64 float64)
    +
    func tmFloat(t time.Time) (f64 float64)
    @@ -3744,11 +4279,11 @@ a/b/c
    -

    5.10.6. tmFmt

    +

    5.9.6. tmFmt

    Function Signature
    -
    func tmFmt(fstr string, t time.Time) (out string)
    +
    func tmFmt(fstr string, t time.Time) (out string)
    @@ -3762,11 +4297,11 @@ a/b/c
    -

    5.10.7. tmNow

    +

    5.9.7. tmNow

    Function Signature
    -
    func tmNow() (now time.Time)
    +
    func tmNow() (now time.Time)
    @@ -3774,11 +4309,11 @@ a/b/c
    -

    5.10.8. tmParseDur8n

    +

    5.9.8. tmParseDur8n

    Function Signature
    -
    func tmParseDur8n(s string) (d time.Duration, err error)
    +
    func tmParseDur8n(s string) (d time.Duration, err error)
    @@ -3786,11 +4321,11 @@ a/b/c
    -

    5.10.9. tmParseMonth

    +

    5.9.9. tmParseMonth

    Function Signature
    -
    func tmParseMonth(v any) (mon time.Month, err error)
    +
    func tmParseMonth(v any) (mon time.Month, err error)
    @@ -3798,11 +4333,11 @@ a/b/c
    -

    5.10.10. tmParseMonthInt

    +

    5.9.10. tmParseMonthInt

    Function Signature
    -
    func tmParseMonthInt(n any) (mon time.Month, err error)
    +
    func tmParseMonthInt(n any) (mon time.Month, err error)
    @@ -3866,11 +4401,11 @@ a/b/c
    -

    5.10.11. tmParseMonthStr

    +

    5.9.11. tmParseMonthStr

    Function Signature
    -
    func tmParseMonthStr(s string) (mon time.Month, err error)
    +
    func tmParseMonthStr(s string) (mon time.Month, err error)
    @@ -3885,11 +4420,11 @@ uniqueness - "June" vs. "July", "March" vs. "May").

    -

    5.10.12. tmParseTime

    +

    5.9.12. tmParseTime

    Function Signature
    -
    func tmParseTime(layout, value string) (t time.Time, err error)
    +
    func tmParseTime(layout, value string) (t time.Time, err error)
    @@ -3902,6 +4437,294 @@ uniqueness - "June" vs. "July", "March" vs. "May").

    +
    +

    6. TODO/Wishlist

    +
    +
    +

    6.1. Function Collections

    +
    +

    Functions should be split into more granular function maps that allows a conusmer to only load a certain subset of relevant functions to reduce surface - string functions, network functions, etc.

    +
    +
    +

    This would ideally also allow for e.g. FuncMap "generators" that would return a FuncMap of methods bound to a struct with certain contextual settings (e.g. a root path restriction for Extend OS functions).

    +
    +
    +
    +

    6.2. Fallibility

    +
    +

    Requires Function Collections first.

    +
    +
    +

    Modeled after Vector’s VRL concept of Fallibility (see also).

    +
    +
    +

    Functions should be grouped/selectable by "fallibility" - if they are guaranteed to return a meaningful value always, if they are guaranteed to return a value that may be empty but no error will be returned, or if a function may return an error.

    +
    +
    +
    +

    6.3. Function Scope Segregation

    +
    +

    Requires Function Collections first.

    +
    +
    +

    Modeled (slightly) after Vector’s VRL concept of purity.

    +
    +
    +

    As more functions get added (and even with the present function set), it may be desired that only functions that work only with provided data are exposed to templates.

    +
    +
    +

    The goal is to scope/separate functions in such a way that they are "tagged" with multiple attributes/characteristics:

    +
    +
    +
      +
    • +

      Fallibility

      +
    • +
    • +

      External Read (e.g. reading arbitrary files)

      +
    • +
    • +

      Internal Modify (would potentially transform source data/data structures)

      +
    • +
    • +

      External Modify (would affect the invoking system, e.g. [todo_os_fs])

      +
    • +
    • +

      Arbitrary Execution (e.g. osExec — see [todo_os_fs])

      +
    • +
    • +

      Network Access (e.g. would involve creating network connections instead of operating on provided data locally)

      +
    • +
    +
    +
    +

    A risk "score" from 1-10 should also be implemented with the above scopes/classes for further/alternative filtering by consumers.

    +
    +
    +
    +

    6.4. Extend OS functions

    +
    +

    Requires Function Scope Segregation first. (Not technically, but can provide a pretty big risk of not split out first.)

    +
    +
    +

    Adding the ability to read files from the filesystem should be added. As part of this, however, a package-level variable should be implemented +(or Function Collections) that can restrict reading to a specific prefix.

    +
    +
    +

    Off the top of my head:

    +
    +
    +
      +
    • +

      osReadFile

      +
      +
        +
      • +

        Returns an *os.File.

        +
      • +
      • +

        Closing the handler gets tricky, though…​ it can be done from within the template, but templates also have no defer to my knowledge. Caveat emptor.

        +
      • +
      +
      +
    • +
    • +

      osReadFileBuf

      +
      +
        +
      • +

        Will return a *bytes.Buffer with the contents of a file.

        +
      • +
      • +

        A little safer than osReadFile as it’s backed by a static set of bytes and doesn’t need to be .Close()'d.

        +
      • +
      +
      +
    • +
    • +

      osReadFileBytes

      +
      +
        +
      • +

        Should include an optional length limiter, so data from e.g. /dev/urandom can be read from.

        +
      • +
      +
      +
    • +
    • +

      osReadFileStr

      +
      +
        +
      • +

        Would return string instead of []byte.

        +
      • +
      +
      +
    • +
    • +

      osReadDir

      +
      +
        +
      • +

        Returns a []fs.DirEntry of a given path via os.ReadDir.

        +
      • +
      +
      +
    • +
    • +

      osStat

      +
      +
        +
      • +

        Returns an fs.FileInfo from an os.Stat or os.LStat (controlled by tpl function parameter)

        +
      • +
      +
      +
    • +
    • +

      osExec

      +
      +
        +
      • +

        Exactly what you’d think. Returns a command via an os/exec.Cmd, with params passed to os/exec.Command (plus *bytes.Buffers set to <exec.Cmd>.Stdin and <exec.Cmd>.Stdout).

        +
      • +
      +
      +
    • +
    +
    +
    +

    These obviously have the potential to be incredibly dangerous if using untrusted template strings.

    +
    +
    +

    6.4.1. Environment Variables

    +
    +
      +
    • +

      osEnvGet (os.Getenv)

      +
    • +
    • +

      osEnvs (returns os.Environ result)

      +
    • +
    • +

      osEnvsMap and other r00t2.io/sysutils/envs funcs

      +
    • +
    +
    +
    +
    +
    +

    6.5. System Functions

    +
    +

    This would be…​ particularly tricky.

    +
    +
    +

    I essentially want to expose a large amount of functionality from golang.org/x/sys/unix and golang.org/x/sys/windows +(and its subpackages).

    +
    +
    +

    At the least I should have a way to (attempt to) convert/coerce an fs.FileInfo.Sys() into the platform-appropriate definite object +(e.g. a golang.org/x/sys/unix.Stat_t and/or +golang.org/x/sys/unix.Statx_t, +or a golang.org/x/sys/windows.Win32FileAttributeData).

    +
    +
    +
    +

    6.6. Encoding Functions

    +
    +

    Should require Function Collections first (at least for grouping).

    +
    +
    + +
    +
    +
    +

    6.7. UUID Functions

    +
    +

    Should require Function Collections first (at least for grouping).

    +
    +
    + +
    +
    +
    +

    6.8. URL Functions

    +
    +

    Expose net/url functions to derive URLs.

    +
    +
    +
    +

    6.9. Live Networking Functions

    +
    +

    Requires Function Scope Segregation first.

    +
    +
    +

    Sometimes networking data lookup is needed at time of render/contextual to render.

    +
    +
    +
      +
    • +

      dns* (DNS lookup options from net)

      +
      + +
      +
    • +
    • +

      http* functions

      +
      + +
      +
    • +
    +
    +
    +
    +

    @@ -3911,7 +4734,7 @@ uniqueness - "June" vs. "July", "March" vs. "May").

    diff --git a/tplx/sprigx/README.md b/tplx/sprigx/README.md index 2d2ee50..73145f0 100644 --- a/tplx/sprigx/README.md +++ b/tplx/sprigx/README.md @@ -6,7 +6,7 @@ Brent Saner -Last rendered 2026-02-24 17:42:04 -0500 +Last rendered 2026-06-22 18:51:29 -0400
    @@ -36,152 +36,200 @@ Table of Contents - [5.1.1. `dump`](#fn_dbg_dump) - [5.2. "Meta"/Template Helpers](#fn_meta) - [5.2.1. `metaIsNil`](#fn_meta_isnil) - - [5.3. Networking](#fn_net_all) - - [5.3.1. `net`](#fn_net) - - [5.3.1.1. `netCidrMask`](#fn_net_cidrmask) - - [5.3.1.2. `netExtractAddr`](#fn_net_cidra) - - [5.3.1.3. `netExtractHost`](#fn_net_hph) - - [5.3.1.4. `netExtractIpnet`](#fn_net_cidrn) - - [5.3.1.5. `netExtractPort`](#fn_net_hpp) - - [5.3.1.6. `netIfaces`](#fn_net_ifaces) - - [5.3.1.7. `netIp4Mask`](#fn_net_ip4mask) - - [5.3.1.8. `netJoinHostPort`](#fn_net_jhp) - - [5.3.1.9. `netParseIP`](#fn_net_parseip) - - [5.3.2. `net/netip`](#fn_netip) - - [5.3.2.1. `netipAddrPort`](#fn_netip_addrport) - - [5.3.2.2. `netipParseAddr`](#fn_netip_parseaddr) - - [5.3.2.3. `netipParseAddrPort`](#fn_netip_pap) - - [5.3.2.4. `netipParsePrefix`](#fn_netip_parsepfx) - - [5.3.2.5. `netipPrefix`](#fn_netip_pfx) - - [5.3.3. `go4.org/netipx`](#fn_netipx) - - [5.3.3.1. `netipxAddrIpNet`](#fn_netipx_addripnet) - - [5.3.3.2. `netipxCmpPfx`](#fn_netipx_cmppfx) - - [5.3.3.3. `netipxFromStdAddr`](#fn_netipx_fromstdaddr) - - [5.3.3.4. `netipxFromIp`](#fn_netipx_fromip) - - [5.3.3.5. `netipxFromIpNet`](#fn_netipx_fromipnet) - - [5.3.3.6. `netipxParseRange`](#fn_netipx_parserange) - - [5.3.3.7. `netipxPfxAddr`](#fn_netipx_pfxaddr) - - [5.3.3.8. `netipxPfxIpNet`](#fn_netipx_pfxipnet) - - [5.3.3.9. `netipxPfxLast`](#fn_netipx_pfxlast) - - [5.3.3.10. `netipxPfxRange`](#fn_netipx_pfxrange) - - [5.3.3.11. `netipxRange`](#fn_netipx_range) - - [5.3.4. `netx`](#fn_netx) - - [5.3.4.1. `netxAddrRfc`](#fn_netx_addrrfc) - - [5.3.4.2. `netxCidr4IpMask`](#fn_netx_cidr4ipmask) - - [5.3.4.3. `netxCidr4Mask`](#fn_netx_cidr4mask) - - [5.3.4.4. `netxCidr4Str`](#fn_netx_cidr4str) - - [5.3.4.5. `netxFamilyVer`](#fn_netx_familyver) - - [5.3.4.6. `netxGetAddrFam`](#fn_netx_getaddrfam) - - [5.3.4.7. `netxGetIpFam`](#fn_netx_getipfam) - - [5.3.4.8. `netxIpRfc`](#fn_netx_iprfc) - - [5.3.4.9. `netxIpRfcStr`](#fn_netx_iprfcstr) - - [5.3.4.10. `netxIpStripRfc`](#fn_netx_ipstriprfc) - - [5.3.4.11. `netxIp4MaskCidr`](#fn_netx_ip4maskcidr) - - [5.3.4.12. `netxIp4MaskMask`](#fn_netx_ip4maskmask) - - [5.4. Numbers/Math](#fn_num) - - [5.4.1. `numFloat32Str`](#fn_num_f32s) - - [5.4.2. `numFloat64`](#fn_num_f64) - - [5.4.3. `numFloat64Str`](#fn_num_f64s) - - [5.4.4. `numFloatStr`](#fn_num_fs) - - [5.5. Operating System](#fn_os) - - [5.5.1. `osFQDN`](#fn_os_fqdn) - - [5.5.2. `osGroupById`](#fn_os_grpid) - - [5.5.3. `osGroupByName`](#fn_os_grpnm) - - [5.5.4. `osHost`](#fn_os_hst) - - [5.5.5. `osHostname`](#fn_os_hstnm) - - [5.5.6. `osIdState`](#fn_os_idst) - - [5.5.7. `osUser`](#fn_os_usr) - - [5.5.8. `osUserById`](#fn_os_usrid) - - [5.5.9. `osUserByName`](#fn_os_usrnm) - - [5.6. Paths](#fn_path) - - [5.6.1. Generic](#fn_path_gnrc) - - [5.6.1.1. `pathJoin`](#fn_path_gnrc_pj) - - [5.6.1.2. `pathPipeJoin`](#fn_path_gnrc_ppj) - - [5.6.1.3. `pathSliceJoin`](#fn_path_gnrc_psj) - - [5.6.1.4. `pathSlicePipeJoin`](#fn_path_gnrc_pspj) - - [5.6.1.5. `pathSubJoin`](#fn_path_gnrc_psubj) - - [5.6.2. OS/Platform-Tailored](#fn_path_os) - - [5.6.2.1. `osPathJoin`](#fn_path_os_pj) - - [5.6.2.2. `osPathPipeJoin`](#fn_path_os_ppj) - - [5.6.2.3. `osPathSep`](#fn_path_ossep) - - [5.6.2.4. `osPathSliceJoin`](#fn_path_os_psj) - - [5.6.2.5. `osPathSlicePipeJoin`](#fn_path_os_pspj) - - [5.6.2.6. `osPathSubJoin`](#fn_path_os_psubj) - - [5.7. PSUtil](#fn_ps) - - [5.7.1. CPU/Processor](#fn_ps_cpu) - - [5.7.1.1. `psCpuCnts`](#fn_ps_cpu_cnts) - - [5.7.1.2. `psCpuInfo`](#fn_ps_cpu_info) - - [5.7.1.3. `psCpuPct`](#fn_ps_cpu_pct) - - [5.7.1.4. `psCpuTimes`](#fn_ps_cpu_tms) - - [5.7.2. Disk](#fn_ps_dsk) - - [5.7.2.1. `psDiskIoCnts`](#fn_ps_dsk_iocnts) - - [5.7.2.2. `psDiskLabel`](#fn_ps_dsk_lbl) - - [5.7.2.3. `psDiskParts`](#fn_ps_dsk_parts) - - [5.7.2.4. `psDiskSerial`](#fn_ps_dsk_srl) - - [5.7.2.5. `psDiskUsage`](#fn_ps_dsk_usg) - - [5.7.3. Host](#fn_ps_hst) - - [5.7.3.1. `psHostBoot`](#fn_ps_hst_boot) - - [5.7.3.2. `psHostId`](#fn_ps_hst_id) - - [5.7.3.3. `psHostInfo`](#fn_ps_hst_info) - - [5.7.3.4. `psHostKernArch`](#fn_ps_hst_krnarch) - - [5.7.3.5. `psHostKernVer`](#fn_ps_hst_krnver) - - [5.7.3.6. `psHostPlatInfo`](#fn_ps_hst_plat) - - [5.7.3.7. `psHostPlatUptime`](#fn_ps_hst_uptm) - - [5.7.3.8. `psHostUsers`](#fn_ps_hst_usrs) - - [5.7.3.9. `psHostPlatVirt`](#fn_ps_hst_virt) - - [5.7.4. Load](#fn_ps_ld) - - [5.7.4.1. `psLoadAvg`](#fn_ps_ld_avg) - - [5.7.4.2. `psLoadMisc`](#fn_ps_ld_misc) - - [5.7.5. Memory](#fn_ps_mem) - - [5.7.5.1. `psMemExVMem`](#fn_ps_mem_exvmem) - - [5.7.5.2. `psMemSwap`](#fn_ps_mem_swap) - - [5.7.5.3. `psMemSwapDevs`](#fn_ps_mem_swapdevs) - - [5.7.5.4. `psMemVMem`](#fn_ps_mem_vmem) - - [5.7.6. Network](#fn_ps_net) - - [5.7.6.1. `psNetConns`](#fn_ps_net_conns) - - [5.7.6.2. `psNetConnsMax`](#fn_ps_net_connsmax) - - [5.7.6.3. `psNetConnsPid`](#fn_ps_net_connspid) - - [5.7.6.4. `psNetConnsPidMax`](#fn_ps_net_connspidmax) - - [5.7.6.5. `psNetCTStats`](#fn_ps_net_ct) - - [5.7.6.6. `psNetCTStatList`](#fn_ps_net_ctlist) - - [5.7.6.7. `psNetFilterCnts`](#fn_ps_net_fltcnt) - - [5.7.6.8. `psNetIoCnts`](#fn_ps_net_iocnts) - - [5.7.6.9. `psNetIoCntsFile`](#fn_ps_net_iocntsfl) - - [5.7.6.10. `psNetIfaces`](#fn_ps_net_ifaces) - - [5.7.6.11. `psNetPids`](#fn_ps_net_pids) - - [5.7.6.12. `psNetProtoCnt`](#fn_ps_net_protocnts) - - [5.7.6.13. `psNetRev`](#fn_ps_net_rev) - - [5.7.7. Processes](#fn_ps_proc) - - [5.7.7.1. `psProcs`](#fn_ps_procs_procs) - - [5.7.7.2. `psProcNew`](#fn_ps_proc_new) - - [5.7.7.3. `psProcPids`](#fn_ps_proc_pids) - - [5.7.7.4. `psProcPidExists`](#fn_ps_proc_pidxst) - - [5.7.8. Sensors/Thermals](#fn_ps_sns) - - [5.7.8.1. `psSensorExTemp`](#fn_ps_sns_extemp) - - [5.7.8.2. `psSensorTemps`](#fn_ps_sns_temps) - - [5.7.9. Windows Services](#fn_ps_winsvc) - - [5.7.9.1. `psWinsvcList`](#fn_ps_winsvc_list) - - [5.7.9.2. `psWinsvcNew`](#fn_ps_winsvc_new) - - [5.8. Strings](#fn_str) - - [5.8.1. `extIndent`](#fn_str_extindent) - - [5.9. System/Platform/Architecture](#fn_sys) - - [5.9.1. `sysArch`](#fn_sys_arch) - - [5.9.2. `sysNumCpu`](#fn_sys_numcpu) - - [5.9.3. `sysOsName`](#fn_sys_os) - - [5.9.4. `sysRuntime`](#fn_sys_rntm) - - [5.10. Time/Dates/Timestamps](#fn_tm) - - [5.10.1. `tmDate`](#fn_tm_date) - - [5.10.2. `tmFloatMicro`](#fn_tm_fltmic) - - [5.10.3. `tmFloatMilli`](#fn_tm_fltmill) - - [5.10.4. `tmFloatNano`](#fn_tm_fltnano) - - [5.10.5. `tmFloat`](#fn_tm_flt) - - [5.10.6. `tmFmt`](#fn_tm_fmt) - - [5.10.7. `tmNow`](#fn_tm_now) - - [5.10.8. `tmParseDur8n`](#fn_tm_pdur8n) - - [5.10.9. `tmParseMonth`](#fn_tm_pmnth) - - [5.10.10. `tmParseMonthInt`](#fn_tm_pmnthi) - - [5.10.11. `tmParseMonthStr`](#fn_tm_pmnths) - - [5.10.12. `tmParseTime`](#fn_tm_ptm) + - [5.2.2. `net`](#fn_net) + - [5.2.2.1. `netCidrMask`](#fn_net_cidrmask) + - [5.2.2.2. `netExtractAddr`](#fn_net_cidra) + - [5.2.2.3. `netExtractHost`](#fn_net_hph) + - [5.2.2.4. `netExtractIpnet`](#fn_net_cidrn) + - [5.2.2.5. `netExtractPort`](#fn_net_hpp) + - [5.2.2.6. `netIfaces`](#fn_net_ifaces) + - [5.2.2.7. `netIp4Mask`](#fn_net_ip4mask) + - [5.2.2.8. `netJoinHostPort`](#fn_net_jhp) + - [5.2.2.9. `netParseIP`](#fn_net_parseip) + - [5.2.3. `net/netip`](#fn_netip) + - [5.2.3.1. `netipAddrPort`](#fn_netip_addrport) + - [5.2.3.2. `netipParseAddr`](#fn_netip_parseaddr) + - [5.2.3.3. `netipParseAddrPort`](#fn_netip_pap) + - [5.2.3.4. `netipParsePrefix`](#fn_netip_parsepfx) + - [5.2.3.5. `netipPrefix`](#fn_netip_pfx) + - [5.2.4. `go4.org/netipx`](#fn_netipx) + - [5.2.4.1. `netipxAddrIpNet`](#fn_netipx_addripnet) + - [5.2.4.2. `netipxCmpPfx`](#fn_netipx_cmppfx) + - [5.2.4.3. `netipxFromStdAddr`](#fn_netipx_fromstdaddr) + - [5.2.4.4. `netipxFromIp`](#fn_netipx_fromip) + - [5.2.4.5. `netipxFromIpNet`](#fn_netipx_fromipnet) + - [5.2.4.6. `netipxParseRange`](#fn_netipx_parserange) + - [5.2.4.7. `netipxPfxAddr`](#fn_netipx_pfxaddr) + - [5.2.4.8. `netipxPfxIpNet`](#fn_netipx_pfxipnet) + - [5.2.4.9. `netipxPfxLast`](#fn_netipx_pfxlast) + - [5.2.4.10. `netipxPfxRange`](#fn_netipx_pfxrange) + - [5.2.4.11. `netipxRange`](#fn_netipx_range) + - [5.2.5. `r00t2.io/goutils/netx`](#fn_netx) + - [5.2.5.1. `netxAddrRfc`](#fn_netx_addrrfc) + - [5.2.5.2. `netxAddrRfc`](#fn_netx_cidr4ipmask) + - [5.2.5.3. `netxCidr4Mask`](#fn_netx_cidr4mask) + - [5.2.5.4. `netxCidr4Str`](#fn_netx_cidr4str) + - [5.2.5.5. `netxFamilyVer`](#fn_netx_familyver) + - [5.2.5.6. `netxGetAddrFam`](#fn_netx_getaddrfam) + - [5.2.5.7. `netxGetIpFam`](#fn_netx_getipfam) + - [5.2.5.8. `netxIpRfc`](#fn_netx_iprfc) + - [5.2.5.9. `netxIpRfcStr`](#fn_netx_iprfcstr) + - [5.2.5.10. `netxIpStripRfc`](#fn_netx_ipstriprfc) + - [5.2.5.11. `netxIp4MaskCidr`](#fn_netx_ip4maskcidr) + - [5.2.5.12. `netxIp4MaskMask`](#fn_netx_ip4maskmask) + - [5.2.5.13. `netxIp4MaskStr`](#fn_netx_ip4maskstr) + - [5.2.5.14. `netxIpVerStr`](#fn_netx_ipverstr) + - [5.2.5.15. `netxIsBrktd6`](#fn_netx_isbrktd6) + - [5.2.5.16. `netxIsIp`](#fn_netx_isip) + - [5.2.5.17. `netxIsPfx`](#fn_netx_ispfx) + - [5.2.5.18. `netxMask4Cidr`](#fn_netx_mask4cidr) + - [5.2.5.19. `netxMask4StrCidr`](#fn_netx_mask4Strcidr) + - [5.2.5.20. `netxMask4StrIpMask`](#fn_netx_mask4stripmask) + - [5.2.5.21. `netxMask4StrMask`](#fn_netx_mask4strmask) + - [5.2.5.22. `netxVerFamily`](#fn_netx_ver2fam) + - [5.2.6. `r00t2.io/goutils/netx/dnsx`](#fn_dnsx) + - [5.2.6.1. `dnsxPtrAddr`](#fn_dnsx_ptraddr) + - [5.2.6.2. `dnsxAddrPtr`](#fn_dnsx_addrptr) + - [5.2.6.3. `dnsxStrWire`](#fn_dnsx_str2wire) + - [5.2.6.4. `dnsxWireStr`](#fn_dnsx_wire2str) + - [5.2.6.5. `dnsxPtrIp`](#fn_dnsx_ptrip) + - [5.2.6.6. `dnsxIpPtr`](#fn_dnsx_ipptr) + - [5.2.6.7. `dnsxIsFqdn`](#fn_dnsx_isfqdn) + - [5.2.6.8. `dnsxIsTxt`](#fn_dnsx_istxt) + - [5.2.6.9. `dnsxIsNsec3`](#fn_dnsx_isnsec3) + - [5.2.6.10. `dnsxIsSrv`](#fn_dnsx_issrv) + - [5.2.6.11. `dnsxIsWild`](#fn_dnsx_iswild) + - [5.2.6.12. `dnsxIsLbl`](#fn_dnsx_islbl) + - [5.2.6.13. `dnsxIsPtr`](#fn_dnsx_isptr) + - [5.3. Numbers/Math](#fn_num) + - [5.3.1. `numFloat32Str`](#fn_num_f32s) + - [5.3.2. `numFloat64`](#fn_num_f64) + - [5.3.3. `numFloat64Str`](#fn_num_f64s) + - [5.3.4. `numFloatStr`](#fn_num_fs) + - [5.4. Operating System](#fn_os) + - [5.4.1. `osFQDN`](#fn_os_fqdn) + - [5.4.2. `osGroupById`](#fn_os_grpid) + - [5.4.3. `osGroupByName`](#fn_os_grpnm) + - [5.4.4. `osHost`](#fn_os_hst) + - [5.4.5. `osHostname`](#fn_os_hstnm) + - [5.4.6. `osIdState`](#fn_os_idst) + - [5.4.7. `osUser`](#fn_os_usr) + - [5.4.8. `osUserById`](#fn_os_usrid) + - [5.4.9. `osUserByName`](#fn_os_usrnm) + - [5.5. Paths](#fn_path) + - [5.5.1. Generic](#fn_path_gnrc) + - [5.5.1.1. `pathJoin`](#fn_path_gnrc_pj) + - [5.5.1.2. `pathPipeJoin`](#fn_path_gnrc_ppj) + - [5.5.1.3. `pathSliceJoin`](#fn_path_gnrc_psj) + - [5.5.1.4. `pathSlicePipeJoin`](#fn_path_gnrc_pspj) + - [5.5.1.5. `pathSubJoin`](#fn_path_gnrc_psubj) + - [5.5.2. OS/Platform-Tailored](#fn_path_os) + - [5.5.2.1. `osPathJoin`](#fn_path_os_pj) + - [5.5.2.2. `osPathPipeJoin`](#fn_path_os_ppj) + - [5.5.2.3. `osPathSep`](#fn_path_ossep) + - [5.5.2.4. `osPathSliceJoin`](#fn_path_os_psj) + - [5.5.2.5. `osPathSlicePipeJoin`](#fn_path_os_pspj) + - [5.5.2.6. `osPathSubJoin`](#fn_path_os_psubj) + - [5.6. PSUtil](#fn_ps) + - [5.6.1. CPU/Processor](#fn_ps_cpu) + - [5.6.1.1. `psCpuCnts`](#fn_ps_cpu_cnts) + - [5.6.1.2. `psCpuInfo`](#fn_ps_cpu_info) + - [5.6.1.3. `psCpuPct`](#fn_ps_cpu_pct) + - [5.6.1.4. `psCpuTimes`](#fn_ps_cpu_tms) + - [5.6.2. Disk](#fn_ps_dsk) + - [5.6.2.1. `psDiskIoCnts`](#fn_ps_dsk_iocnts) + - [5.6.2.2. `psDiskLabel`](#fn_ps_dsk_lbl) + - [5.6.2.3. `psDiskParts`](#fn_ps_dsk_parts) + - [5.6.2.4. `psDiskSerial`](#fn_ps_dsk_srl) + - [5.6.2.5. `psDiskUsage`](#fn_ps_dsk_usg) + - [5.6.3. Host](#fn_ps_hst) + - [5.6.3.1. `psHostBoot`](#fn_ps_hst_boot) + - [5.6.3.2. `psHostId`](#fn_ps_hst_id) + - [5.6.3.3. `psHostInfo`](#fn_ps_hst_info) + - [5.6.3.4. `psHostKernArch`](#fn_ps_hst_krnarch) + - [5.6.3.5. `psHostKernVer`](#fn_ps_hst_krnver) + - [5.6.3.6. `psHostPlatInfo`](#fn_ps_hst_plat) + - [5.6.3.7. `psHostPlatUptime`](#fn_ps_hst_uptm) + - [5.6.3.8. `psHostUsers`](#fn_ps_hst_usrs) + - [5.6.3.9. `psHostPlatVirt`](#fn_ps_hst_virt) + - [5.6.4. Load](#fn_ps_ld) + - [5.6.4.1. `psLoadAvg`](#fn_ps_ld_avg) + - [5.6.4.2. `psLoadMisc`](#fn_ps_ld_misc) + - [5.6.5. Memory](#fn_ps_mem) + - [5.6.5.1. `psMemExVMem`](#fn_ps_mem_exvmem) + - [5.6.5.2. `psMemSwap`](#fn_ps_mem_swap) + - [5.6.5.3. `psMemSwapDevs`](#fn_ps_mem_swapdevs) + - [5.6.5.4. `psMemVMem`](#fn_ps_mem_vmem) + - [5.6.6. Network](#fn_ps_net) + - [5.6.6.1. `psNetConns`](#fn_ps_net_conns) + - [5.6.6.2. `psNetConnsMax`](#fn_ps_net_connsmax) + - [5.6.6.3. `psNetConnsPid`](#fn_ps_net_connspid) + - [5.6.6.4. `psNetConnsPidMax`](#fn_ps_net_connspidmax) + - [5.6.6.5. `psNetCTStats`](#fn_ps_net_ct) + - [5.6.6.6. `psNetCTStatList`](#fn_ps_net_ctlist) + - [5.6.6.7. `psNetFilterCnts`](#fn_ps_net_fltcnt) + - [5.6.6.8. `psNetIoCnts`](#fn_ps_net_iocnts) + - [5.6.6.9. `psNetIoCntsFile`](#fn_ps_net_iocntsfl) + - [5.6.6.10. `psNetIfaces`](#fn_ps_net_ifaces) + - [5.6.6.11. `psNetPids`](#fn_ps_net_pids) + - [5.6.6.12. `psNetProtoCnt`](#fn_ps_net_protocnts) + - [5.6.6.13. `psNetRev`](#fn_ps_net_rev) + - [5.6.7. Processes](#fn_ps_proc) + - [5.6.7.1. `psProcs`](#fn_ps_procs_procs) + - [5.6.7.2. `psProcNew`](#fn_ps_proc_new) + - [5.6.7.3. `psProcPids`](#fn_ps_proc_pids) + - [5.6.7.4. `psProcPidExists`](#fn_ps_proc_pidxst) + - [5.6.8. Sensors/Thermals](#fn_ps_sns) + - [5.6.8.1. `psSensorExTemp`](#fn_ps_sns_extemp) + - [5.6.8.2. `psSensorTemps`](#fn_ps_sns_temps) + - [5.6.9. Windows Services](#fn_ps_winsvc) + - [5.6.9.1. `psWinsvcList`](#fn_ps_winsvc_list) + - [5.6.9.2. `psWinsvcNew`](#fn_ps_winsvc_new) + - [5.7. Strings](#fn_str) + - [5.7.1. Standalone](#fn_str_stnd) + - [5.7.1.1. `extIndent`](#fn_str_stnd_extindent) + - [5.7.2. `r00t2.io/goutils/stringsx`](#fn_str_strsx) + - [5.7.2.1. `strsxIsAscii`](#fn_str_strsx_isascii) + - [5.7.2.2. `strsxIsAsciiBuf`](#fn_str_strsx_isasciibuf) + - [5.7.2.3. `strsxIsAsciiSpcl`](#fn_str_strsx_isasciispcl) + - [5.7.2.4. `strsxIsAsciiBufSpcl`](#fn_str_strsx_isasciibufspcl) + - [5.7.2.5. `strsxLenSpl`](#fn_str_strsx_lenspl) + - [5.7.2.6. `strsxLenSplStr`](#fn_str_strsx_lensplstr) + - [5.7.2.7. `strsxPad`](#fn_str_strsx_pad) + - [5.7.2.8. `strsxRedact`](#fn_str_strsx_rdct) + - [5.7.2.9. `strsxRev`](#fn_str_strsx_rev) + - [5.7.2.10. `strsxTrimLns`](#fn_str_strsx_trimlns) + - [5.7.2.11. `strsxTrimSpcLft`](#fn_str_strsx_trimspcl) + - [5.7.2.12. `strsxTrimSpcRt`](#fn_str_strsx_trimspcr) + - [5.8. System/Platform/Architecture](#fn_sys) + - [5.8.1. `sysArch`](#fn_sys_arch) + - [5.8.2. `sysNumCpu`](#fn_sys_numcpu) + - [5.8.3. `sysOsName`](#fn_sys_os) + - [5.8.4. `sysRuntime`](#fn_sys_rntm) + - [5.9. Time/Dates/Timestamps](#fn_tm) + - [5.9.1. `tmDate`](#fn_tm_date) + - [5.9.2. `tmFloatMicro`](#fn_tm_fltmic) + - [5.9.3. `tmFloatMilli`](#fn_tm_fltmill) + - [5.9.4. `tmFloatNano`](#fn_tm_fltnano) + - [5.9.5. `tmFloat`](#fn_tm_flt) + - [5.9.6. `tmFmt`](#fn_tm_fmt) + - [5.9.7. `tmNow`](#fn_tm_now) + - [5.9.8. `tmParseDur8n`](#fn_tm_pdur8n) + - [5.9.9. `tmParseMonth`](#fn_tm_pmnth) + - [5.9.10. `tmParseMonthInt`](#fn_tm_pmnthi) + - [5.9.11. `tmParseMonthStr`](#fn_tm_pmnths) + - [5.9.12. `tmParseTime`](#fn_tm_ptm) +- [6. TODO/Wishlist](#todo) + - [6.1. Function Collections](#todo_collctns) + - [6.2. Fallibility](#todo_fallible) + - [6.3. Function Scope Segregation](#todo_safe) + - [6.4. Extend OS functions](#todo_os) + - [6.4.1. Environment Variables](#todo_os_env) + - [6.5. System Functions](#todo_sys) + - [6.6. Encoding Functions](#todo_encode) + - [6.7. UUID Functions](#todo_uuid) + - [6.8. URL Functions](#todo_url) + - [6.9. Live Networking Functions](#todo_net)
    @@ -197,18 +245,13 @@ Table of Contents
    -SprigX is a suite of extensions to -the sprig library -(Go docs). +SprigX is a suite of extensions to the sprig library (Go docs).
    -They provide functions that offer more enriched use cases and -domain-specific data. +They provide functions that offer more enriched use cases and domain-specific data.
    @@ -225,23 +268,10 @@ domain-specific data. Tip
    -

    If you are reading this README on the Go Module Directory -documentation (https://pkg.go.dev/r00t2.io/goutils/tplx/sprigx) or the -directory landing page (https://git.r00t2.io/r00t2/go_goutils/src/branch/master/tplx/sprigx), -it may not render correctly. Anchor-links (links within this document to -other sections of this document) will likely also not work.

    +

    If you are reading this README on the Go Module Directory documentation (https://pkg.go.dev/r00t2.io/goutils/tplx/sprigx) or the directory landing page (https://git.r00t2.io/r00t2/go_goutils/src/branch/master/tplx/sprigx), it may not render correctly. Anchor-links (links within this document to other sections of this document) will likely also not work.

    -

    Be sure to view it at properly via the in-repo AsciiDoc rendering or by -downloading and viewing the HTML version in a browser locally -and/or rendering a PDF version.

    +

    Be sure to view it at properly via the in-repo AsciiDoc rendering or by downloading and viewing the HTML version in a browser locally and/or rendering a PDF version.

    @@ -261,11 +291,7 @@ and/or rendering a PDF version.

    -This documentation is written in -AsciiDoc (with -AsciiDoctor extensions). +This documentation is written in AsciiDoc (with AsciiDoctor extensions).
    @@ -295,12 +321,7 @@ cd go_goutils
    -HTML output is re-rendered and included in git on each commit automatically (via -github:gabyx/Githooks) but can be -re-rendered on-demand locally via: +HTML output is re-rendered and included in git on each commit automatically (via github:gabyx/Githooks) but can be re-rendered on-demand locally via:
    @@ -328,13 +349,7 @@ asciidoctor -a ROOTDIR="${orig_dir}/" -o README.html README.adoc
    -This documentation can be rendered to PDF via -asciidoctor-pdf. It is -not included in git automatically because binary files that change on -each commit is not a good idea for git, especially for a repo that gets -cloned as part of a library inclusion in a module/package dependency -system (like `gomod`). +This documentation can be rendered to PDF via asciidoctor-pdf. It is not included in git automatically because binary files that change on each commit is not a good idea for git, especially for a repo that gets cloned as part of a library inclusion in a module/package dependency system (like `gomod`).
    @@ -469,17 +484,13 @@ var txtTpl *template.Template = template.
    -Or, as a convenience, you can simply use the -[`sprigx.CombinedTxtFuncMap`](#lib_cmbtfmap) and/or -[`sprigx.CombinedHtmlFuncMap`](#lib_cmbhfmap) functions. +Or, as a convenience, you can simply use the [`sprigx.CombinedTxtFuncMap`](#lib_cmbtfmap) and/or [`sprigx.CombinedHtmlFuncMap`](#lib_cmbhfmap) functions.
    -If a `