Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

AutoLISP - Write a LIST to a File?

10 views
Skip to first unread message

Eric A. Stiles

unread,
Jul 13, 1997, 3:00:00 AM7/13/97
to

I'm writing a program in AutoLISP and I'm stumped. I would like to be
able to save a LIST of different info including an assocation list to a
file. I started to do this when I realized that the (write-line)
function only writes text to a file. AutoLISP was created for
manipulating list, it seems that there should be a way to do this.

Any Ideas, Eric

Stephen c. Good

unread,
Jul 14, 1997, 3:00:00 AM7/14/97
to

In article <33C977...@gmgw.com>, est...@gmgw.com says...

I would like to be able to save a LIST of different info including an
assocation list to a file.
One w3ay is to process each element into text by its TYPE, and the
STRCAT them into a line of TEXT.


Chris L. Amos

unread,
Jul 14, 1997, 3:00:00 AM7/14/97
to

Eric A. Stiles wrote:
>
> I'm writing a program in AutoLISP and I'm stumped. I would like to be

> able to save a LIST of different info including an assocation list to a
> file. I started to do this when I realized that the (write-line)
> function only writes text to a file. AutoLISP was created for
> manipulating list, it seems that there should be a way to do this.
>
> Any Ideas, Eric


Try:

(print <lst> <file descriptor>)

When you read it back from the file use:

(setq inLine (read-line <file descpritor>))
(setq inline (read inLine)) ;this gets rid of the double quotes


--
Chris L. Amos
--------------------------------------------------------------
CADD Support Services, Inc. | e-mail responses:
"making AutoCAD meet your needs" | remove the leading
Calgary, AB, CANADA | "**"
--------------------------------------------------------------

Owen Wengerd

unread,
Jul 14, 1997, 3:00:00 AM7/14/97
to

Eric:

Use (print) to write a list to a file. Note the optional third argument
to the (prinx) functions.

If you're just saving a single list, which you then intend to read back
in later, then do something like the following to write it:

(setq mylist '(1 2 3 4))
(setq fh (open "save.lsp"))
(print "(setq mylist " fh))
(print mylist fh)
(print ")" fh)
(close fh)

Then restore 'mylist' with (load "save"). :)
--
Owen Wengerd [ManuSoft]
** AutoCAD Wizard At Large **
http://www.manusoft.com
ow...@manusoft.com
Compuserve: 71324,3252


Eric A. Stiles <est...@gmgw.com> wrote in article
<33C977...@gmgw.com>...

Darren J. Young

unread,
Jul 14, 1997, 3:00:00 AM7/14/97
to

In article <33C977...@gmgw.com>, est...@gmgw.com says...
> I'm writing a program in AutoLISP and I'm stumped. I would like to be
> able to save a LIST of different info including an assocation list to a
> file. I started to do this when I realized that the (write-line)
> function only writes text to a file. AutoLISP was created for
> manipulating list, it seems that there should be a way to do this.

(TYPE (READ "("bla1" "bla2" "bla3")")) = LIST

--
Y-------------------------------------------------------------------+
| Darren J. Young | Minnesota CADWorks, Inc. |
| dyo...@mcwi.com | P.O. Box 7293 |
| mc...@compuserve.com | St. Cloud, Minnesota 56302-7293 |
| http://www.mcwi.com | Phone: 1-320-654-9053 |
| CAD/CAM/CNC - Drafting Design Customization Training Programming |
0,0-----------------------------------------------------------------X
Email addresses not to be sold or used for unsolicited advertisements

Herbert Koenig

unread,
Jul 15, 1997, 3:00:00 AM7/15/97
to

In 33C977...@gmgw.com
est...@gmgw.com (Eric A. Stiles) wrote to all:

> I'm writing a program in AutoLISP and I'm stumped. I would like to
> be able to save a LIST of different info including an assocation list
> to a file. I started to do this when I realized that the
> (write-line) function only writes text to a file. AutoLISP was
> created for manipulating list, it seems that there should be a way to
> do this.
>

> Any Ideas, Eric

Hello Eric,

the fastest way to write LISP-lists to a file is by
"(print variable file)"

You have to print "(setq variable" to the File first, then print the
Variable, then "print )" to The same file.

To retrieve this information, You just need to load that file.


