From: Thomas M. Philip
Subject: Lisp and Tcl
Date: 
Message-ID: <Pine.SOL.4.21.0002152020290.29331-100000@apocalypse.OCF.Berkeley.EDU>
This may be related to the Java/Lisp thread...

What would be the easiest way to open a TCL interpretor
and have it communicate with a Lisp program?

I need communicate with the serial port and perform some 
type manipulation to ensure that data is transfered according
to the protocol.  I'm not familiar doing this with Lisp and
haven't found many resources.

Any help would be appreciated.

--Thomas

From: Christian Lynbech
Subject: Re: Lisp and Tcl
Date: 
Message-ID: <of66vpj706.fsf@chl.tbit.dk>
I too would like to hear about any investigations into the combination
of CommonLisp and TCL.

My problem is that we have an existing source base in (a slightly
extended) tcl, but the (lisp based) application that is to replace it
will take some time before catching up. One simple way of jumpstarting
the process would to somehow integrate lisp and tcl.

The Guile Scheme folks have been playing around with the same
ideas. There is some (somewhat old) code that simply links a tcl
interpreter into the scheme interpreter application and something in
that manner should be doable in CL as well.

There is also (at least one) translator which turns tcl code into
scheme, though I have no idea as to what condition it is in. The url
is:

        http://www.cs.earlham.edu/~bickiia/

There is in fact currently some discussion about integrating
translators into Guile, on the Guile malinglist.


---------------------------+--------------------------------------------------
Christian Lynbech          | Ericsson Telebit A/S                       
Fax:   +45 8628 8186       | Fabrikvej 11, DK-8260 Viby J
Phone: +45 8738 2228       | email: ···@tbit.dk --- URL: http://www.tbit.dk
---------------------------+--------------------------------------------------
Hit the philistines three times over the head with the Elisp reference manual.
                                        - ·······@hal.com (Michael A. Petonic)
From: Pierre R. Mai
Subject: Re: Lisp and Tcl
Date: 
Message-ID: <87ya8j77df.fsf@orion.dent.isdn.cs.tu-berlin.de>
Christian Lynbech <···@tbit.dk> writes:

> I too would like to hear about any investigations into the combination
> of CommonLisp and TCL.

Well, since the Tcl Interpreter as such can be easily embedded in C,
it can also be embedded in a CL implementation, using that
implementations FFI.  See below for a very rudimentary way of doing
this in CMUCL (the eval-in-tcl doesn't use a persistent interpreter.
You will likely want to do this for real purposes though).

Note though that a number of issues will remain to be solved with this 
approach:  What about interaction of I/O commands, event-loops,
multi-processing and blocking syscalls, etc.

Note also that this approach gives you easy access to Tcl from Lisp,
but not vice-versa.  To extend the Tcl interpreter in Lisp, more
(possigly ugly) work will have to be done, since this involves
Callbacks into Lisp code, which isn't trivial most of the time.

> My problem is that we have an existing source base in (a slightly
> extended) tcl, but the (lisp based) application that is to replace it
> will take some time before catching up. One simple way of jumpstarting
> the process would to somehow integrate lisp and tcl.

IMHO whether this approach is beneficial would depend very much on the 
existing application, the intended replacement, etc.:

- Would it be simpler to just interface with a running Tcl process via 
  a socket?  In effect Tcl_Eval gives you not much additional benefit
  compared to a Tcl process that's listening to a socket and
  evaluating every string/line/whatever that comes across this socket.

- Does your existing Tcl code have useful interfaces to call from the
  Lisp side?

- Note that both Tcl and CL are contenders for your Top-Level code,
  and that CL should win...

In general, the low-level interfacing should be no problem, but the
higher levels might prove hard to do right.

> The Guile Scheme folks have been playing around with the same
> ideas. There is some (somewhat old) code that simply links a tcl
> interpreter into the scheme interpreter application and something in
> that manner should be doable in CL as well.

Yes, see below.

> There is also (at least one) translator which turns tcl code into
> scheme, though I have no idea as to what condition it is in. The url
> is:
> 
>         http://www.cs.earlham.edu/~bickiia/
> 
> There is in fact currently some discussion about integrating
> translators into Guile, on the Guile malinglist.

I don't really believe in translators:  The output they create
normally is not very maintainable, so you are better of to rewrite
from scratch or use it untranslated, IMHO.

Regs, Pierre.

