View Full Version : File manipulation with LISP
jguest82179
2005-11-21, 10:29 PM
Can anyone tell me why the following code:
(setq FILENAME (getvar "DWGNAME"))
(setq FILEPATH "N:\\Extract\\")
(setq FILE (strcat FILEPATH FILENAME ".txt"))
(setq F (open FILE "a"))
(write-line VALUES FILE)
(close F)
delivers this error?
; error: bad argument type: output-streamp:
Any help would be appreciated. Thanks. :-)
It looks like you are trying to write to a variable that is not a pointer to a file. You have saved the filename within variable FILE but you are opening a pointer to in the variable F. You are then trying to write to the FILE variable. You need to write to the F variable and then close F instead of FILE.
jguest82179
2005-11-21, 10:43 PM
Thanks Richard,
I spotted the error in the line
(close FILE)
which should have read
(close F)
but I was not awake enough to spot the error in the 'write-line' statement. I'll try that fix right now.
jguest82179
2005-11-21, 11:18 PM
Thanks Richard - it works now! :-D
The new code now reads:
(setq FILENAME (getvar "DWGNAME"))
(setq FILEPATH "N:\\TA_Custom\\Extract\\")
(setq FILE (strcat FILEPATH FILENAME ".txt"))
(setq F (open FILE "a"))
(write-line VALUES F)
(close F)
Now I have another small problem. What I am actually trying to do with this LISP is to pull all of the attributes out of the title block of a drawing and into a text file (obviously there is more code than just that above).
The problem is that the title block of these drawings has not been made well and has three instances of the same attribute tag. The code that I have written is only finding the first instance of this tag and collecting its data from there - then ignoring the other two.
Here is the code that I am using:
(defun C:ALLATT ()
(progn
(setq ALLENT (ssget "all"))
(setq NUMENT (sslength ALLENT))
(setq INDEX 0)
(repeat NUMENT
(setq NEXTENT (entget (ssname ALLENT INDEX)))
(setq INDEX (+ 1 INDEX))
(setq ENTTYPE (assoc 0 NEXTENT))
(if (= "INSERT" (cdr ENTTYPE))
(progn
(setq BLOCK NEXTENT)
(if (and (= "INSERT" (cdr (assoc 0 BLOCK))) (= 1 (cdr (assoc 66 BLOCK))))
(progn
(setq ATTVALLIST nil)
(while (= "ATTRIB" (cdr (assoc 0 (setq BLOCK (entget (entnext (cdr (car BLOCK))))))))
(progn
(setq ATTVALLIST (cons (cons (cdr (assoc 2 BLOCK)) (cdr (assoc 1 BLOCK)))ATTVALLIST))
(setq VALUES (strcat (car (car ATTVALLIST))))
(Setq VALUES (strcat VALUES ","))
(setq VALUES (strcat VALUES (cdr (car ATTVALLIST))))
(setq VALUES (strcat VALUES ","))
(setq BLOCK (entget (entnext (cdr (car BLOCK)))))
(setq FILENAME (getvar "DWGNAME"))
(setq FILEPATH "N:\\TA_Custom\\Extract\\")
(setq FILE (strcat FILEPATH FILENAME ".txt"))
(setq F (open FILE "a"))
(write-line VALUES F)
(close F)
)
)
)
)
)
)
)
)
)
Can anyone think of a way to get it to find the other two instances of the tag and include them in its output as well?
T.Willey
2005-11-22, 12:12 AM
Are you trying to get all the blocks in the drawing, and write to a text file, all the attribute information? If so, then look into ActiveX controls. I think it will make your like a lot easier.
Tim
jguest82179
2005-11-22, 12:17 AM
Well actually I changed the code a little more after I posted it, because I was working with older drawings that only had the one block in them (being the title block), but I would soon need to expand it beyond that. So I added an 'and' statement with a condition of 'assoc 2' (block name) to limit it to that one block.
T.Willey
2005-11-22, 12:22 AM
Did you get it to work the way you want it to? If not, post what is happening, and what you want to happen, and someone can help you out.
Tim
jguest82179
2005-11-22, 12:40 AM
Yes, the code does the basic task that I required of it.
The only problem that I have now is that of a block that has somehow managed to get three identical attribute tags (with different information) within the one block.
The above code simply grabs the first of the three instances and ignores the other two.
Can you post a copy of the drawing that has this attribute problem? It could help in creating a solution for you.
T.Willey
2005-11-22, 04:24 PM
It should show all the attributes, even if the tag name is the same. Try this and see if it works because it worked for me.
(defun c:Testing (/ Sel Ent EntData)
(if
(and
(setq Sel (entsel "\n Select block: "))
(setq Ent (car Sel))
)
(while (= "ATTRIB" (cdr (assoc 0 (setq EntData (entget (setq Ent (entnext Ent)))))))
(prompt (strcat "\n Tag value = " (cdr (assoc 2 EntData)) " , Attribute value = " (cdr (assoc 1 EntData))))
)
)
(princ)
)
Here is what was printed to the text screen.
Command: testing
Select block:
Tag value = HELLO , Attribute value = tag 4
Tag value = HELLO , Attribute value = tag 3
Tag value = HELLO , Attribute value = tag 2
Tag value = HELLO , Attribute value = tag 1
Command:
Tim
jguest82179
2005-11-22, 10:52 PM
You are exactly right, Tim.
IF I had proof read my code properly I would have figured out why it was not getting all of the data.
Unfortunately I did not, and even worse - I decided to make do with what I could get as even it was better than nothing. So I have processed about 4500 drawings in a batch, using incorrect code. This means that I now have to do them all over again using the right code. :sad:
Thanks to everyone for all of your help. :-)
(progn
(setq ATTVALLIST nil)
(while (= "ATTRIB" (cdr (assoc 0 (setq BLOCK (entget (entnext (cdr (car BLOCK))))))))
(progn
(setq ATTVALLIST (cons (cons (cdr (assoc 2 BLOCK)) (cdr (assoc 1 BLOCK)))ATTVALLIST))
(setq VALUES (strcat (car (car ATTVALLIST))))
(Setq VALUES (strcat VALUES ","))
(setq VALUES (strcat VALUES (cdr (car ATTVALLIST))))
(setq VALUES (strcat VALUES ","))
(setq BLOCK (entget (entnext (cdr (car BLOCK)))))
(setq FILENAME (getvar "DWGNAME"))
(setq FILEPATH "N:\\TA_Custom\\Extract\\")
(setq FILE (strcat FILEPATH FILENAME ".txt"))
(setq F (open FILE "a"))
(write-line VALUES F)
(close F)
)
)
)
)
As you can see, it was my own silly mistake that was stopping me from getting all of the data. The above code effectively moves to the next entity twice in a row, therefore it will only get every second attribute. After removing the second 'entnext' it now gets all of the data as intended, and I can now build a more complete database from the results. :-D
Thanks for the update. I'm glad you problem was solved. I hate to hear that you had that many drawings to redo. :(
Have a :beer:
Richard
T.Willey
2005-11-22, 11:17 PM
IF I had proof read my code properly I would have figured out why it was not getting all of the data.
Glad you found it. I looked through your code, and didn't catch it either. Hope you have it in a batch process, so at least YOU don't have to open and run the command in each.
Tim
jguest82179
2005-11-22, 11:31 PM
Well, I'm trying to do that.
I have ScriptPro on my machine, but I couldn't find the install file to load it onto another machine so I downloaded it again from AutoDesk but it won't install.
Can anyone help?
T.Willey
2005-11-22, 11:51 PM
Sorry never used ScriptPro. Buy you can write a lisp that will write a script. It would be easy if all the drawings were in one folder.
Tim
jguest82179
2005-11-23, 12:13 AM
It's OK, I just found ScriptPro as a part of another package that actually installs properly.
Autodesk Customization Conversion Tools (http://usa.autodesk.com/adsk/servlet/item?siteID=123112&id=4091678&linkID=2475897)
(Thanks to Mike Perry - I pinched that from one of his posts.)
OK Tim, do you ever need to perform the same operation on more than a handful of drawings at a time? If so, then ScriptPro is an absolutely invaluable tool.
It is dead easy to use, and it has its own logging and error handling systems built in so if your script encounters, for example, a dwg that needs recovery then ScriptPro will simply make a note of the fact and then move on to the next drawing allowing you to continue without interruption and then return to the offending file at a later time. BRILLIANT! :-D
kennet.sjoberg
2005-11-23, 12:14 AM
Hi guest !
I like to write my code myself, because I have learn a lot of that so when I now steps in to your code I hope you do not mind
(defun C:ALLATT ( / ALLENT NUMENT YouPutTheRestOfThemHere ) ; <--take care and declare your local variables to the right of the /
; (progn ; progn not nessesary
(setq ALLENT (ssget "all")) ; <-- if you are interested in only block, filter out everything else
(setq ALLENT (ssget "_X" '((0 . "INSERT") )) ) ; <-- like this
; (setq ALLENT (ssget "_X" '((0 . "INSERT")(2 . "MyBlockName") )) ) ; <-- or even better if you know the name of the block
; (setq ALLENT (ssget "_X" '((0 . "INSERT")(2 . "MyBlockName")(66 . 1) )) ) ; <- I found 66 in the code, it is god I will use that one
(setq ALLENT (ssget "_X" '((0 . "INSERT")(66 . 1) )) ) ; I miss the blockname "MyBlockName" so I skip it ( but not you )
(setq NUMENT (sslength ALLENT)) ; <-- wooow minimized selectionset, think turbo
(setq INDEX 0)
(setq NEXTENT (ssname ALLENT INDEX )) ; <-- this is the first block in the selectionset
(repeat NUMENT
; (setq NEXTENT (entget (ssname ALLENT INDEX))) ; <-- this make no sense here
(setq INDEX (+ 1 INDEX))
; (setq ENTTYPE (assoc 0 NEXTENT)) ; <-- if we select only "INSERT" this make no sense
; (if (= "INSERT" (cdr ENTTYPE)) ; <-- and not this eigther
; (progn ; hmm.. no if no progn
; (setq BLOCK NEXTENT) ; <-- leftover
; we allready know this (if (and (= "INSERT" (cdr (assoc 0 BLOCK))) (= 1 (cdr (assoc 66 BLOCK)))); <-- aha 66 "Entities follow" move it to "_X"
; (progn ; hmm.. no if no progn
; (setq ATTVALLIST nil) ; <-- not neccesary
; ok, the block is now NEXTENT and we know it has "Entities follow" = ATTRIBUTE only, let us check them
(setq NEXTENT (entnext NEXTENT )) ; <-- this is the entname of the first attribute in the block
; (while (= "ATTRIB" (cdr (assoc 0 (setq BLOCK (entget (entnext (cdr (car BLOCK)))))))) ; lets make an other test
(while (= "ATTRIB" (cdr (assoc 0 (entget NEXTENT)))) ; exit while when SEQEND
; (progn ; unneccesary we are enclosed by the while loop
; (setq ATTVALLIST (cons (cons (cdr (assoc 2 BLOCK)) (cdr (assoc 1 BLOCK)))ATTVALLIST)) ; leftover
(setq ATTVALLIST (entget NEXTENT) ) ; this can be done in the while argument
; (setq VALUES (strcat (car (car ATTVALLIST)))) ; leftovers
; (Setq VALUES (strcat VALUES ","))
; (setq VALUES (strcat VALUES (cdr (car ATTVALLIST))))
; (setq VALUES (strcat VALUES ","))
; it would be nice if i know what to print, but I suppose "tag" and "value"
(setq VALUES (strcat (cdr (assoc 2 ATTVALLIST )) "," (cdr (assoc 1 ATTVALLIST ))))
; (setq BLOCK (entget (entnext (cdr (car BLOCK))))) ; leftover
(setq FILENAME (getvar "DWGNAME")) ; this ends with .dwg
(setq FILENAME (vl-filename-base (getvar "DWGNAME"))); this ends without .dwg
(setq FILEPATH "N:\\TA_Custom\\Extract\\")
(setq FILEPATH "C:\\Temp\\") ; <-- erase my debugging line
(setq FILE (strcat FILEPATH FILENAME ".txt")) ; I suggest you put this before the repeat (and open only IF there is a selectionset )
(setq F (open FILE "a")) ; hmm.. it will be a lot of network open an close
(write-line VALUES F) ; "a" append may not be the right choice
(close F) ; I suggest you close the file after you have iterated all the blocks, put it close to the (princ) line
; ) ; ... enclosed by the while loop
(setq NEXTENT (entnext NEXTENT )) ; well, now we have checked one attribute let the while loop take next
) ; endwhile
; ) ; hmm.. no if no progn
); one block is done, let us send next to repeat ( if it exist )
; ) ; hmm.. no if no progn
; ) ; hmm.. no if
; ) ; no progn nessesary
; ) ; [ Moderator Action = ON ] Profanity removed. [ Moderator Action = OFF ]****, I miss this one
(princ) ; happy silence end
) ; end defun
When you kill all comments and extra lines there will be 23 lines left of working code
: ) Happy Computing !
kennet
T.Willey
2005-11-23, 12:19 AM
When I have a situation like that I usually write a lisp that can handle what I need specifically. Thanks for sharing that bit of information. I've only used scripts a couple of times, and they seem useful and easy to use every time I have used them.
Glad you found what you need.
Tim
T.Willey
2005-11-23, 12:35 AM
Since we are sharing code. This is how I would write it. You may want to change the path of the text file.
(defun c:ExtractAtts (/ ss File Opened Ent AttList)
(vl-load-com)
(if (setq ss (ssget "x" '((0 . "INSERT") (66 . 1))))
(progn
(setq File "C:/temp/test.txt")
(setq Opened (open File "a"))
(write-line (strcat "Drawing full path = \"" (getvar "dwgprefix") (getvar "dwgname") "\"") Opened)
(while (setq Ent (ssname ss 0))
(write-line (strcat " Block name = \"" (cdr (assoc 2 (entget Ent))) "\"") Opened)
(setq AttList (vlax-invoke (vlax-ename->vla-object Ent) 'GetAttributes))
(foreach Att AttList
(write-line (strcat " Tag value = \"" (vla-get-TagString Att) "\" , Attribute value = \"" (vla-get-TextString Att) "\"") Opened)
)
(write-line "" Opened)
(ssdel Ent ss)
)
(close Opened)
)
)
(princ)
)
Tim
kennet.sjoberg
2005-11-23, 12:58 AM
Since we are shari.....
Great, I suppose someone can efficient that code,
but the purpose with this Thread is not only to share and eat code, the main thing is to learn.
<escape mode on>
: ) Happy Computing !
kennet
jguest82179
2005-11-23, 12:58 AM
Thanks Kennet and Tim for posting your code, it is always interesting to see different ways of achieving the same outcome.
I have taken a detailed look at your code, Kennet, and I think I understand it pretty well. I especially like the filtering of the 'ssget' function - I wasn't aware of that capability, but I think I will be making plenty of use of it in future.
I have also taken a look at your code, Tim, and I see what you are doing but I am not familiar with the functions that start with vl, vla, & vlax (you used one in your code too, Kennet). I assume that these are 'Visual Lisp' functions, yes? I still have a lot of learning to do, where would I find out more about these in particular? (Preferably printed material, or another thread here on AUGI - I hate "Help Files")
jguest82179
2005-11-23, 01:01 AM
When I have a situation like that I usually write a lisp that can handle what I need specifically. Thanks for sharing that bit of information. I've only used scripts a couple of times, and they seem useful and easy to use every time I have used them.
I forgot to mention earlier, in this instance I am simply using the script (and ScriptPro) to load and launch the lisp that we have been discussing here.
T.Willey
2005-11-23, 04:15 PM
Things that start with "vl" are visual lisp (in my knowledge, which could be wrong), and then "vla" or "vlax" are ActiveX control wrappers so you can use VBA calls in lisp. That is my understanding. I learned about the ActiveX controls mostly from the help files. Sorry, I know you didn't want to hear that.
Kennet,
That is why I didn't post code until we got his resloved. Just showing another way to skin a cat.
Tim
kennet.sjoberg
2005-11-23, 07:29 PM
. . . but I am not familiar with the functions that start with vl, vla, & vlax (you used one in your code too, Kennet). . .
Yes vl- commands is a tiny improvement, but you can use next line if "old lisp" feels better
(setq FILENAME (substr (getvar "DWGNAME") 1 (- (strlen (getvar "DWGNAME")) 4 )) )
but I hope there will be a time when vl-, vla-, vlx, vlr- commands is all over your code.
The vla- functions implement ActiveX support in AutoLISP
The vlax- functions provide ActiveX utility and data conversion functions, dictionary handling functions, and curve measurement functions.
The vlr- functions provide support for AutoCAD reactors.
if you are going to use (vla-bla-bla) or (vlax-bla-bla) or (vlr-bla-bla)
you must load (vl-load-com) the ActiveX and Visual LISP extensions to the AutoLISP environment language.
: ) Happy Computing !
kennet
BTW If you are using Visual Lisp (vl-bla-bla) you do not need to load the extensioner.
jguest82179
2005-11-23, 10:27 PM
Yes vl- commands is a tiny improvement, but you can use next line if "old lisp" feels better
(setq FILENAME (substr (getvar "DWGNAME") 1 (- (strlen (getvar "DWGNAME")) 4 )) )
but I hope there will be a time when vl-, vla-, vlx, vlr- commands is all over your code.
Thanks Kennet,
It's not so much a case of preferring "old lisp", it's just that I don't know anything about the various 'vl-' functions and as such have not tried to use them as yet. I'm also using VBA for programming databases a lot lately, so I'm not opposed to trying new concepts by any means.
That is my understanding. I learned about the ActiveX controls mostly from the help files. Sorry, I know you didn't want to hear that.
You're right Tim - I didn't want to hear that! :-(
Nah, just kidding. :-) I guess that the help files are my closest resource, but what I was really hoping for was something with some useful tutorials and such.
Cheers,...Jon.
T.Willey
2005-11-23, 11:15 PM
but what I was really hoping for was something with some useful tutorials and such.
Check www.afralisp.co.za I have seen some good stuff on there web site. And don't forget that you can always post questions here for something you don't understand.
Tim
Powered by vBulletin® Version 4.2.5 Copyright © 2025 vBulletin Solutions Inc. All rights reserved.