From 48c0bf44ad8cdbaf60811f03e08d14caef1964be Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Fri, 3 May 2024 01:14:43 +0100 Subject: [PATCH] zone.lisp: Split a single `:txt' string into small enough pieces. The substrings of a `:txt' record can be at most 255 bytes long. If the argument is a single string that's too long then split it into pieces; prefer to split at semicolons, or spaces. If the argument is a list of strings, then respect their split. Theoretically, the split positions are semantically transparent, but it's possible that some programs are sensitive to the boundaries. --- zone.lisp | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/zone.lisp b/zone.lisp index 031a15d..5589361 100644 --- a/zone.lisp +++ b/zone.lisp @@ -26,7 +26,7 @@ (defpackage #:zone (:use #:common-lisp - #:mdw.base #:mdw.str #:collect #:safely + #:mdw.base #:mdw.str #:anaphora #:collect #:safely #:net #:services) (:import-from #:net #:round-down #:round-up)) @@ -868,9 +868,36 @@ (rec-name (zr-data zr)) 5) +(defun split-txt-data (data) + (collecting () + (let ((i 0) (n (length data))) + (loop + (let ((end (+ i 255))) + (when (<= n end) (return)) + (let ((split (acond ((position #\; data :from-end t + :start i :end end) + (+ it 1)) + ((position #\space data :from-end t + :start i :end end) + (+ it 1)) + (t end)))) + (loop + (when (or (>= split end) + (char/= (char data split) #\space)) + (return)) + (incf split)) + (collect (subseq data i split)) + (setf i split)))) + (collect (subseq data i))))) + (defzoneparse :txt (name data rec) ":txt (TEXT*)" - (rec :data (listify data))) + (rec :data (cond ((stringp data) (split-txt-data data)) + (t + (dolist (piece data) + (unless (<= (length piece) 255) + (error "`:txt' record piece `~A' too long" piece))) + data)))) (defmethod zone-record-rrdata ((type (eql :txt)) zr) (mapc #'rec-string (zr-data zr)) -- 2.11.0