Big D R A W B A C K :

LISP make its own decision about decimal places, with six places
before the decimal point there will be none behind.

MAil me, if you need suggestions, how to deal with that problem, here
comes some Code.

(defun c:wlsts ( / datei dnam)
(setq filename (getfiled "Open File" "" "prv" 3))

(if filename
(progn
(setq file (open filename "w"))
(if file
(progn
(write-line "(setq h400pktlist '" file)
(print h400pktlist file)
(write-line ")" file)

(write-line "(setq h400linlist '" file)
(print h400linlist file)
(write-line ")" file)

(close file)
) ;progn
(progn
(alert "Error Opening File")
) ;progn
) ; if file
) ;progn
) ; if filename
(princ)
)

regards

Herbert

Vladimir Nesterovsky

unread,
Jul 16, 1997, 3:00:00 AM7/16/97
to

The PRINT idea *is* the answer, generally speaking, but we have
some details here to look after.

First of all, it's better to use PRIN1 to _preserve_ quotes
in case your list contains strings. But then we have two
problems: numbers presicion and strings with inner quotes.
The latter is probably very rare, but because of AutoLISP's
bug (at least I consider it such), when (prin1 "a\"b")
yeilds "a"b" instead of "a\"b", the quotes go out of sync and the
whole thing blows up (the READ function fails).

As for number precision -- I don't know any way to control
the precision used by PRIN1 in AutoLISP. :( So if you have
some big number, say coordinates of point, that you want to store
in this file, you'll get 123456.7 on output (or something like that).
So what do you do if you MUST have 2 or 3 digits _after_ decimal point?
PRIN1 falls short in such case. RTOS might have helped you, but
it takes only one number as value argument, and not a arbitrarily
structured list. So actually we come at the conclusion that special
function must be written to handle all this issues.

It had been done already. In fact this article can be found on
DEJANEWS.COM after some searching, that contains EXACTLY this function
(I admit, it's mine -- but I'm really doing this for some little
__"self-aggrandizing"__ after all) ;)

That's also a (good) example of recursion.

You can search DEJANEWS for FPRINV and after you've find the article go
to
THREAD VIEW to see complete discussion we had back then.

=============== start quoting article ====================
Article 1 of 1

Subject: Re: Question about AutoLISP programming...
From: Vladimir Nesterovsky <vne...@netvision.net.il>
Date: 1996/01/16
Message-Id: <NEWTNews.821784...@dialup.netvision.net.il>
Newsgroups: comp.cad.autocad,alt.cad.autocad
[More Headers]

In Article<60MHc...@hkoenig.forth-ev.de>,
<hko...@hkoenig.forth-ev.de> write:

> Later I retrieve the data by (load "filename").

It's very interesting question about storing
list values in file, and nice trick to write
it out for later LOADing as LISP file -
although this answer was at very end of your
posting, Herbert (you better start with a start
to make it easier for reader to catch the right answer).

So it's very easy -- right? You just
(setq fd (open "myfile.tmp" "w"))
(princ "(setq MY_VAR (qoute" fd)
(prin1 MY_VAR fd)
(princ "))" fd)
(setq fd (close fd))

and later on you retrieve this info with
(load "myfile.tmp")

So that's all?? So simple?
Yes - and No.