;;;; Trivial Tcl8.0 Interfacing demo for CMU CL
;;;; This is placed in the public-domain (to keep the lawyers happy)
;;;;
;;;; Evaluate (alien:load-foreign "/usr/lib/libtcl8.0.so") before
;;;; compiling or loading this file.

(in-package :CL-USER)

(alien:def-alien-type tcl-interp (* t))

(declaim (inline tcl-createinterp))
(alien:def-alien-routine "Tcl_CreateInterp" tcl-interp)

(declaim (inline tcl-eval))
(alien:def-alien-routine "Tcl_Eval" c-call:int
  (interp tcl-interp :in)
  (string c-call:c-string :in))

(declaim (inline tcl-getstringresult))
(alien:def-alien-routine "Tcl_GetStringResult" c-call:c-string
  (interp tcl-interp :in))

(declaim (inline tcl-deleteinterp))
(alien:def-alien-routine "Tcl_DeleteInterp" c-call:void
  (interp tcl-interp :in))

(defun eval-in-tcl (string)
  (let ((inter (tcl-createinterp)))
    (unwind-protect
	 (let* ((result-code (tcl-eval inter string))
		(result-string (tcl-getstringresult inter)))
	   (values result-code (copy-seq result-string)))
      (tcl-deleteinterp inter))))

-- 
Pierre Mai <····@acm.org>         PGP and GPG keys at your nearest Keyserver
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
From: Pierre R. Mai
Subject: Re: Lisp and Tcl
Date: 
Message-ID: <87k8jzthta.fsf@orion.dent.isdn.cs.tu-berlin.de>
····@acm.org (Pierre R. Mai) writes:

> Christian Lynbech <···@tbit.dk> writes:
> 
> > >>>>> "Pierre" == Pierre R Mai <····@acm.org> writes:
> > 
> > Pierre> ... since this involves Callbacks into Lisp code, which isn't
> > Pierre> trivial most of the time.
> > 
> > Would that be "non-trivial" as in "practically impossible"? Are there
> > any example code, for instance at cons.org?

[...]

> Well, I dug a bit into this, and below you'll find four files that
> demonstrate how to do this kind of thing with CMUCL on x86 (you'll
> need the (generational) conservative GC).  Compile tcl-callback.c (you 
> need the header files from the CMUCL source) with cc -c tcl-callback.c
> then load cl-tcl-load.cl (after possibly adjusting the paths therein).
> Finally compile and load cl-tcl-demo.cl and play with things like
> (cl-tcl-demo:tcl-demo 128).

[...]

> Note also that the code is a quick hack to try things out, and might
> contain evil bugs in large quantities.

And unfortunately this was right on target, since I hadn't understood
the signal-handler implementation of CMU CL correctly (the GC treats
the signal-handlers specially, so those don't need to be updated via
scavenge-hooks when the handlers are moved by the GC).

Since I posted the original code here, I'll also post the updated
working code here as well.  The current revision is also sanitized in
a number of areas.  Enjoy.

Regs, Pierre.

-------------- cl-tcl.cl ----------------

;;;; Trivial Tcl8.0 Interfacing demo for CMU CL
;;;; This is placed in the public-domain (to keep the lawyers happy)
;;;;
;;;; Evaluate (alien:load-foreign "/usr/lib/libtcl8.0.so") and
;;;; (alien:load-foreign "tcl-demo.o") before compiling or loading
;;;; this file.  You will also likely need a version of CMUCL where
;;;; the /usr/bin/lisp binary has been produced with the flags
;;;; -Xlinker --export-dynamic added to OS_LINK_FLAGS in Config.linux*
;;;; Note that the Debian binaries usually don't include these flags.

(cl:defpackage "CL-TCL"
    (:use "CL" "ALIEN" "C-CALL" "SYSTEM")
  (:export
   "+TCL-OK+" "+TCL-ERROR+" "+TCL-RETURN+" "+TCL-BREAK+" "+TCL-CONTINUE+"
   "TCL-INTERPRETER"
   "CREATE-TCL-INTERPRETER" "DESTROY-TCL-INTERPRETER"
   "REGISTER-TCL-COMMAND" "UNREGISTER-TCL-COMMAND"
   "WITH-TCL-INTERPRETER" "EVAL-TCL-EXPR"))

(in-package :CL-TCL)

;;;; User and Implementation-level constants

