+ (aset new i
+ (cond ((or (and start (< i start))
+ (and end (> i end)))
+ (char string i))
+ ((or (= i (or start 0))
+ (not just-saw-alphanum-p))
+ (char-upcase (char string i)))
+ (t
+ (char-downcase (char string i)))))
+ (setq just-saw-alphanum-p (alphanumericp (char string i))))))
+
+;; TODO: NSTRING-{UPCASE,DOWNCASE,CAPITALIZE}
+;; - Q: can i just extract the above functions without the MAKE-STRING call, and then have the STRING-* variants do MAKE-STRING + NSTRING-*?
+;; - NOTE: sacla's tests depend on COPY-SEQ, which doesn't exist yet.
+
+(defun string-equal (s1 s2 &key start1 end1 start2 end2)
+ (let* ((s1 (string s1))
+ (s2 (string s2))
+ (n1 (length s1))
+ (n2 (length s2))
+ (start1 (or start1 0))
+ (end1 (or end1 n1))
+ (start2 (or start2 0))
+ (end2 (or end2 n2)))
+ (when (= (- end2 start2) (- end1 start1))
+ (dotimes (i (- end2 start2) t)
+ (unless (char-equal (char s1 (+ start1 i)) (char s2 (+ start2 i)))
+ (return-from string-equal nil))))))
+
+;; just like string/= but with char-equal instead of char=
+(defun string-not-equal (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-not-equal (+ start1 i)))
+ (unless (char-equal (char s1 (+ start1 i)) (char s2 (+ start2 i)))
+ (return-from string-not-equal (+ start1 i))))))
+
+(defun string-trim (character-bag string)
+ (string-left-trim character-bag (string-right-trim character-bag string)))
+
+(defun string-left-trim (character-bag string)
+ (let* ((string (string string))
+ (n (length string))
+ (start (or (position-if-not (lambda (c) (find c character-bag)) string) n)))
+ (subseq string start)))
+
+(defun string-right-trim (character-bag string)
+ (let* ((string (string string))
+ (n (length string)))
+ (dotimes (i n "")
+ (when (not (find (char string (- n i 1)) character-bag))
+ (return-from string-right-trim (subseq string 0 (- n i)))))))