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.

///