(defconstant +TCL-OK+ 0
  "TCL return code:  Command completed normally; the interpreter's
result contains the command's result.")

(defconstant +TCL-ERROR+ 1
  "TCL return code:  The command couldn't be completed successfully;
the interpreter's result describes what went wrong.")

(defconstant +TCL-RETURN+ 2
  "TCL return code:  The command requests that the current procedure
return; the interpreter's result contains the procedure's return value.")

(defconstant +TCL-BREAK+ 3
  "TCL return code:  The command requests that the innermost loop
be exited; the interpreter's result is meaningless.")

(defconstant +TCL-CONTINUE+ 4
  "TCL return code:  Go on to the next iteration of the current loop;
the interpreter's result is meaningless.")

;;;; FFI bindings to the Tcl Library and the C-side of the callback stuff

(declaim (inline tcl-createinterp))
(def-alien-routine "Tcl_CreateInterp" system-area-pointer)

(declaim (inline tcl-eval))
(def-alien-routine "Tcl_Eval" int
  (interp system-area-pointer :in)
  (string c-string :in))

(declaim (inline tcl-getstringresult))
(def-alien-routine "Tcl_GetStringResult" c-string
  (interp system-area-pointer :in))

(declaim (inline tcl-deleteinterp))
(def-alien-routine "Tcl_DeleteInterp" void
  (interp system-area-pointer :in))

(declaim (inline set-lisp-callback-handler))
(def-alien-routine "Set_Lisp_Callback_Handler" void
  (handler unsigned-long :in))

(declaim (inline register-tcl-lisp-command))
(def-alien-routine "Register_Tcl_Lisp_Command" void
  (interp system-area-pointer :in)
  (name c-string :in))

(declaim (inline unregister-tcl-lisp-command))
(def-alien-routine "Unregister_Tcl_Lisp_Command" void
  (interp system-area-pointer :in)
  (name c-string :in))

;;;; User-level stuff

(defstruct (tcl-interpreter (:print-function print-tcl-interpreter))
  (valid-p t)
  (sap (int-sap 0) :type system-area-pointer)
  (commands (make-hash-table :test #'equal) :read-only t))

(defun print-tcl-interpreter (inter stream depth)
  (declare (ignore depth))
  (print-unreadable-object (inter stream :type t :identity t)
    (format stream "~:[(INVALID)~;(·····@~8,'0X)~]"
	    (tcl-interpreter-valid-p inter)
	    (sap-int (tcl-interpreter-sap inter)))))

(defvar *tcl-interpreter-list* nil
  "List of valid TCL interpreters.")

(defun create-tcl-interpreter ()
  "Create a TCL interpreter object that can be passed to the other
functions of CL-TCL."
  (let ((result (make-tcl-interpreter :sap (tcl-createinterp))))
    (push result *tcl-interpreter-list*)
    result))

(defun destroy-tcl-interpreter (inter)
  "Destroy the TCL interpreter object `inter'."
  (assert (and (tcl-interpreter-valid-p inter)
	       (member inter *tcl-interpreter-list*)))
  (setf *tcl-interpreter-list*
	(delete (tcl-interpreter-sap inter) *tcl-interpreter-list*
		:key #'tcl-interpreter-sap :test #'sap=))
  (tcl-deleteinterp (tcl-interpreter-sap inter))
  (setf (tcl-interpreter-valid-p inter) nil
	(tcl-interpreter-sap inter) (int-sap 0))
  inter)

(defun register-tcl-command (inter name handler)
  "Registers the lisp function `handler' as the handler for the
command named by the string `name' in the TCL-Interpreter `inter'.
Any previously existing handlers will be superseded.  When the
corresponding command is invoked in the TCL interpreter, the handler
will be called with the TCL-Interpreter object, the command name and
all the arguments to the TCL command.  The handler must return two
values: The return code (one of +TCL-OK+, +TCL-ERROR+, +TCL-RETURN+,
+TCL-BREAK+ or +TCL-CONTINUE+) and the result or error indicator
string."
  (assert (tcl-interpreter-valid-p inter))
  (setf (gethash name (tcl-interpreter-commands inter)) handler)
  (register-tcl-lisp-command (tcl-interpreter-sap inter) name))

(defun unregister-tcl-command (inter name)
  "Unregisters the previously registered command named `name' in the
TCL-Interpreter `inter'.  Returns the old handler function."
  (assert (tcl-interpreter-valid-p inter))
  (let ((handler (gethash name (tcl-interpreter-commands inter) nil)))
    (assert handler)
    (remhash name (tcl-interpreter-commands inter))
    (unregister-tcl-lisp-command (tcl-interpreter-sap inter) name)
    handler))

(defmacro with-tcl-interpreter (inter (&rest commands) &body body)
  "Evaluate the body in an environment were `inter' is bound to a
Tcl interpreter instance and for each (name tcl-proc) in `commands'
a Tcl command for name is defined, which invokes tcl-proc."
  `(let ((,inter (create-tcl-interpreter)))
     (unwind-protect
	  (progn
	    ,@(loop for (name handler) in commands
		    collect
		    `(register-tcl-command ,inter ,name ,handler))
	    ,@body)
       (destroy-tcl-interpreter ,inter))))

(defun eval-tcl-expr (inter expr)
  "Evaluate the expression (string) `expr' in the Tcl-Interpreter
`inter' and return as multiple values the return code and result
string."
  (assert (tcl-interpreter-valid-p inter))
  (let* ((result-code (tcl-eval (tcl-interpreter-sap inter) expr))
	 (result-string (tcl-getstringresult (tcl-interpreter-sap inter))))
    (values result-code result-string)))

;;;; Lisp-side of the callback stuff.

(defun %lisp-callback-handler (inter-sap args)
  (handler-case
      (let ((inter (find inter-sap *tcl-interpreter-list*
			 :key #'tcl-interpreter-sap :test #'sap=)))
	(assert (and inter (tcl-interpreter-valid-p inter)))
	(let ((handler (gethash (car args)
				(tcl-interpreter-commands inter) nil)))
	  (assert handler)
	  (multiple-value-bind (code result)
	      (apply handler inter args)
	    (cons code result))))
    (error (c) (cons +TCL-ERROR+ (format nil "Lisp error: ~A" c)))))

(defun %update-lisp-callback-handler ()
  (set-lisp-callback-handler
   (kernel:get-lisp-obj-address #'%lisp-callback-handler)))

(defvar *lisp-callback-scavhook*
  (ext:make-scavenger-hook :value #'%lisp-callback-handler
			   :function #'%update-lisp-callback-handler))

(%update-lisp-callback-handler)

-------------- tcl-callback.c ----------------

/*
 * ;;;; Trivial Tcl8.0 Interfacing demo for CMU CL
 * ;;;; This is placed in the public-domain (to keep the lawyers happy)
 * ;;;;
 * ;;;; Evaluate (alien:load-foreign "/usr/lib/libtcl8.0.so") before
 * ;;;; compiling or loading this file.
 */

#include <stdlib.h>
#include <string.h>
#include <tcl.h>
#include "lisp.h"
#include "internals.h"
#include "alloc.h"
#include "arch.h"

lispobj lisp_callback_handler;

static lispobj alloc_str_list(char *list[])
{
  lispobj result, newcons;
  struct cons *ptr;
  
  if (*list == NULL)
    result = NIL;
  else {
    result = newcons = alloc_cons(alloc_string(*list++), NIL);
    
    while (*list != NULL) {
      ptr = (struct cons *)PTR(newcons);
      newcons = alloc_cons(alloc_string(*list++), NIL);
      ptr->cdr = newcons;
    }
  }
  
  return result;
}

int LispTclProc(ClientData data,Tcl_Interp *interp,int argc,char** argv)
{
  lispobj lisp_result;
  struct vector *vec;
  char* result;
  int returnvalue;

  lisp_result=funcall2(lisp_callback_handler,alloc_sap(interp),
		       alloc_str_list(argv));
  
  returnvalue=fixnum_value(CONS(lisp_result)->car);
  vec=(struct vector*)PTR(CONS(lisp_result)->cdr);
  
  result=ckalloc((vec->length)+1);
  strcpy(result,(char*)vec->data);
  
  interp->result=result;
  interp->freeProc=TCL_DYNAMIC;
  
  return returnvalue;
}

void Set_Lisp_Callback_Handler(lispobj handler)
{
  lisp_callback_handler=handler;
}

void Register_Tcl_Lisp_Command(Tcl_Interp* interp,char* name)
{
  Tcl_CreateCommand(interp,name,LispTclProc,NULL,NULL);
}

void Unregister_Tcl_Lisp_Command(Tcl_Interp* interp,char* name)
{
  Tcl_DeleteCommand(interp,name);
}

-------------- cl-tcl-load.cl ----------------

(alien:load-foreign "/usr/lib/libtcl8.0.so")
(alien:load-foreign (make-pathname :name "tcl-callback" :type "o" :version nil
				   :defaults *load-truename*))
(load (compile-file (make-pathname :name "cl-tcl" :type "cl" :version nil
				   :defaults *load-truename*)))

-------------- cl-tcl-demo.cl ----------------

(cl:defpackage "CL-TCL-DEMO"
    (:use "CL" "CL-TCL")
  (:export "TCL-DEMO"))

(in-package :CL-TCL-DEMO)

(defun tcl-incr (inter cmd first &optional second)
  (declare (ignore inter cmd))
  (values 0
	  (format nil "~D"
		  (+ (parse-integer first)
		     (if second (parse-integer second) 1)))))

(defun tcl-demo (n)
  (with-tcl-interpreter inter (("lincr" #'tcl-incr))
    (multiple-value-bind (code result)
	(eval-tcl-expr inter 
		       (format nil "set result \"(\"
for {set i 1} {$i <= ~D} {set i [lincr $i 2]} {append result $i \" \"}
append result \")\"
return $result" n))
      (case code
	((#.+TCL-OK+ #.+TCL-RETURN+) (read-from-string result))
	(t (values code result))))))


-- 
Pierre Mai <····@acm.org>         PGP and GPG keys at your nearest Keyserver
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
From: Hartmann Schaffer
Subject: Re: Lisp and Tcl
Date: 
Message-ID: <38ab10d1.0@flint.sentex.net>
In article <········································@apocalypse.ocf.berkeley.edu>,
	"Thomas M. Philip" <········@ocf.Berkeley.EDU> writes:
> This may be related to the Java/Lisp thread...
> 
> What would be the easiest way to open a TCL interpretor
> and have it communicate with a Lisp program?
> 
> I need communicate with the serial port and perform some 
> type manipulation to ensure that data is transfered according
> to the protocol.  I'm not familiar doing this with Lisp and
> haven't found many resources.
> 
> Any help would be appreciated.

have you looked at with-wish?  i don't know the url where you could find
it,  but i suspect cons.org would be a good starting point

-- 

Hartmann Schaffer

It is better to fill your days with life than your life with days
From: Thomas M. Philip
Subject: Re: Lisp and Tcl
Date: 
Message-ID: <Pine.SOL.4.21.0002171452160.9176-100000@conquest.OCF.Berkeley.EDU>
Thanks Hartmann for the info on with-wish.

For the others of you who were interested, with-wish allows lisp
to communicate with TCL/TK.  It seems to work pretty well, but I
had to make a few changes for it to work on my system.

The url is:

http://www.cis.upenn.edu/~kaye/tcl.html

--thomas
From: Hidayet Tunc Simsek
Subject: Re: [garnet] Was: Lisp and Tcl
Date: 
Message-ID: <38ADCCAD.84F99C62@EECS.Berkeley.Edu>
Fred Gilham wrote:
> 
> Tunc Simsek <······@paleale.EECS.Berkeley.EDU> writes:
> 
> > As a side note to Lisp-Tcl and CLIM  I recently downloaded GARNET,
> > installed it without any trouble on SunOS/Solaris and found it very
> > impressive.  Unfortunately it seems that it is not supported actively
> > any longer.
> 
> I am `half-heartedly' supporting it.  I would like to support it fully
> but I'm not sure if I can fold it in to my work on an on-going basis.
> 

great, I'd hate to see GARNET go unsupported.  

> Anyone who wants to send bug reports or bug fixes, please do so.
> 
> I've got a version that I've tested under CMUCL and Linux ACL 5.0 that
> people can ftp from
> 
>    ftp.csl.sri.com:/pub/users/gilham/garnet
> 
> I will keep putting my latest version in there as an `unofficial'
> release.
> 

I'll check it out.  I installed the version distributed on the Garnet
homepage.

> >
> > I'm also looking for a GUI for my lisp programs and think that GARNET
> > is the best choice (at least in my case).  The question I have is:
> >
> >       Are there any 2D/3D plotting packages for GARNET (ie. those
> >       that do not use CLIM.  Only CLX based).
> > I shopped around and found that there are packages for CLIM (I think
> > a popular one is calle scigraph).  Could those be ported to work with
> > GARNET?
> >
> 
> Don't know about the above.

hmm, I hope someone can help with this.

> 
> I see a fair number of people putting effort into building FFI-based
> GUIs for lisp.  Someone's already pointed out the inefficiency in
> this.  I would suggest that the lisp community pick up Garnet as at
> least the basis for a free GUI.

Well, I use CLLIB to do GNUPLOT from within my CMUCL and it seems to
work fine.
However, this is a static deal. 

> 
> For example, I am currently working on an `interactive stream' for
> Garnet.  The idea is to use a Garnet text window and wrap it up with
> CLOS and talk to it using the Gray Streams stuff.  I'm doing this in
> CMUCL.  I'm taking the "top-level" or "tl" program and having it use
> the Garnet-based interactive stream as its I/O stream.  Voila!
> Instant lisp listener.

I'm not familiar with Gray Streams.  But I understand your intention.
I agree that a GUI based interpreter would be useful:  e.g. point
and click inspection of variables


> 
> I'm doing this in CMUCL.

Me too.

> 
> I'm currently getting a prompt and getting it to take input but it
> still has a few bugs.  I'll make this available when it's done.
> 

o.k., great.

Tunc

> --
> Fred Gilham                                      ······@csl.sri.com
> I have over the years been viewed as a man of the left and a man of
> the right, and the truth is that I've never put much stake in such
> labels. But this I have learned: the left patrols its borders and
> checks membership credentials ever so much more scrupulously, even
> ruthlessly, than does the right.            -- Richard John Neuhaus
From: Hidayet Tunc Simsek
Subject: Re: [garnet] Was: Lisp and Tcl
Date: 
Message-ID: <38ADCFE2.6FC0B2FC@EECS.Berkeley.Edu>
One bug (or rather a feature) is that if I already have Netscape open on
my
SunOS/solaris and I do:

 * (load "garnet-loader")

Then the loader aborts when loading create-instances.sparcf
I think the problem is that xlib cannot allocate colors.

Thanks,
tunc


Fred Gilham wrote:

[snip]
> Anyone who wants to send bug reports or bug fixes, please do so.
> 
[snip]
> --
> Fred Gilham                                      ······@csl.sri.com
> I have over the years been viewed as a man of the left and a man of
> the right, and the truth is that I've never put much stake in such
> labels. But this I have learned: the left patrols its borders and
> checks membership credentials ever so much more scrupulously, even
> ruthlessly, than does the right.            -- Richard John Neuhaus
From: Tim Bradshaw
Subject: Re: [garnet] Was: Lisp and Tcl
Date: 
Message-ID: <ey3u2j6t8uu.fsf@cley.com>
* Tunc Simsek wrote:

> I shopped around and found that there are packages for CLIM (I think
> a popular one is calle scigraph).  Could those be ported to work with 
> GARNET?

My memories of garnet are vague, but I think porting between it and
CLIM (either way) would be significant work.  

--tim
From: Robert Monfera
Subject: Re: Lisp and Tcl
Date: 
Message-ID: <38AA3403.7DC4F127@fisec.com>
"Thomas M. Philip" wrote:

> I need communicate with the serial port and perform some
> type manipulation to ensure that data is transfered according
> to the protocol.  I'm not familiar doing this with Lisp and
> haven't found many resources.

Hasn't someone posted serial or parallel port code yesterday?
From: Steve Long
Subject: Re: Lisp and Tcl
Date: 
Message-ID: <38AA81E0.2945A@isomedia.com>
If someone posted a way to do this, I would sure like to see it again.
From: Paolo Amoroso
Subject: Re: Lisp and Tcl
Date: 
Message-ID: <MQGsOCRlDHB7EYuTiazdJ50jSe8W@4ax.com>
On Wed, 16 Feb 2000 10:54:30 +0000, Steve Long <·········@isomedia.com>
wrote:

> If someone posted a way to do this, I would sure like to see it again.

Look for the article with subject "Re: Communicating with serial/parallel
ports" by David McClain, Message-ID: <·············@corp.supernews.com>,
posted to comp.lang.lisp on Mon, 14 Feb 2000 11:33:32 -0700. The code looks
Windowsish and I don't know how portable it is.


Paolo
-- 
EncyCMUCLopedia * Extensive collection of CMU Common Lisp documentation
http://cvs2.cons.org:8000/cmucl/doc/EncyCMUCLopedia/