Monday, January 26, 2009

UTF-8 strings in trivial-ldap field values

Everybody using LDAP and Common Lisp probably knows the trivial-ldap library. It's a nifty, simple and concise implementation of the LDAP protocol in pure Common Lisp - i.e. no foreign library is needed to access your directory using this package. Trivial-ldap documentation states that UTF-8 strings are not supported, although the non-ascii string attribute value is properly passed in trivial-ldap:entry slots. Here is how you can easily get UTF-8 string attribute in Allegro CL:
(defun ldap-utf-8 (user pass base filter attribute)
  (let ((ldap (trivial-ldap:new-ldap :user user
                                     :pass pass
                                     :base base)))
    (trivial-ldap:bind ldap)
    (unwind-protect
         (when (trivial-ldap:search ldap filter)
           (loop for res = (trivial-ldap:next-search-result ldap)
                 while res
                 do (return-from ldap-utf-8
                      (octets-to-string
                       (string-to-octets
                        (car (trivial-ldap:attr-value res attribute))
                        :external-format :8-bit)
                       :external-format :utf8))))
      (trivial-ldap:unbind ldap))))
The arguments are self explanatory.

Tuesday, January 20, 2009

Blindness - A Movie by Fernando Meirelles

Definitely one of the best movies I've seen in a couple of months. Based on a excellent book by Jose Saramago, I've read 2 years ago. Pretty original story about a city affected by an epidemic of blindness. Caused by some contagious virus spread by unknown means, which cripples everyone except one woman - a doctor's wife (excellent Julianne Moore in this role). While there were numerous pretty effective depictions of an epidemic (28 Days After and it's sequel 28 Weeks After come to mind), none was so touching and personal in depiction of radical change in human nature affected by loss of senses. Noteworthy performance by Gael García Bernal. Well worth the time and highly recommended.

Sunday, January 18, 2009

I/O in Allegro CL multiprocessing code

Recent posting by one Timur Sufiev on slime-devel mailing list about tracing not working in threaded sbcl made me check how it looks for Allegro CL. First I found out what swank does in Allegro backend when you set swank:*globally-redirect-io* in your ~/.swank.lisp. It occurs that it creates a set of bindings in excl:*cl-default-special-bindings* for common stream variables:
  • *terminal-io*
  • *query-io*
  • *debug-io*
  • *standard-input*
  • *standard-output*
  • *trace-output*
  • *error-output*
Each of them pointing to a synonym stream connected to current slime session streams. Unfortunately Allegro CL doesn't use this variable on every mp:make-process (or mp:process-run-function wrapper for that matter). Franz treats this variable as a set of sensible defaults which you can use in your own process creating code with the keyword argument :initial-bindings to mp:make-process or mp:process-run-function. OK - I read too much into the documentation :-/ It was all kindly explained to me by a Franz engineer in a swift follow-up to a "bug-report" I submited. Unfortunately there are situations where you don't want or simply can't modify code spawning a subprocess (notable example being hunchentoot or any other MP enabled web server). It would make you patch each and every new release of the software either by modifying the source code or replacing it's internal functions - both things a huge no-no. So - what to do if you really want to direct I/O from a subprocess to your slime session? The answer is pretty simple - use advice or fwrap facility in Allegro CL to instrument mp:process-run-function or mp:make-process invocation to add these defaults when you need it. Here is a relevant snippet:
(excl:def-fwrapper default-special-bindings (&rest args)
 (declare (special user::*provide-initial-bindings*))
 (when (and (boundp 'user::*provide-initial-bindings*)
            user::*provide-initial-bindings*)
   (let ((name-or-args (car args)))
     (when (not (listp name-or-args))
       (setq name-or-args (list :name name-or-args))) ;listify
     (unless (getf name-or-args :initial-bindings)    ;update arglist
       (setf (car args)
             (list* :initial-bindings
                    excl:*cl-default-special-bindings*
                    name-or-args)))))
 (call-next-fwrapper))

(excl:fwrap 'mp:process-run-function 'dsb 'default-special-bindings)

The way you enable this is not complicated as well. Just start the main thread with special variable user::*provide-initial-bindings* bound to non nil value. Like this:
CL-USER> (let ((user::*provide-initial-bindings* t))
         (hunchentoot:start-server))
Now every I/O you you do the above-mentioned streams should appear in your slime repl window. Function tracing of course will work as well.

Saturday, January 17, 2009

Intro

This entry starts my "on-line diary". Blog is so last century and I'm not quite sure what weblog is ;) But - honest to blog, I will try to maintain it fairly often to hopefully increase signal/noise ratio in the Internet and even entertain my gentle readers from time to time. I'm an IT enthusiast, so - as for stuff which I will enter here - it's going to be mostly net-related. Sometimes cultural, sometimes technical. Anyway - keep your eyes peeled for the blizzard of entries.