From: Jim Prewett download@hpc.unm.edu
I realize that the above syntax still leaves something to be desired. It is, IMO, too general for what most users need. I think we could probably make a couple of convienance macros that would expand into the above.
I'm not sure yet if I like the idea of using "generators" here, or if each function should be given an argument of which machine it is.
IP ranges are easy enough to generate and loop over:
(require :split-sequence)
(defun addr4->int (ipaddr) (destructuring-bind (a1 a2 a3 a4) (mapcar #'parse-integer (split-sequence:split-sequence #. ipaddr)) (dpb a1 (byte 8 24) (dpb a2 (byte 8 16) (dpb a3 (byte 8 8) a4)))))
(defun int->addr4 (intaddr) (format nil "~D.~D.~D.~D" (ldb (byte 8 24) intaddr) (ldb (byte 8 16) intaddr) (ldb (byte 8 8) intaddr) (ldb (byte 8 0) intaddr)))
(defmacro do-ip-range ((var start-ip end-ip &optional return) &body body) (let ((start (gensym "start")) (end (gensym "end")) (a (gensym))) `(let ((,start (addr4->int ,start-ip)) (,end (addr4->int ,end-ip))) (loop for ,a from ,start to ,end do (let ((,var (int->addr4 ,a))) ,@body) finally (return ,return)))))
(do-ip-range (addr "128.104.206.15" "128.104.206.33" 'woohoo) (print addr))
Seems like this might be useful in several places (network discovery, say).
-- wm, trying to decide if DO-CIDR-RANGE is in order...