1 ;;; --------------------------------------------------------------------------
2 ;;; CLFSWM - FullScreen Window Manager
4 ;;; --------------------------------------------------------------------------
5 ;;; Documentation: General tools
6 ;;; --------------------------------------------------------------------------
8 ;;; (C) 2011 Philippe Brochard <hocwp@free.fr>
10 ;;; This program is free software; you can redistribute it and/or modify
11 ;;; it under the terms of the GNU General Public License as published by
12 ;;; the Free Software Foundation; either version 3 of the License, or
13 ;;; (at your option) any later version.
15 ;;; This program is distributed in the hope that it will be useful,
16 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;;; GNU General Public License for more details.
20 ;;; You should have received a copy of the GNU General Public License
21 ;;; along with this program; if not, write to the Free Software
22 ;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 ;;; --------------------------------------------------------------------------
27 (in-package :common-lisp-user
)
34 :defconfig
:*config-var-table
* :configvar-value
:configvar-group
:config-default-value
43 :create-symbol
:create-symbol-in-package
59 :with-all-internal-symbols
60 :export-all-functions
:export-all-variables
61 :export-all-functions-and-variables
97 :get-command-line-words
100 :string-to-list-multichar
105 :exchange-one-in-list
109 :append-formated-list
111 :parse-integer-in-list
113 :next-in-list
:prev-in-list
124 (setq *random-state
* (make-random-state t
))
129 (defmacro awhen
(test &body body
)
134 (defmacro aif
(test then
&optional else
)
135 `(let ((it ,test
)) (if it
,then
,else
)))
138 ;;; Configuration variables
139 (defstruct configvar value group doc
)
141 (defparameter *config-var-table
* (make-hash-table :test
#'equal
))
143 (defmacro defconfig
(name value group doc
)
145 (setf (gethash ',name
*config-var-table
*)
146 (make-configvar :value
,value
147 :group
(or ,group
'Miscellaneous
)))
148 (defparameter ,name
,value
,doc
)))
150 (defun config-default-value (var)
151 (let ((config (gethash var
*config-var-table
*)))
153 (configvar-value config
))))
155 (defun config-group->string
(group)
156 (format nil
"~:(~A group~)" (substitute #\Space
#\-
(string group
))))
159 ;;; Configuration variables
160 (defun config-all-groups ()
162 (maphash (lambda (key val
)
163 (declare (ignore key
))
164 (pushnew (configvar-group val
) all-groups
:test
#'equal
))
166 (sort all-groups
(lambda (x y
)
167 (string< (string x
) (string y
))))))
172 (defun find-in-hash (val hashtable
&optional
(test #'equal
))
173 "Return the key associated to val in the hashtable"
174 (maphash #'(lambda (k v
)
175 (when (and (consp v
) (funcall test
(first v
) val
))
176 (return-from find-in-hash
(values k v
))))
180 (defun view-hash-table (title hashtable
)
181 (maphash (lambda (k v
)
182 (format t
"[~A] ~A ~A~%" title k v
))
185 (defun copy-hash-table (hashtable)
186 (let ((rethash (make-hash-table :test
(hash-table-test hashtable
))))
187 (maphash (lambda (k v
)
188 (setf (gethash k rethash
) v
))
193 (defun nfuncall (function)
197 (defun pfuncall (function &rest args
)
199 (or (functionp function
)
200 (and (symbolp function
) (fboundp function
))))
201 (apply function args
)))
204 (defun symbol-search (search symbol
)
205 "Search the string 'search' in the symbol name of 'symbol'"
206 (search search
(symbol-name symbol
) :test
#'string-equal
))
208 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
209 (defun mkstr (&rest args
)
210 (with-output-to-string (s)
214 (defun create-symbol (&rest args
)
215 (values (intern (string-upcase (apply #'mkstr args
)))))
217 (defun create-symbol-in-package (package &rest args
)
218 (values (intern (string-upcase (apply #'mkstr args
)) package
))))
224 (defun call-hook (hook &optional args
)
225 "Call a hook (a function, a symbol or a list of functions)
226 Return the result of the last hook"
231 (cons (dolist (h hook
)
233 (function (setf result
(apply hook args
)))
234 (symbol (when (fboundp hook
)
235 (setf result
(apply hook args
))))))))
240 (defmacro add-new-hook
(hook &rest value
)
241 "Add a hook. Duplicate it if needed"
242 `(setf ,hook
(append (typecase ,hook
247 (defmacro add-hook
(hook &rest value
)
248 "Add a hook only if not duplicated"
250 `(dolist (,i
(list ,@value
))
251 (unless (member ,i
(typecase ,hook
254 (add-new-hook ,hook
,i
)))))
256 (defmacro remove-hook
(hook &rest value
)
258 `(dolist (,i
(list ,@value
) ,hook
)
259 (setf ,hook
(remove ,i
,hook
)))))
265 (defparameter *timer-list
* nil
)
267 (declaim (inline realtime-
>s s-
>realtime
))
269 (defun realtime->s
(rtime)
270 (float (/ rtime internal-time-units-per-second
)))
272 (defun s->realtime
(second)
273 (round (* second internal-time-units-per-second
)))
276 (defun clear-timers ()
277 (setf *timer-list
* nil
))
279 (defun add-timer (delay fun
&optional
(id (gensym)))
280 "Start the function fun at delay seconds."
282 (let ((time (+ (get-internal-real-time) (s->realtime delay
))))
283 (lambda (current-time)
284 (when (>= current-time time
)
290 (defun at (delay fun
&optional
(id (gensym)))
291 "Start the function fun at delay seconds."
292 (funcall #'add-timer delay fun id
))
294 (defmacro with-timer
((delay &optional
(id (gensym))) &body body
)
295 "Same thing as add-timer but with syntaxic sugar"
302 (defun process-timers ()
303 "Call each timers in *timer-list* if needed"
304 (let ((current-time (get-internal-real-time)))
305 (dolist (timer *timer-list
*)
306 (when (funcall (second timer
) current-time
)
307 (setf *timer-list
* (remove timer
*timer-list
* :test
#'equal
))))))
309 (defun erase-timer (id)
310 "Erase the timer identified by its id"
311 (setf *timer-list
* (remove id
*timer-list
* :test
(lambda (x y
)
312 (equal x
(first y
))))))
314 (defun timer-test-loop ()
317 (format t
"Plop-~A" count
)
320 (format t
"Toto-~A" count
)
321 (add-timer 3 #'toto
:toto
)))
322 (add-timer 3 #'toto
:toto
)
323 (add-timer 13 #'plop
)
325 (princ ".") (force-output)
335 (defvar *%dbg-name%
* "dbg")
336 (defvar *%dbg-count%
* 0)
339 (defmacro dbg
(&rest forms
)
341 ,@(mapcar #'(lambda (form)
343 (string `(setf *%dbg-name%
* ,form
))
344 (number `(setf *%dbg-count%
* ,form
))))
346 (format t
"~&DEBUG[~A - ~A] " (incf *%dbg-count%
*) *%dbg-name%
*)
347 ,@(mapcar #'(lambda (form)
349 ((or string number
) nil
)
350 (t `(format t
"~A=~S " ',form
,form
))))
356 (defmacro dbgnl
(&rest forms
)
358 ,@(mapcar #'(lambda (form)
360 (string `(setf *%dbg-name%
* ,form
))
361 (number `(setf *%dbg-count%
* ,form
))))
363 (format t
"~&DEBUG[~A - ~A] --------------------~%" (incf *%dbg-count%
*) *%dbg-name%
*)
364 ,@(mapcar #'(lambda (form)
366 ((or string number
) nil
)
367 (t `(format t
" - ~A=~S~%" ',form
,form
))))
373 (defun dbgc (obj &optional newline
)
380 (defun distance (x1 y1 x2 y2
)
381 (+ (abs (- x2 x1
)) (abs (- y2 y1
))))
385 (defmacro with-all-internal-symbols
((var package
) &body body
)
386 "Bind symbol to all internal symbols in package"
387 `(do-symbols (,var
,package
)
388 (multiple-value-bind (sym status
)
389 (find-symbol (symbol-name ,var
) ,package
)
390 (declare (ignore sym
))
391 (when (eql status
:internal
)
395 (defun export-all-functions (package &optional
(verbose nil
))
396 (with-all-internal-symbols (symbol package
)
397 (when (fboundp symbol
)
399 (format t
"Exporting ~S~%" symbol
))
400 (export symbol package
))))
403 (defun export-all-variables (package &optional
(verbose nil
))
404 (with-all-internal-symbols (symbol package
)
405 (when (boundp symbol
)
407 (format t
"Exporting ~S~%" symbol
))
408 (export symbol package
))))
410 (defun export-all-functions-and-variables (package &optional
(verbose nil
))
411 (with-all-internal-symbols (symbol package
)
412 (when (or (fboundp symbol
) (boundp symbol
))
414 (format t
"Exporting ~S~%" symbol
))
415 (export symbol package
))))
419 (defun ensure-function (object)
420 (if (functionp object
)
422 (symbol-function object
)))
427 (defun empty-string-p (string)
431 (defun find-common-string (string list
&optional orig
)
432 "Return the string in common in all string in list"
434 (let ((result (remove-if-not (lambda (x)
435 (zerop (or (search string x
:test
#'string-equal
) -
1)))
437 (if (= (length result
) (length list
))
438 (if (> (length (first list
)) (length string
))
439 (find-common-string (subseq (first list
) 0 (1+ (length string
))) list string
)
445 (defun cmd-in-path (&optional
(tmpfile "/tmp/clfswm-cmd.tmp"))
446 (labels ((delete-tmp ()
447 (when (probe-file tmpfile
)
448 (delete-file tmpfile
))))
450 (dolist (dir (split-string (getenv "PATH") #\
:))
451 (ushell (format nil
"ls ~A/* >> ~A" dir tmpfile
)))
453 (with-open-file (stream tmpfile
:direction
:input
)
454 (loop for line
= (read-line stream nil nil
)
456 collect
(subseq line
(1+ (or (position #\
/ line
:from-end t
) -
1)))))
461 (defmacro setf
/= (var val
)
462 "Set var to val only when var not equal to val"
463 (let ((gval (gensym)))
465 (when (/= ,var
,gval
)
466 (setf ,var
,gval
)))))
469 (defun number->char
(number)
470 (cond ((<= number
25) (code-char (+ (char-code #\a) number
)))
471 ((<= 26 number
35) (code-char (+ (char-code #\
0) (- number
26))))
472 ((<= 36 number
61) (code-char (+ (char-code #\A
) (- number
36))))
475 (defun number->string
(number)
476 (string (number->char number
)))
480 (defun simple-type-of (object)
481 (let ((type (type-of object
)))
487 (defun repeat-chars (n char
)
488 "Return a string containing N CHARs."
489 (make-string n
:initial-element char
))
493 (defun nth-insert (n elem list
)
494 "Insert elem in (nth n list)"
495 (nconc (subseq list
0 n
)
501 (defun split-string (string &optional
(separator #\Space
))
502 "Return a list from a string splited at each separators"
503 (loop for i
= 0 then
(1+ j
)
504 as j
= (position separator string
:start i
)
505 as sub
= (subseq string i j
)
506 unless
(string= sub
"") collect sub
509 (defun string-match (match list
)
510 "Return the string in list witch match the match string"
511 (let ((len (length match
)))
512 (remove-duplicates (remove-if-not (lambda (x)
513 (string-equal match
(subseq x
0 (min len
(length x
)))))
515 :test
#'string-equal
)))
518 (defun append-newline-space (string)
519 "Append spaces before Newline on each line"
520 (with-output-to-string (stream)
521 (loop for c across string do
522 (when (equal c
#\Newline
)
527 (defun expand-newline (list)
528 "Expand all newline in strings in list"
531 (setf acc
(append acc
(split-string l
#\Newline
))))
534 (defun ensure-list (object)
535 "Ensure an object is a list"
541 (defun ensure-printable (string &optional
(new #\?))
542 "Ensure a string is printable in ascii"
543 (or (substitute-if-not new
#'standard-char-p
(or string
"")) ""))
545 (defun limit-length (string &optional
(length 10))
546 (subseq string
0 (min (length string
) length
)))
549 (defun ensure-n-elems (list n
)
550 "Ensure that list has exactly n elements"
551 (let ((length (length list
)))
552 (cond ((= length n
) list
)
553 ((< length n
) (ensure-n-elems (append list
'(nil)) n
))
554 ((> length n
) (ensure-n-elems (butlast list
) n
)))))
556 (defun begin-with-2-spaces (string)
557 (and (> (length string
) 1)
558 (eql (char string
0) #\Space
)
559 (eql (char string
1) #\Space
)))
561 (defun string-equal-p (x y
)
562 (when (stringp y
) (string-equal x y
)))
567 (defun find-assoc-word (word line
&optional
(delim #\"))
569 (let* ((pos (search word line
))
570 (pos-1 (position delim line
:start
(or pos
0)))
571 (pos-2 (position delim line
:start
(1+ (or pos-1
0)))))
572 (when (and pos pos-1 pos-2
)
573 (subseq line
(1+ pos-1
) pos-2
))))
576 (defun print-space (n &optional
(stream *standard-output
*))
577 "Print n spaces on stream"
579 (princ #\Space stream
)))
582 (defun escape-string (string &optional
(escaper '(#\
/ #\
: #\
) #\
( #\Space
#\
; #\,)) (char #\_))
583 "Replace in string all characters found in the escaper list"
585 (escape-string (substitute char
(car escaper
) string
) (cdr escaper
) char
)
590 (defun first-position (word string
)
591 "Return true only if word is at position 0 in string"
592 (zerop (or (search word string
) -
1)))
595 (defun find-free-number (l) ; stolen from stumpwm - thanks
596 "Return a number that is not in the list l."
597 (let* ((nums (sort l
#'<))
598 (new-num (loop for n from
0 to
(or (car (last nums
)) 0)
604 ;; there was no space between the numbers, so use the last + 1
605 (if (car (last nums
))
606 (1+ (car (last nums
)))
613 ;;; Shell part (taken from ltk)
614 (defun do-execute (program args
&optional
(wt nil
) (io :stream
))
615 "execute program with args a list containing the arguments passed to
616 the program if wt is non-nil, the function will wait for the execution
617 of the program to return.
618 returns a two way stream connected to stdin/stdout of the program"
619 #-CLISP
(declare (ignore io
))
620 (let ((fullstring program
))
622 (setf fullstring
(concatenate 'string fullstring
" " a
)))
623 #+:cmu
(let ((proc (ext:run-program program args
:input
:stream
:output
:stream
:wait wt
)))
625 (error "Cannot create process."))
627 (ext:process-output proc
)
628 (ext:process-input proc
)))
629 #+:clisp
(ext:run-program program
:arguments args
:input io
:output io
:wait wt
)
630 #+:sbcl
(let ((proc (sb-ext:run-program program args
:input
:stream
:output
:stream
:wait wt
)))
632 (error "Cannot create process."))
634 (sb-ext:process-output proc
)
635 (sb-ext:process-input proc
)))
636 #+:lispworks
(system:open-pipe fullstring
:direction
:io
)
637 #+:allegro
(let ((proc (excl:run-shell-command
638 (apply #'vector program program args
)
639 :input
:stream
:output
:stream
:wait wt
)))
641 (error "Cannot create process."))
643 #+:ecl
(ext:run-program program args
:input
:stream
:output
:stream
645 #+:openmcl
(let ((proc (ccl:run-program program args
:input
649 (error "Cannot create process."))
651 (ccl:external-process-output-stream proc
)
652 (ccl:external-process-input-stream proc
)))))
654 (defun do-shell (program &optional args
(wait nil
) (io :stream
))
655 (do-execute "/bin/sh" `("-c" ,program
,@args
) wait io
))
663 "Return the value of the environment variable."
664 #+allegro
(sys::getenv
(string var
))
665 #+clisp
(ext:getenv
(string var
))
667 (cdr (assoc (string var
) ext
:*environment-list
* :test
#'equalp
669 #+gcl
(si:getenv
(string var
))
670 #+lispworks
(lw:environment-variable
(string var
))
671 #+lucid
(lcl:environment-variable
(string var
))
672 #+(or mcl ccl
) (ccl::getenv var
)
673 #+sbcl
(sb-posix:getenv
(string var
))
674 #+ecl
(si:getenv
(string var
))
675 #-
(or allegro clisp cmu gcl lispworks lucid mcl sbcl scl ecl ccl
)
676 (error 'not-implemented
:proc
(list 'getenv var
)))
679 (defun (setf getenv
) (val var
)
680 "Set an environment variable."
681 #+allegro
(setf (sys::getenv
(string var
)) (string val
))
682 #+clisp
(setf (ext:getenv
(string var
)) (string val
))
684 (let ((cell (assoc (string var
) ext
:*environment-list
* :test
#'equalp
687 (setf (cdr cell
) (string val
))
688 (push (cons (intern (string var
) "KEYWORD") (string val
))
689 ext
:*environment-list
*)))
690 #+gcl
(si:setenv
(string var
) (string val
))
691 #+lispworks
(setf (lw:environment-variable
(string var
)) (string val
))
692 #+lucid
(setf (lcl:environment-variable
(string var
)) (string val
))
693 #+sbcl
(sb-posix:putenv
(format nil
"~A=~A" (string var
) (string val
)))
694 #+ecl
(si:setenv
(string var
) (string val
))
695 #+ccl
(ccl::setenv
(string var
) (string val
))
696 #-
(or allegro clisp cmu gcl lispworks lucid sbcl scl ecl ccl
)
697 (error 'not-implemented
:proc
(list '(setf getenv
) var
)))
706 #+(or clisp cmu
) (ext:quit
)
710 #+lispworks
(lw:quit
)
711 #+(or allegro-cl allegro-cl-trial
) (excl:exit
)
717 (defun remove-plist (plist &rest keys
)
718 "Remove the keys from the plist.
719 Useful for re-using the &REST arg after removing some options."
721 ((null (setq rest
(nth-value 2 (get-properties plist keys
))))
722 (nreconc copy plist
))
723 (do () ((eq plist rest
))
724 (push (pop plist
) copy
)
725 (push (pop plist
) copy
))
726 (setq plist
(cddr plist
))))
731 (defun urun-prog (prog &rest opts
&key args
(wait t
) &allow-other-keys
)
732 "Common interface to shell. Does not return anything useful."
733 #+gcl
(declare (ignore wait
))
734 (setq opts
(remove-plist opts
:args
:wait
))
735 #+allegro
(apply #'excl
:run-shell-command
(apply #'vector prog prog args
)
737 #+(and clisp lisp
=cl
)
738 (apply #'ext
:run-program prog
:arguments args
:wait wait opts
)
739 #+(and clisp
(not lisp
=cl
))
741 (apply #'lisp
:run-program prog
:arguments args opts
)
742 (lisp:shell
(format nil
"~a~{ '~a'~} &" prog args
)))
743 #+cmu
(apply #'ext
:run-program prog args
:wait wait
:output
*standard-output
* opts
)
744 #+gcl
(apply #'si
:run-process prog args
)
745 #+liquid
(apply #'lcl
:run-program prog args
)
746 #+lispworks
(apply #'sys
::call-system-showing-output
747 (format nil
"~a~{ '~a'~}~@[ &~]" prog args
(not wait
))
749 #+lucid
(apply #'lcl
:run-program prog
:wait wait
:arguments args opts
)
750 #+sbcl
(apply #'sb-ext
:run-program prog args
:wait wait
:output
*standard-output
* opts
)
751 #+ecl
(apply #'ext
:run-program prog args opts
)
752 #+ccl
(apply #'ccl
:run-program prog args opts
:wait wait
)
753 #-
(or allegro clisp cmu gcl liquid lispworks lucid sbcl ecl ccl
)
754 (error 'not-implemented
:proc
(list 'run-prog prog opts
)))
757 ;;(defparameter *shell-cmd* "/usr/bin/env")
758 ;;(defparameter *shell-cmd-opt* nil)
760 #+UNIX
(defparameter *shell-cmd
* "/bin/sh")
761 #+UNIX
(defparameter *shell-cmd-opt
* '("-c"))
763 #+WIN32
(defparameter *shell-cmd
* "cmd.exe")
764 #+WIN32
(defparameter *shell-cmd-opt
* '("/C"))
767 (defun ushell (&rest strings
)
768 (urun-prog *shell-cmd
* :args
(append *shell-cmd-opt
* strings
)))
771 (urun-prog *shell-cmd
* :args
(append *shell-cmd-opt
* (list string
))))
774 (defun set-shell-dispatch (&optional
(shell-fun 'ushell
))
775 (labels ((|shell-reader|
(stream subchar arg
)
776 (declare (ignore subchar arg
))
777 (list shell-fun
(read stream t nil t
))))
778 (set-dispatch-macro-character #\
# #\
# #'|shell-reader|
)))
781 (defun ushell-loop (&optional
(shell-fun #'ushell
))
783 (format t
"UNI-SHELL> ")
784 (let* ((line (read-line)))
785 (cond ((zerop (or (search "quit" line
) -
1)) (return))
786 ((zerop (or (position #\
! line
) -
1))
787 (funcall shell-fun
(subseq line
1)))
788 (t (format t
"~{~A~^ ;~%~}~%"
790 (ignore-errors (eval (read-from-string line
))))))))))
797 (defun cldebug (&rest rest
)
804 (defun get-command-line-words ()
805 #+sbcl
(cdr sb-ext
:*posix-argv
*)
806 #+(or clozure ccl
) (cddddr (ccl::command-line-arguments
))
807 #+gcl
(cdr si
:*command-args
*)
808 #+ecl
(loop for i from
1 below
(si:argc
) collect
(si:argv i
))
809 #+cmu
(cdddr extensions
:*command-line-strings
*)
810 #+allegro
(cdr (sys:command-line-arguments
))
811 #+lispworks
(cdr sys
:*line-arguments-list
*)
813 #-
(or sbcl clozure gcl ecl cmu allegro lispworks clisp
)
814 (error "get-command-line-arguments not supported for your implementation"))
819 (defun string-to-list (str &key
(split-char #\space
))
820 (do* ((start 0 (1+ index
))
821 (index (position split-char str
:start start
)
822 (position split-char str
:start start
))
825 (unless (string= (subseq str start
) "")
826 (push (subseq str start
) accum
))
828 (when (/= start index
)
829 (push (subseq str start index
) accum
))))
832 (defun near-position (chars str
&key
(start 0))
833 (do* ((char chars
(cdr char
))
834 (pos (position (car char
) str
:start start
)
835 (position (car char
) str
:start start
))
847 ;;;(defun near-position2 (chars str &key (start 0))
848 ;;; (loop for i in chars
849 ;;; minimize (position i str :start start)))
851 ;;(format t "~S~%" (near-position '(#\! #\. #\Space #\;) "klmsqk ppii;dsdsqkl.jldfksj lkm" :start 0))
852 ;;(format t "~S~%" (near-position '(#\Space) "klmsqk ppii;dsdsqkl.jldfksj lkm" :start 0))
853 ;;(format t "~S~%" (near-position '(#\; #\l #\m) "klmsqk ppii;dsdsqkl.jldfksj lkm" :start 0))
854 ;;(format t "result=~S~%" (string-to-list-multichar "klmsqk ppii;dsdsqkl.jldfksj lkm" :preserve t))
855 ;;(format t "result=~S~%" (string-to-list-multichar "klmsqk ppii;dsd!sqkl.jldfksj lkm"
856 ;; :split-chars '(#\k #\! #\. #\; #\m)
860 (defun string-to-list-multichar (str &key
(split-chars '(#\space
)) (preserve nil
))
861 (do* ((start 0 (1+ index
))
862 (index (near-position split-chars str
:start start
)
863 (near-position split-chars str
:start start
))
866 (unless (string= (subseq str start
) "")
867 (push (subseq str start
) accum
))
869 (let ((retstr (subseq str start
(if preserve
(1+ index
) index
))))
870 (unless (string= retstr
"")
871 (push retstr accum
)))))
877 (defun list-to-string (lst)
878 (string-trim " () " (format nil
"~A" lst
)))
882 (defun clean-string (string)
883 "Remove Newline and upcase string"
885 (string-right-trim '(#\Newline
) string
)))
887 (defun one-in-list (lst)
888 (nth (random (length lst
)) lst
))
890 (defun exchange-one-in-list (lst1 lst2
)
891 (let ((elem1 (one-in-list lst1
))
892 (elem2 (one-in-list lst2
)))
893 (setf lst1
(append (remove elem1 lst1
) (list elem2
)))
894 (setf lst2
(append (remove elem2 lst2
) (list elem1
)))
898 (defun rotate-list (list)
900 (append (cdr list
) (list (car list
)))))
902 (defun anti-rotate-list (list)
904 (append (last list
) (butlast list
))))
906 (defun n-rotate-list (list n
)
908 (n-rotate-list (rotate-list list
) (1- n
))
912 (defun append-formated-list (base-str
914 &key
(test-not-fun #'(lambda (x) x nil
))
915 (print-fun #'(lambda (x) x
))
917 (let ((str base-str
) (first t
))
919 (cond ((funcall test-not-fun i
) nil
)
921 (concatenate 'string str
924 (funcall print-fun i
))))
926 (if (string= base-str str
)
927 (concatenate 'string str default-str
) str
)))
930 (defun shuffle-list (list &key
(time 1))
931 "Shuffle a list by swapping elements time times"
932 (let ((result (copy-list list
))
933 (ind1 0) (ind2 0) (swap 0))
935 (setf ind1
(random (length result
)))
936 (setf ind2
(random (length result
)))
938 (setf swap
(nth ind1 result
))
939 (setf (nth ind1 result
) (nth ind2 result
))
940 (setf (nth ind2 result
) swap
))
945 (defun convert-to-number (str)
946 (cond ((stringp str
) (parse-integer str
:junk-allowed t
))
947 ((numberp str
) str
)))
949 (defun parse-integer-in-list (lst)
950 "Convert all integer string in lst to integer"
951 (mapcar #'(lambda (x) (convert-to-number x
)) lst
))
955 (defun next-in-list (item lst
)
956 (do ((x lst
(cdr x
)))
958 (when (equal item
(car x
))
959 (return (if (cadr x
) (cadr x
) (car lst
))))))
961 (defun prev-in-list (item lst
)
962 (next-in-list item
(reverse lst
)))
965 (let ((jours '("Lundi" "Mardi" "Mercredi" "Jeudi" "Vendredi" "Samedi" "Dimanche"))
966 (mois '("Janvier" "Fevrier" "Mars" "Avril" "Mai" "Juin" "Juillet"
967 "Aout" "Septembre" "Octobre" "Novembre" "Decembre"))
968 (days '("Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" "Sunday"))
969 (months '("January" "February" "March" "April" "May" "June" "July"
970 "August" "September" "October" "November" "December")))
971 (defun date-string ()
972 (multiple-value-bind (second minute hour date month year day
)
974 (if (search "fr" (getenv "LANG") :test
#'string-equal
)
975 (format nil
" ~2,'0D:~2,'0D:~2,'0D ~A ~2,'0D ~A ~A "
977 (nth day jours
) date
(nth (1- month
) mois
) year
)
978 (format nil
" ~2,'0D:~2,'0D:~2,'0D ~A ~A ~2,'0D ~A "
980 (nth day days
) (nth (1- month
) months
) date year
)))))