From: Mark Wooding Date: Sun, 5 May 2024 01:50:03 +0000 (+0100) Subject: zone.lisp: Add seconds-to-timespec conversion and use it when dumping SOA. X-Git-Url: https://git.distorted.org.uk/~mdw/zone/commitdiff_plain zone.lisp: Add seconds-to-timespec conversion and use it when dumping SOA. --- diff --git a/zone.lisp b/zone.lisp index 3456b45..0979120 100644 --- a/zone.lisp +++ b/zone.lisp @@ -68,15 +68,20 @@ (push r a) (setf val q))))) -(let ((unit-scale (make-hash-table))) +(let ((unit-scale (make-hash-table)) + (scales nil)) (dolist (item `(((:second :seconds :sec :secs :s) ,1) ((:minute :minutes :min :mins :m) ,60) ((:hour :hours :hr :hrs :h) ,(* 60 60)) ((:day :days :dy :dys :d) ,(* 24 60 60)) ((:week :weeks :wk :wks :w) ,(* 7 24 60 60)))) - (destructuring-bind (units scale) item - (dolist (unit units) (setf (gethash unit unit-scale) scale)))) + (destructuring-bind + ((&whole units singular plural &rest hunoz) scale) item + (declare (ignore hunoz)) + (dolist (unit units) (setf (gethash unit unit-scale) scale)) + (push (cons scale (cons singular plural)) scales))) + (setf scales (sort scales #'> :key #'car)) (export 'timespec-seconds) (defun timespec-seconds (ts) @@ -103,7 +108,26 @@ unit))))) (convert (+ acc (to-integer (* count scale))) tail))))))) - (convert 0 ts)))) + (convert 0 ts))) + + (export 'seconds-timespec) + (defun seconds-timespec (secs) + "Convert a count of seconds to a time specification." + (let ((sign (if (minusp secs) -1 +1)) (secs (abs secs))) + (collecting () + (loop (cond ((zerop secs) + (unless (collected) (collect-append '(0 :seconds))) + (return)) + ((< secs 60) + (collect (* secs sign)) + (collect (if (= secs 1) :second :seconds)) + (return)) + (t + (let ((match (find secs scales :test #'>= :key #'car))) + (multiple-value-bind (quot rem) (floor secs (car match)) + (collect (* quot sign)) + (collect (if (= quot 1) (cadr match) (cddr match))) + (setf secs rem)))))))))) (defun hash-table-keys (ht) "Return a list of the keys in hashtable HT." @@ -1676,20 +1700,20 @@ $TTL ~2@*~D~2%" copy))) (format *zone-output-stream* "~ ~A~30TIN SOA~40T~A ( -~55@A~60T ;administrator -~45T~10D~60T ;serial -~45T~10D~60T ;refresh -~45T~10D~60T ;retry -~45T~10D~60T ;expire -~45T~10D )~60T ;min-ttl~2%" +~55@A~58T; administrator +~45T~10D~58T; serial +~45T~10D~58T; refresh: ~{~D ~(~A~)~^ ~} +~45T~10D~58T; retry: ~{~D ~(~A~)~^ ~} +~45T~10D~58T; expire: ~{~D ~(~A~)~^ ~} +~45T~10D )~58T; min-ttl: ~{~D ~(~A~)~^ ~}~2%" (bind-output-hostname (zone-name zone)) (bind-hostname (soa-source soa)) admin (soa-serial soa) - (soa-refresh soa) - (soa-retry soa) - (soa-expire soa) - (soa-min-ttl soa)))) + (soa-refresh soa) (seconds-timespec (soa-refresh soa)) + (soa-retry soa) (seconds-timespec (soa-retry soa)) + (soa-expire soa) (seconds-timespec (soa-expire soa)) + (soa-min-ttl soa) (seconds-timespec (soa-min-ttl soa))))) (export 'bind-format-record) (defun bind-format-record (zr format &rest args)