Skip to content
utilities.lisp 1.85 KiB
Newer Older
#+xcvb (module (:depends-on ("macros")))

;;; Lists
(defun list-of-length-p (n x)
(defun mapcar/ (function env arguments)
  (mapcar (lambda (x) (funcall function env x)) arguments))

(defun sequence-function-map (function sequence &key key)
  (let ((map (make-hash-table :test 'equal)))
    (flet ((index (x)
             (let ((k (if key (funcall key x) x)))
               ;; more general would be to merge results when it appears multiple times
               ;; instead of dropping subsequent appearances. But this is enough for our purposes.
               (unless (nth-value 1 (gethash k map))
                 (setf (gethash k map) (funcall function x))))))
      (map () #'index sequence))
    map))

(defun sequence-position-map (sequence)
  (let ((index -1))
    (flet ((index (x) (declare (ignore x)) (incf index)))
      (sequence-function-map #'index sequence))))

(defun readable-string (x &key (package :cl) output)
  (with-output (output)
    (with-safe-io-syntax ()
      (let ((*package* (find-package package)))
        (write x :stream output :readably t :escape t :pretty nil)
        (terpri output)))))
;;; Filesystem
(defun find-proper-ancestor (dir properf)
  (loop :for x = (pathname-directory-pathname dir)
    :then (pathname-parent-directory-pathname x) :do
    (cond
      ((funcall properf x) (return x))
      ((member (pathname-directory x) '(() (:absolute)) :test 'equal)
       (return nil)))))

;;; Environment control
;;; This better be moved to some portability package...
(defun setenv (name value &optional (overwrite t))
  (or #+sbcl (sb-posix:setenv name value (if overwrite 1 0))
      #+clozure (ccl:setenv name value overwrite)
      #+clisp (unless (and (not overwrite) (ext:getenv name)) (system::setenv name value))
      (error "~S not supported in your implementation" 'setenv)))