0

According to the bindat spec docs, there are two specs to pack strings. They are str and strz. Both are for a fixed length string.

Now, suppose I want to pack ("some" "list" "of" "string), I should do this:

(bindat-pack
 '((elem0 strz 5)
   (elem1 strz 5)
   (elem2 strz 3)
   (elem3 strz 7))
 '((elem0 . "some")
   (elem1 . "list")
   (elem2 . "of")
   (elem3 . "string")))

But that is so inflexible for several reasons:

  1. I have to put name and length manually.
  2. strz need to know size of the string before hand instead of just calculate the length of given string.

There are vec and repeat in the bindat spec but both are the same, both need length of the list before hand.

So far, I've come up with this:

(require 'seq)
(require 'bindat)

(defun make-strz-spec (name value)
  (let ((value (cond ((stringp value) value)
                     ((symbolp value) (symbol-name value))
                     (t (error "%s is neither string nor a symbol" value))))
        (sym (make-symbol name)))
    `((,sym strz ,(+ 1 (string-bytes value)))
      (,sym . ,value))))

(defun make-strz-spec-list (string-list)
  (seq-map-indexed
   (lambda (str idx)
     (let ((name (concat "elem-" (number-to-string idx))))
       (make-strz-spec name str)))
   string-list))

(defun bindat-pack-list-of-string (string-list)
  (let ((spec-pair (make-strz-spec-list string-list)))
    (bindat-pack
     (mapcar (lambda (elem) (nth 0 elem)) spec-pair)
     (mapcar (lambda (elem) (nth 1 elem)) spec-pair))))

;; this
(bindat-pack-list-of-string '("some" "list" "of" "string"))

But, that introduces more functions globally with very specific purpose. I don't want to pollute programming environment just for this.

Since I am still new with emacs-lisp and lisp in general. I am sure there's a better way than mine.

So, back to my main question, how can I bind-pack list of null terminated string?

NickD
  • 27,023
  • 3
  • 23
  • 42
Mas Bagol
  • 103
  • 4

1 Answers1

1

A function or macro that returns what you need isn't necessarly hard, long, or specially heavy; neither needs little more than a few primitives. For example:

(defun pack-string-list (l)
  (setq l (reverse l))
  (let* (sym spec strc)
    (dotimes (i (length l))
      (setq sym (make-symbol (concat "elem"
                                     (number-to-string i))))
      (push (cons sym (list 'strz 
                            (+ 1 (string-bytes (nth i l))))) 
            spec)
      (push (cons sym (nth i l)) strc))
    (bindat-pack spec strc)))

I don't know bindat package beyond this scope, but something easy-to-follow like this function looks like a fair trade-off to me if your concerns, whose meaning I don't understand, are right. Also probably such function could be written more idiomatically or simplified.

Muihlinn
  • 2,576
  • 1
  • 14
  • 22