Ok this is embarrassing but what's Nim's equivalent of printf? In particular stringifying a bunch of bytes as a hex string? I see a format proc in strutils but it seems to only accept string varargs. I was trying to put together a crude guid generation function I have in Golang (see below) but I'm stumped.

func guid() string{
    f, _ := os.Open("/dev/urandom", os.O_RDONLY, 0)
    b := make([]byte, 16)
    f.Read(b)
    f.Close()
    uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
    return uuid
}

proc guid():string=
    let f = open("/dev/urandom")
    var b:array[16, byte]
    discard readBytes(f, b, 0, 16)
    close(f)
    format("%x-%x-%x-%x-%x", b[0..4], b[4..6], b[6..8], b[8..10], b[10..15])

I understand I can use sprintf directly from C but don't know what function signature to use!

Thanks for any help!

2017-11-13 05:18:53

Have a look at toHex() in strutils which for anything bigger than a byte, you can specify the number of Hex chars to produce, and for a byte will output two hex chars.

so maybe as the equivalent of one of your %x try (untested)

"$1$2$3$4" % [toHex(b[0]), toHex(b[1]), toHex(b[2]), toHex(b[3])]
and not sure what the byte order should be

2017-11-13 10:32:57
import strutils

proc hexDump*[T](v: T): string =
  var s: seq[uint8] = @[]
  s.setLen(v.sizeof)
  copymem(addr(s[0]), v.unsafeAddr, v.sizeof)
  result = ""
  for i in s: result.add(i.toHex)

var
  i: int64 = 123
  ui: uint64 = 123
  f: float = 123.45
  s = @[1, 2, 3, 4]
  t: tuple[a: int, b: string] = (1, "123")
  set: set[uint8] = {1'u8..3'u8, 5'u8..6'u8}
  a: array[5, uint8] = [1'u8, 2, 3, 4, 5]

echo i.hexDump
echo ui.hexDump
echo f.hexDump
echo s.hexDump
echo t.hexDump
echo set.hexDump
echo a.hexDump

Without copying:

import strutils

proc hexDump*[T](v: T): string =
  template read_u8(p: ByteAddress): untyped =
    (cast[ptr uint8](p)[])
  
  var p = cast[ByteAddress](v.unsafeAddr)
  let e = p + v.sizeof
  result = ""
  while p < e:
    result.add(read_u8(p).toHex)
    p.inc

var
  i: int64 = 123
  ui: uint64 = 123
  f: float = 123.45
  s = @[1, 2, 3, 4]
  t: tuple[a: int, b: string] = (1, "123")
  set: set[uint8] = {1'u8..3'u8, 5'u8..6'u8}
  a: array[5, uint8] = [1'u8, 2, 3, 4, 5]

echo i.hexDump
echo ui.hexDump
echo f.hexDump
echo s.hexDump
echo t.hexDump
echo set.hexDump
echo a.hexDump

2017-11-14 12:19:27

Thanks @jlp765 and @dataman. I decided to go with the following for now.

import strutils

proc guid():string=
    result = ""
    const n = 8
    let f = open("/dev/urandom")
    var a:array[n, byte]
    discard readBytes(f, a, 0, n)
    close(f)
    for b in a: result.add(toHex(b))

But I must admit, I'm rather surprised a C style sprintf or Lisp style format is missing (at least I couldn't find it so far) in Nim's stdlib. I'm just a beginner in Nim otherwise I'd write one myself. Perhaps hopefully soon.

2017-11-15 04:35:31
There's an open PR for this: https://github.com/nim-lang/Nim/pull/6517
2017-11-15 11:11:12