We have two problems here:
1. Precision of real values as Herbert pointed out, -
but I want just to save MY_VAR to file, without
having to restructure it and entire application.
2. !!! If a list contains string with a "\"" inside,
it's hopeless. Neither PRINC, no PRIN1 is no good -
try the above trick for
(setq my_var '("inside_\"quotes\"_here"))
and you'll end up with my_var equal to
'("inside_" QUOTES "_here")
- list of string, SYM and then string again.

(BTW -- to Dennis Shinn -- the REAL question was
to store run-time data, not compile-time (!??) )


So here's the function that solves the problem:
;;
;; PRINT OUT VARIABLE VALUE TO FILE
;; by Vladimir Nesterovsky, 1995.
;; email vne...@netvision.net.il
;;
;; uses FD -- output file descriptor.
;; reals output is controlled by DIMZIN and LUPREC
;; system variables.
(defun fprinv( V / typ i) ;; V is just some variable, may be a list
(cond
((null V)(princ " nil " fd));;stop recursion
((atom V) ;;stop recursion
(setq typ (type V))
(cond
((= 'REAL typ) ;;decimal output controlled
(princ (rtos V 2) fd) ;;by DIMZIN and LUPREC
(princ " " fd)) ;;as per AutoLISP manual
((and (= 'STR typ) (setq i (isinstr (chr 34) V)))
;; is there quote inside?
(princ "(STRCAT " fd) ;; <<<
(while i
(prin1 (substr V 1 (1- i)) fd)
(princ " (chr 34) " fd) ;; <<<
(setq V (substr V (1+ i))
i (isinstr (chr 34) V))
)
(prin1 V fd)
(princ ") " fd))
(T ;;regular atomic (non-list) value
(prin1 V fd)
(princ " " fd)) ))
((and (cdr V) (atom (cdr V))) ;; dotted pair
(princ "(" fd)
(fprinv (car V)) ;; recursion !!
(princ ". " fd)
(fprinv (cdr V)) ;; recursion !!
(princ ") " fd))
(T ;; regular list
(princ "(" fd)
(mapcar 'fprinv V) ;; recursion !!
(princ ") " fd))
))

So, again, we save VAR with
(setq fd (open "tmp.tmp" "w"))
(princ "(setq var (quote" fd)
(fprinv var)
(princ "))" fd)
(setq fd (close fd))
and retrieve with
(load "tmp.tmp")

NB! specify file extension explicitly,
if it's not a ".LSP".

CAUTION! If user break out with ^C, your file
is left not-closed, and you can't access it,
so be sure to put '(SET FD(CLOSE FD)) statement
into your error handling routine.


Basically FPRINV is a simple recursion on list with some
trick done to overcome inner-quotes-in-string problem.
As you could see, I use here ISINSTR function, that
returns index of substring inside other string (based 1).
Here it is -- ( I wonder if anyone have
better/simpler/faster version of this -- if you
do, please post it.)


;;;;returns index of substr in str or nil if not found
(defun isinstr( subs s / l1 l2 cnt ret x)
;; is SUBS inside the string S ??
(setq
l1 (strlen subs)
l2 (strlen s)
ret nil
)
(if (= l1 l2)
(if (= subs s)
(setq ret 1) ;; subs begins at pos 1 in s
)
)
(if (< l1 l2) (progn ;; else l1 < l2
(setq cnt 1) ;; string begins at 1
(setq x (+ (- l2 l1) 1))
(while (and (not ret) (<= cnt x) )
(if (= subs (substr s cnt l1))
(setq ret cnt)
;;(isinstr "" _string) == 1 ,
;;because (substr s 1 0) == ""
)
(setq cnt (1+ cnt))
)))
ret ;;position of substr in str, from 1
)

Best wishes,
Vladimir Nesterovsky <vne...@netvision.net.il>
01/16/96 01:28:04

================ end quoting article =====================

That's it. Use it as you wish, but only for legal purposes please. :)
If you'd make a lot of money with it, send me a small donation. :)

Cheers -----------
Live long and prosper :)
Vlad
==================
(defun re-list(l / s)
(re-list-i l))
(defun re-list-i(l / tok)
(setq tok (car l) s (cdr l))
(cond
((null l) nil)
((="}"tok)nil)
((="{"tok)
(cons (re-list-i s)(re-list-i s)))
(T(cons tok (re-list-i s)))))
==================


Chris L. Amos wrote:


>
> Eric A. Stiles wrote:
> >
> > I'm writing a program in AutoLISP and I'm stumped. I would like to be
> > able to save a LIST of different info including an assocation list to a
> > file. I started to do this when I realized that the (write-line)
> > function only writes text to a file. AutoLISP was created for
> > manipulating list, it seems that there should be a way to do this.
> >
> > Any Ideas, Eric
>

Héctor (HEDA)

unread,
Jul 16, 1997, 3:00:00 AM7/16/97
to

On Sun, 13 Jul 1997 17:50:59 -0700, "Eric A. Stiles"
<est...@gmgw.com> wrote:

>I'm writing a program in AutoLISP and I'm stumped. I would like to be
>able to save a LIST of different info including an assocation list to a
>file. I started to do this when I realized that the (write-line)
>function only writes text to a file. AutoLISP was created for
>manipulating list, it seems that there should be a way to do this.
>
> Any Ideas, Eric

You can try to write each list element to a single line of the file.
And the retrieve the elemets to construct again the list.


(setq sign (list (list name "Hector D. Corcin")
(list nickname "_HeDa_")
(list e-mail "he...@geocities.com")
(list homepage "http://www.yi.com/home/CorcinHector")
)
)

Reini Urban

unread,
Jul 17, 1997, 3:00:00 AM7/17/97
to

On Wed, 16 Jul 1997 03:44:24 +0300, Vladimir Nesterovsky
<vne...@netvision.net.il> wrote:
snip

> (defun re-list(l / s)
> (re-list-i l))
> (defun re-list-i(l / tok)
> (setq tok (car l) s (cdr l))
> (cond
> ((null l) nil)
> ((="}"tok)nil)
> ((="{"tok)
> (cons (re-list-i s)(re-list-i s)))
> (T(cons tok (re-list-i s)))))


Now I understand what you meant by:
"Did you have a look at (re-list)?"
Not really understandable at the first glance, esp. why you used two funcs
instead of one and why you used "s" as local param in the first func and not
in the second. Looks like it has something to do with dirty side-effect tricks
by changing "s" in the 2nd func for the (cons (re-list-i s)(re-list-i s)))
line. Indeed very dirty trick.

Is it a EED-list to Lisp-list conversion as posted by Serge (de_plain), Morten
(cl) and yours (rebuild-list) in our EED thread?
< stored at http://xarch.tu-graz.ac.at/autocad/news/eed_retrieval.txt >
--
Reini
AutoCAD stuff: http://xarch.tu-graz.ac.at/autocad/

Vladimir Nesterovsky

unread,
Jul 22, 1997, 3:00:00 AM7/22/97
to Reini Urban, Morten Warankov

Hi Reini!

Just got your message in DEJANEWS -- by accident, really. ;-(
If you would just put me on CC, I'd get your message as a
side effect ;-) despite my damn ISP's low newsfeed.

As for our matters ---

No, it's not a dirty trick, it's a very clean one. :):):)
It has to do with keeping some variable static from call
to call (in C-terms) or, in LISP -- providing _lexical closure_
for this variable (I've obviously done some Winston&Horn readings,
have I? ). :):) In AutoLISP I can do this by nested functions, when
the inner function is a real working one, and outer function
is to be called.

