Subject: Re: Some more misc. Lisp queries From: Erik Naggum <erik@naggum.net> Date: Sun, 26 Aug 2001 23:56:18 GMT Newsgroups: comp.lang.lisp Message-ID: <3207858975690383@naggum.net> * quasiabhi@yahoo.com (Q u a s i) > The reason I asked so many (perhaps stupid) questions is that people > here (where I live) call it a vintage language with no future. Yeah, _for them_. What they mean is that they are not part of Lisp's future. That is their choice, not Lisp's. > Also I was also surprised at the minimal quantity of internet resources > related to Lisp. Being one of the oldest language, maybe I expected a > little more. I can easily see how this is disappointing. However, there is at least one somewhat surprising reason for this: It is so easy to do things in Common Lisp that people have no personal need to advertise it and make a public nuisance of themselves. While Archimedes may have made the first serious connection between nudity and marketing scientific discovery, I think today's Common Lisp hacker goes "yeah!" and just smiles. In sharp contrast, today's young punks go "HOLY SHIT! IT WORKS! GUYS! GUYS! IT WORKS!" and rush off to get another cool domain name. That "yeah!" is also probably worth a thousand times more money than the other Cool Hack, which is why it is _not_ marketed -- the reward was right there to begin with, with no need to attract attention from the crowds just to feel good about your own work. Remember, Common Lisp people are about 10 years older than Java people. As for reimplementing things from scratch, I got so immensely frustrated with the available "libraries" of web-design crap that an incredibly incompetent moron had abused unintelligently for a week _not_ serving a high-profile ultra-high-security project I am now working on that I sat down and whipped up a new Lisp "scripting language", I added a handler to Apache and used the support for CLISP "binaries" (.fas files) under Linux to fire up an interpreter to deal with my pages, and instead of reams of junk code produced by cut and paste and sloppy editing, I could use real Lisp _macros_ in my source files, producing XML and Javascript and all sorts of junk efficienctly, well-tested and _fast_. Designing that new language took me about three hours, but I have saved at least 40 hours dealing with the putrid fecal matter that some people actually spend their days trying to shape into web pages. After working my butt off long into the night and missing a Saturday party, I had completed more _real_ work in a 16-hour stretch with a dimunitive Lisp tool like CLISP than a supposed _professional_ had managed to get done in a whole week. This pisses me off so much even hundreds of rounds of target practice does not calm down. What I have done, highly inexperienced at web design and not knowing one iota of Javascript on Friday morning, probably looks clunky and is generally bells-and-whistles-free apart from functionality we need, should have been a walk in the park for a professional web head. It should have taken him mere hours to cobble up something from his vast store of libraries and tools and have it ready for us the same day. If I can fumble my way through huge tomes, copy stuff I do not fully grasp, bumping into problems I had no idea would cause so many lines of logs in the poor server, and generally feeling like an incompetent fool myself, but I can still get it done in two days with Lisp as the underlying tool, writing most of this from scratch while scratching my head and swearing, god damn it, those imbecilic _frauds_ who claim to have "libraries" on their side should be hanged at dawn. People scream about CGI and how hard it is to prosess those things and they load 100K+ Perl libraries and write HTML with code that is even more verbose than HTML to begin with. I shall break the "rule" I laid down above and tell you what I did. Below is how I make those pesky CGI variables available to my code. It probably is not 100% correct, but it works a lot better than the incredibly stupid Perl solutions I have seen, and Perl is supposedly _good_ at this crap. Retch! Excuse me while I barf in Larry Wall's general direction. (I use string streams because I have no particular inclication to reinvent buffers. Those who hate loop and format probably also hate string streams, but it is not _my_ fault that their Lisp vendor did not make them fast enough for them back in 1980-whatever when their mind was set about what is Lisp and what is not.) (defun 3ml-cgi-decode () (let ((stream (if (string-equal "get" request-method) (make-string-input-stream query-string) *standard-input*)) (symbols ())) (with-open-stream (output (make-string-output-stream)) (loop for char = (read-char stream nil nil) do (case char (#\= (push (intern (string-upcase (get-output-stream-string output))) symbols)) ((nil #\&) (when symbols (setf (symbol-value (first symbols)) (get-output-stream-string output)))) (#\+ (write-char #\space output)) (#\% (let* ((nib1 (read-char stream nil nil)) (nib2 (read-char stream nil nil)) (code (+ (* 16 (digit-char-p nib1 16)) (digit-char-p nib2 16)))) (write-char (code-char code) output))) (t (write-char char output))) while char)) (setf *cgi-variables* symbols))) You get the symbols that were passed in in the *cgi-variables* list so you can check for them with find or member, but you can use the symbols without bothering to check, too, provided you have a restart around them to get rid of the annoying unbound-variable error. (Tracking this stuff down took me some time, as I have not needed to build interpreters that should do this before. It may not be correct. Use with caution.) (restart-case (handler-bind ((unbound-variable (lambda (ignore) (declare (ignore ignore)) (use-value "")))) ...) (use-value (&optional value) value)) In the end, my nifty little markup language has stuff like this in it: <table <border 0><width 375> <form <name registerform><action register.3ml><method post><onsubmit return validate()> {:discard ; This {} form does not yield a value to be printed in its place. (defun make-form (prompt type name &optional width) (format nil "<tr <td ~@[<width ~A>~] <p <class header> ~A:>>~ <td <input <type ~A><name ~A><value {~A}><size 35>>>>" width prompt type name name size))} {(make-form "Given name" "text" "givenname" 120)} {(make-form "Family name" "text" "familyname")} {(make-form "E-mail" "text" "email")} {(make-form "Phone" "text" "phone")} {(make-form "Organization" "text" "organization")} {(make-form "Username" "text" "username")} {(make-form "Password" "password" "password1")} {(make-form "Password (confirm)" "password" "password2")} <tr <td <input <type hidden><name invitation><value {invitation}>>> <td <input <type submit><name register><value Register>> <input <type reset>>>>>> I assume that this is immediately understandable apart from the use of {~A} and {invitation}. Those result in expansions to the CGI variables with the input field names. I also assume that any wreck who has had to deal with the expanded HTML from something like this will appreciate its relative brevity. Once I get more work done in this area, however, it should like this, but the code that produces HTML/XML is too simple to deal with it this late this weekend: {(defun make-form (prompt type name &optional width) <tr <td {(when width <width {width}>)} <p <class header> {prompt}:>> <td <input <type {type}><name {name}><value {'{name}}><size 35>>>>)} <make-form <prompt Organization><type text><name organization>> There, I have posted both loop code, intricate format constrol strings, a compact new syntax that saves a lot on typing (ewwww!), shown that I use javascript (EWWWW!), and I have not even kept the fact that I designed web pages a secret. No cats were harmed in the production of this code or these web pages, however. ///