+(defun string/= (s1 s2 &key (start1 0) end1 (start2 0) end2)
+ (let* ((s1 (string s1))
+ (s2 (string s2))
+ (n1 (length s1))
+ (n2 (length s2))
+ (end1 (or end1 n1))
+ (end2 (or end2 n2)))
+ (dotimes (i (max (- end1 start1) (- end2 start2)) nil)
+ (when (or (>= (+ start1 i) n1)
+ (>= (+ start2 i) n2))
+ (return-from string/= (+ start1 i)))
+ (unless (char= (char s1 (+ start1 i)) (char s2 (+ start2 i)))
+ (return-from string/= (+ start1 i))))))
+
+
+(defun compare-strings (s1 s2 start1 end1 start2 end2 char-eq char-lt if-eq if-a-sub-b if-b-sub-a)
+ ;; step through strings S1 and S2, using bounds START1 END1 START2 END2.
+ ;; using character comparison functions CHAR-EQ (equality) and CHAR-LT (less-than),
+ ;; find the first difference, if any, and return its index.
+ ;; the IF-* params say what to do if the strings are equal, or a strict prefix substring of the other:
+ ;; if T, it returns the first different index. if NIL, it returns NIL.
+ (let* ((s1 (string s1))
+ (s2 (string s2))
+ (end1 (or end1 (length s1)))
+ (end2 (or end2 (length s2)))
+ (len-1 (- end1 start1))
+ (len-2 (- end2 start2)))
+ (dotimes (i (max len-1 len-2) (if if-eq (+ start1 i) nil))
+ (when (= i len-1) ;; ran off the end of s1
+ (return-from compare-strings (if if-a-sub-b (+ start1 i) nil)))
+ (when (= i len-2) ;; ran off the end of s2
+ (return-from compare-strings (if if-b-sub-a (+ start1 i) nil)))
+ (let ((c1 (char s1 (+ start1 i)))
+ (c2 (char s2 (+ start2 i))))
+ (when (not (funcall char-eq c1 c2)) ;; found a difference
+ (return-from compare-strings
+ (if (not (funcall char-lt c1 c2))
+ (+ start1 i)
+ nil)))))))
+
+(defun string< (s1 s2 &key (start1 0) end1 (start2 0) end2)
+ (compare-strings s1 s2 start1 end1 start2 end2
+ #'char= #'char> nil t nil))
+
+(defun string> (s1 s2 &key (start1 0) end1 (start2 0) end2)
+ (compare-strings s1 s2 start1 end1 start2 end2
+ #'char= #'char< nil nil t))
+
+(defun string<= (s1 s2 &key (start1 0) end1 (start2 0) end2)
+ (compare-strings s1 s2 start1 end1 start2 end2
+ #'char= #'char> t t nil))
+
+(defun string>= (s1 s2 &key (start1 0) end1 (start2 0) end2)
+ (compare-strings s1 s2 start1 end1 start2 end2
+ #'char= #'char< t nil t))
+
+(defun string-lessp (s1 s2 &key (start1 0) end1 (start2 0) end2)
+ (compare-strings s1 s2 start1 end1 start2 end2
+ #'char-equal #'char-greaterp nil t nil))
+
+(defun string-greaterp (s1 s2 &key (start1 0) end1 (start2 0) end2)
+ (compare-strings s1 s2 start1 end1 start2 end2
+ #'char-equal #'char-lessp nil nil t))
+
+(defun string-not-greaterp (s1 s2 &key (start1 0) end1 (start2 0) end2)
+ (compare-strings s1 s2 start1 end1 start2 end2
+ #'char-equal #'char-greaterp t t nil))
+
+(defun string-not-lessp (s1 s2 &key (start1 0) end1 (start2 0) end2)
+ (compare-strings s1 s2 start1 end1 start2 end2
+ #'char-equal #'char-lessp t nil t))