Yes, it's about this old EED-decoding question. You remeber that
discussion, of course. I couldn't find a LISP solution, so did it in C,
subctituting RTLB/RTLE resbufs for RTSTR("{"/"}") ones. Of course, I
wanted then a LISP solution. We got back then a function from Serge, but
it was big and hard to comprehend (for me, that is). Than there was a
nice trick from Morten (I only did some refinement on it) -- just
convert the whole thing into a string while changing curly braces to
parentheses, put it inside another pair of parentheses, and hand it over
to READ -- let it do the work! It was nice, but it have a reals'
precision problem and it isn't really a LISP solution -- I mean, the real
work is done by READ, and how it does its work, remains a mystery.

So I did a little thinking some day. What I really wanted was, actually,
a sort of specialized READ function. Now it's essencially the same,
whether it's done in C or by READ ( when C sends a list back to LISP,
the latter does the same work) --- the meaning is TO CONVERT PLAIN,
ONE-DIMENTIONED STREAM INTO REAL TREE-LIKE LIST.

Once again -- the lists in LISP are actually the trees -- each list
can have nested list inside it and so on. On the other hand, what
READ has at its input, is PLAIN INPUT ONE-DIMENTIONAL STREAM.
And it doesn't matter, if it's stream of characters, or stream of tokens
of some kind -- like XDATA IS!!!

So to make XREAD for reading xdata records is like to write a READ
function which only has some specialized sort of tokens at input.

And here's a trick --
It's natural to try to accomplish the thing via RECURSION. But HOW can I
achieve the right grouping? To balance a parenths? And most of all -- IF
I stop recursion by returning NIL - but "}" was at the middle of stream --
how can I continue???

The answer stroke me -- make this recursion ITERATIVE! ;-) That means --
itereate over the input stream, keeping the record of it at OUTER level
of variables, so that it doesn't get destroyed by recursion, AND rebuild
the structure of LISTS by recursion!

Here it is again with more clearer names and comments:

;; the function to be called
(defun xread ( stream / rest-of-stream ) ;;provide LEXICAL CLOSURE
(_xread stream)) ;;for REST-OF-STREAM variable

(defun _xread ( stream / token )
(setq token (car stream)
rest-of-stream (cdr stream)) ;; <<<<<<<<< !!!!!
(cond
((null stream) nil) ;;stop the recursion
((= "}" token) nil) ;;stop THIS LEVEL OF recursion! Another will
;;continue if REST-OF-STREAM isn't NIL
;; here's the tricky part: ;-)
((= "{" token) ;;we need to add this AS A LIST
(cons
(_xread rest-of-stream) ;; will return list, and stop
;; eventually on "}"
(_xread rest-of-stream) ;; CONTINUE READING PROCESS!
)) ;; rest-of-stream is different second time!!!
(T ;; regular case -- the last case, as usually
;; in recursive functions
;; add token as ATOM
(cons token (_xread rest-of-stream)))))

So if you apply XREAD on regular 1-dim list like '(1 2 3 4 5),
it just reconstructs it again from it's atoms, working through
the last case in COND and stopping on 1st. BUT if you'd try it
with '( 1 "{" 2 3 "{" 4 "}" 5), you'll see the magic.

Another little thing to add: how to whatch the execution.
TRACE won't really help, as it will be hard to understand.
Here's the same function rewritten to PRINT while it works:


(setq *verbose* 'T) ;; set to NIL to suppress output

(defun pxread (lst / inp) ;; with Print Out
(_pxread 2 lst)
(princ) )

(defun _pxread (k l / tok);; RECURSIVE ITERATION ! :) :)
(prink "TOK: " (setq tok (car l)))
(setq inp (cdr l))
(setq res
(cond
((null l) nil) ;; stop recursion!
((= "}" tok) nil) ;; stop recursion! INPut continues.
((= "{" tok) (cons
(_pxread (+ k 2) (prink "FIRST : " inp) )
(_pxread (+ k 2) (prink "SECOND: " inp))))
(T (cons tok
(_pxread (+ k 2) (prink "REST : " inp))))))
(prink "RES: " res) )

(defun prink(m x)
(if *verbose* (progn
(princ "\n")
(repeat k (princ " "))
(princ m)
(prin1 x)) x ))

Enjoy! :):)

P.S. The real reason I'm getting excited with all this, is that
it's pretty simple to code it in C, and we have also EVAL and APPLY
that work together, in Winston&Horn (got mine at AMAZON.COM).
So one could write his own little LISP .....

In article <33cdf4d6...@news.sime.com>,


Reini Urban <rur...@sbox.tu-graz.ac.at> wrote:
>
> On Wed, 16 Jul 1997 03:44:24 +0300, Vladimir Nesterovsky
> <vne...@netvision.net.il> wrote:
> snip

> > (defun re-list(l / s)
> > (re-list-i l))
> > (defun re-list-i(l / tok)
> > (setq tok (car l) s (cdr l))
> > (cond
> > ((null l) nil)
> > ((="}"tok)nil)
> > ((="{"tok)
> > (cons (re-list-i s)(re-list-i s)))
> > (T(cons tok (re-list-i s)))))
>

> Now I understand what you meant by:
> "Did you have a look at (re-list)?"
> Not really understandable at the first glance, esp. why you used two funcs
> instead of one and why you used "s" as local param in the first func and not
> in the second. Looks like it has something to do with dirty side-effect
tricks
> by changing "s" in the 2nd func for the (cons (re-list-i s)(re-list-i s)))
> line. Indeed very dirty trick.
>
> Is it a EED-list to Lisp-list conversion as posted by Serge (de_plain),
Morten
> (cl) and yours (rebuild-list) in our EED thread?
> < stored at http://xarch.tu-graz.ac.at/autocad/news/eed_retrieval.txt >
> --
> Reini
> AutoCAD stuff: http://xarch.tu-graz.ac.at/autocad/

-------------------==== Posted via Deja News ====-----------------------
http://www.dejanews.com/ Search, Read, Post to Usenet

0 new messages