Nothing Special   »   [go: up one dir, main page]

The Visual LISP Editor

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 192
At a glance
Powered by AI
AutoLISP is a programming language used to automate tasks in AutoCAD. Some common functions and their uses are discussed in the document.

AutoLISP is a dialect of the LISP programming language built specifically for use with the full version of AutoCAD. It is used to create programs to automate tasks in Autocad.

Some common AutoLISP functions discussed are GETVAR, IF, INDEX, NTH, SUBSTR, UPPER, and their uses. Functions like GETVAR can retrieve system variables, IF performs conditional evaluations, and INDEX/NTH can extract values from comma-delimited strings.

https://books.google.com.vn/books?

id=EOrpBwAAQBAJ&pg=PA180&lpg=PA180&dq=how+to+int
erpreting+the+autocad+command+to+autolisp&source=bl&ots
=ZiMzAwQsWL&sig=ACfU3U18hajT-Cqv4iOP-ZQ0KzBoj-
1Irw&hl=vi&sa=X&ved=2ahUKEwj2_dPLwt3hAhUKpo8KHerh
A-UQ6AEwC3oECAcQAQ#v=onepage&q=how%20to
%20interpreting%20the%20autocad%20command%20to
%20autolisp&f=false

Essential AutoLISP®: With a Quick Reference Card and a


Diskette
how to interpreting the autocad command to autolisp

https://forums.autodesk.com/t5/visual-lisp-autolisp-and-
general/autolisp-books/td-p/846456

http://doannghiep.tk/download/c49QAAAAMAAJ-essential-
autolisp

https://knowledge.autodesk.com/search-
result/caas/CloudHelp/cloudhelp/2016/ENU/AutoCAD-
AutoLISP/files/GUID-234D7B54-1972-4E84-9CFB-
1057DE3D10EB-htm.html
https://www.afralisp.net/autolisp
https://www.afralisp.net/visual-lisp/tutorials/beginning-
visual-lisp-part-1.php
http://www.jefferypsanders.com/autolisptut.html
https://www.pdfdrive.com/autolisp-books.html
http://www.jefferypsanders.com/autolispbeg.html
https://knowledge.autodesk.com/search-
result/caas/CloudHelp/cloudhelp/2016/ENU/AutoCAD-
AutoLISP/files/GUID-38D0244E-C0C7-4FF0-A4B9-
DE6E05635BD6-htm.html
http://www.perthcadservices.com.au/index.php/cad-bim-3d-
printing-blog/55-the-best-5-auto-lisp-routines-that-every-
autocad-drafter-must-know-about
- https://forums.autodesk.com/t5/visual-lisp-autolisp-and-
general/convert-autolisp-commands-to-cad-
commands/td-p/1649416
- https://forums.autodesk.com/t5/visual-lisp-autolisp-and-
general/converting-macro-to-lisp/td-p/2395139
- https://knowledge.autodesk.com/search-
result/caas/CloudHelp/cloudhelp/2016/ENU/Auto
CAD-AutoLISP/files/GUID-75F19C76-78D0-443B-
BC39-EB9FEB4650B1-htm.html
- https://www.cadtutor.net/tutorials/autolisp/quic
k-start.php
- https://www.scribd.com/document/12318800/Aut
oLisp
- https://www.scribd.com/search?
content_type=documents&page=1&query=Essenti
al%20AutoLISP
- http://www.4d-technologies.com/techcenter/
-
- https://www.google.com.vn/search?
sa=N&biw=1242&bih=547&q=how+to+interpreting+the+
autocad+command+to+autolisp&tbm=isch&source=univ
&ved=2ahUKEwimtbfowt3hAhUIYo8KHWlrCMI4ChCwB
HoECAkQAQ
-

https://www.youtube.com/watch?v=cBTQ0uHaI4Y
https://www.afralisp.net/visual-lisp/
http://www.theswamp.org/index.php?topic=41040.0
https://stackoverflow.com/questions/17964480/build-
automation-for-autocad-lisp-files
https://www.youtube.com/watch?v=Jlw3UgFSiKM
https://www.youtube.com/watch?v=cBTQ0uHaI4Y
http://ntdh.warriorcry.fun/g5zckL1EtWc/Tutorial_Visual_Lisp
_Autocad_0007_Programando_DCL/
https://news.ycombinator.com/item?id=19677292

(defun c:Region2Polyline nil

(if (setq ss (ssget "_x" '((0 . "REGION"))))

(:Region2Polyline ss)

(princ)

)
5 AUTO LISP routines
that every AutoCAD
drafter must know
about.
What is AutoLISP? AutoLISP is a dialect of the LISP
programming language built specifically for use with the full
version of AutoCAD. It is used to create programs to use in
Autocad that are not built in with the software. Almost all
manual commands you use can be automated to increase
productivity, Lisp routines can do all sorts of weird and
wonderful things. Below are my top 5 favorite LISPs programs
that if introduced will save you lots of time.

5) Block count

Lee Mac’s Block count this program enables the user to record
the quantities of a selection or all standard or dynamic blocks in
the working drawing. The results of the block count may be
displayed at the AutoCAD command-line, written to a Text or
CSV file, or displayed in an AutoCAD Table, where available.

4) Batch Attribute Editor


Again from Lee Mac, this tool is great for updating title blocks,
especially on larger projects this tool is priceless. Basically this
program allows the user to modify the values of multiple
attributes residing within multiple attributed blocks across
multiple drawings.

3) Trim around

Trim around Text by Yuqun Lian This routine writes a text string
to the drawing and then breaks any lines, polylines, etc. that
intersect an imaginary box around the text. The text is placed on
the current layer using the current style. The default input and
repeat capabilities of TB.LSP make multiple labeling very
convenient.

2) Double offset

Back to Lee Mac again for the double offset, if you find you start
all your drawings in the center line then this one is for you. This
program operates in much the same way as the standard offset
command, however will perform an offset to both sides of the
selected object.

1) Incremental Numbering Suite

Finally my favorite Lisp is the Incremental Numbering Suite by


the one and only lee Mac. The Incremental Numbering Suite
enables the user to dynamically place incrementing
alphabetical or numerical text in a drawing, with a range of
positioning utilities and an optional prefix and/or suffix.

I hope you will find these new Lisp programs useful and
productive in your everyday Autocad drafting life, please feel
free to share your own in the comments.

Below are some more useful links for more LISP programs.

http://www.lee-mac.com/programs.html

http://paulogilsoto.blogspot.com.au/2009/10/links-to-lisp-
routines.html

http://www.simplecad.com/autolisp-files

http://web2.airmail.net/terrycad/AutoLISP-Code.htm

If you found this helpful please have a look at our post 10


helpful Autocad commands for more productive CAD drafting

http://www.perthcadservices.com.au/index.php/cad-bim-3d-
printing-blog/47-more-productive-cad-drafting
AutoLISP Quick Start
by Kenny Ramage

See also, The AfraLISP Website

Introduction
This tutorial is aimed at the AutoCAD users who would like to start learning AutoLisp. I suggest that
you go through this tutorial along with the AutoCAD Programmers Reference Guide. You can then
lookup the relevant AutoLisp commands for a more detailed explanation. Hope this helps you and
Good Luck in your Lisping - Kenny Ramage

Principles of Programming
All AutoLisp programs must contain the suffix ".LSP" otherwise AutoCAD will not access them when
loading. (eg. CHTEXT.LSP).

Use a simple text processor such as Notepad to create and edit your lisp files.

Function (which is simply the program)

Is a pre-defined set of instructions that describes a set of actions that AutoLisp is to perform, divided
into three sections:

 OPERATOR - Getting input.


 ARGUMENT - Manipulating the input.
 COMMAND - Using the manipulated input.

Charting

Draw out or write out in English what you want your program to do.

Variables

These are like empty boxes in which to store data, to be used later. In AutoLisp, variables may be a
collection of letters or numbers as long as they begin with the letters.

Example of legal variables are as follows:

 A
 ARC1
 POINT1
 PNT1
 D3

An AutoLisp variable may contain more than one value in a single variable. A value can be anything,
such as :

 Real number
 String
 Integer
 Pickset

Therefore a variable can store just about anything.

Structuring

Structure your program in such a way that it is easy to understand, by yourself and everyone else. e.g.
Keep input statements together. Keep your arguments together. Keep your commands together. Track
your work with the semicolon. When you begin a line with a semicolon, anything you write after will be
ignored by AutoLisp. It is used for documentation and explanation of your program. Write notes about
your program, what you are doing and what the variables are. A semicolon does not have to begin the
line.

(prompt "This line will print"); This is a comment

From where the semicolon begins, the remainder of the line is a comment statement.

Parentheses ( )

Parentheses are vital to writing AutoLisp programs. All commands are surrounded by parentheses.
AutoLisp uses parentheses to nest, allowing you to write a command that acts on (evaluates) another
command. In turn, that command can act on another. As you add parentheses, you're nesting
commands become deeper and deeper. Remember to come out of the nest with an equal number of
parentheses.

Note: Always close what you open.

Defun (Define Function)


In AutoLisp the name of the program or function must be defined in the first statement, which is done
by using the command:

(defun functionname ()

body of program

Defun is the first actual command and is followed by the name of the function (or program). Defun
encloses the entire program and its closing bracket comes after the main body of the program There
are different ways of starting a function for example:

1. (defun drawline ()

The first way, you are saying that all variables you plan to use in the program are GLOBAL,
which are variables that do not lose their value after the program ends.

2. (defun drawline (/ pntl pnt2)

The second way, you are saying that the variables you are using are LOCAL variables, which
are variables that have value only for that program and while that program is running.
3. (defun C:drawline ()

The third way, as the first BUT the C: tells AutoCAD to treat that function as any other
AutoCAD command.
4. (defun C:drawline (/ pntl pnt2)

The fourth way, as the second, but an AutoCAD command.


5. (defun drawline (a / pntl pnt2)
The last, variable a receives the first value to it from outside the program.

Data Types
Integers
Are numbers ranging between -32768 and +32767 without decimal points eg: 1
Reals
Are numbers with a decimal point eg: 1.0

Strings
Strings are bits of text and can be up to a maximum length of 100 characters eg: Point 1

Lists
A list is a variable that has more than one element. A point in your drawing is described by the value of
the X co-ordinate and the value of the Y co-ordinate. In AutoLisp, that point can be described by a
single variable, a list of two elements, the first being the X value and the second being the Y value
eg: ( 7 10 ). The following are also examples of lists: ( 5 9 7 2 ) and ( 1.5 2.3 4.9 ).

Atoms
If a variable has a single indivisible value it is an atom. For example, each element in the lists above is
an atom e.g. 6 or A

The type function will return the data type of a variable. For example:

(type "My name")

Will return STR meaning "string". In fact, you can try this for yourself now. Type the code above at the
AutoCAD command prompt and hit enter.

Input Commands (getting info from the user)


AutoLisp provides a number of options for getting different types of data from the user.

Input Commands

getpoint Needs you to pick a point on the screen.

getint Needs an Integer eg: 1.

getreal Needs a real number eg: 10.00.

getcorner Needs a second point on the screen and draws an elastic window from a previous point.

getstring Needs a string of text.

getdist Needs a value either by picking on the screen or a number from the keyboard.

getangle Needs an angle either by pointing on the screen or by typing an angle, which will be returned
in radians.

getkword Needs a keyword from the user.

getvar Will get the value of an AutoCAD system variable.

initget Establishes various options for use by the next getxxx function.

getorient Is similar to the GETANGLE but is affected by the zero-degree base and the direction. It will
always give you the absolute angle using 0 degree base as EAST.

Input Command Examples


In each of the following examples, enter the code at the AutoCAD prompt to see what happens.

1. (getpoint "\nPick a POINT on the screen:") Pick a point when prompted and

AutoCAD will return the value (X Y Z) of that point.

Tip: \n is a special escaped character that takes you to the next line (like a carriage return).

The forward slash character tells AutoLisp to interpret the following character as a special
character rather than just as a letter "n". The "n" must be always be lower case. The use of "\n"
is purely cosmetic (it doesn't change the way the program works) but it does make everything
much easier to read for the user by starting each prompt on a new line.

Caution: Your prompt must always be between quotes, "prompt" otherwise you will get an
error.

2. (getint "\nEnter your age :") Type an integer (such as 34) and AutoLisp will return

that number.

3. (getreal "\nEnter a number :") Type a real number (such as 10.51) and AutoLisp

will return that number.


4. (getcorner pnt1 "\nPick second point :") Will create an elastic window from the

variable called "pnt1", which must already be defined.


5. (getstring "\nWhat is the day today? :") Type some text and Autolisp will return

that text.
Or…
(getstring T "\nWhat is your full name? :") This prompt allows you to enter a

string of words separated by spaces. Ordinarily, AutoCAD will interpret a space in the same
way it interprets a carriage return. The T is a special AutoLisp symbol that means "true" it is

used to allow spaces in string input. In fact, you can use any positive integer (such as 1) in
place of T but the T symbol helps to make the code more understandable.
6. (getdist "\nHow long is the line? :") Pick two points or type a length and

AutoLisp will return that length.


7. (getangle "\nWhat is the angle? :") Pick two points for the angle or type an angle

and AutoLisp will return that angle in radians.


8. (initget 1 "Yes NO")
(getkword "\nAre you going? (Yes or NO):") Initget will control the next getxxx

function and is used to specify a list of valid options or keywords, getkword will accept only
one of the words specifies using initget. In this case, the options are "Yes" or "No". The 1 is an

initget bitcode and it means that a null response is not allowed. See the section below for
more details.

Tip: Just as in native AutoCAD commands, any valid option keyword can be entered simply by
typing the upper case part of the keyword. So, in the example above, to answer Yes to the
prompt, you need only type "y" but to answer NO, you must type "no". This is used to avoid
potential ambiguities when 2 or more options begin with the same letter.

9. (getvar "FILLETRAD") Would return the set value of the FILLETRAD system variable

(fillet radius) eg : 0. 5

10. (getorient "\nWhat is the angle? :") Pick two points for the angle or type an

angle and AutoLisp will return an angle in radians relative to 0 degrees at East.

Initget Bit Codes


The number 1 after the initget function in code example 8, above is known as an initget bit code.
Initget bit codes can be used to control what type of inputs are allowed. In this example, 1 is
used to disallow a null input. This forces the user to enter one of the specified option
keywords rather than just hitting carriage return.

Initget Bit Codes

1 Disallow null input.

2 Disallow zero values.

4 Disallow negative values.

8 DO not check limits, even if LIMECHECK is on.

16 Return 3D points rather than 2D points.

32 Use dashed lines when drawing rubber band or box.


Example:

(initget (+ 1 2 4))
(getint "\nHow old are you?:")

Will only accept a positive, non-zero Integer eg: 21

Setq Command
Short for (Set Equal) or make one thing equal to another.

(setq) is an assignment command, eg : it assigns the value of one variable or constant to another
variable.

Note: (setq) is the primary assignment command in AutoLisp. The "=" (equals character) is not used
as an assignment in AutoLisp. The equals character is used, but only as a non assignment statement.
It does not have the ability to make one variable equal to another as it does in some other
programming languages (it is used for a comparison of variables, numbers or strings).

(setq a b)
This statement assigns the value of b to the variable a so that a becomes the same as b and b is

unchanged.

Note: The first variable after the (setq) is the one that receives the value. Watch out for this because it
is a potential cause of confusion.

Print Commands
Prompt

(prompt "Maybe you need a rest")

This command is used simply to print a message on the command line. A line feed (\n) is not included

so two consecutive prompt commands will print both messages on the same line and without any
spaces between them. Therefore, any printing after the prompt must be preceeded by
the (terpri) function or \n.

Terpri

This is a line feed that causes the next printed text to appear on the next line. It generally follows the
prompt command. eg:
(prompt "Hello, how are you?")(terpri)

or
(prompt "\nHello, how are you?")

Prin1

This function prints the expression on the screen and returns the expression. It can be any expression
and need not only be a string. The expression can also be written to a file and will appear in the file
exactly as it would on the screen.

(prin1 "Hello") would print "Hello".

(prin1 a) would print the value of variable a.

(prin1 a f) would print the value of variable a to an open file named in variable f.

Princ

Is the same as prin1 except that the control characters ("") are not printed. Can also be used to print a
blank line by using no statement after princ.

(princ "Hello") would print Hello.

Print

Same as prin1 except that a new line is printed before the expression and a space is printed after the
expression.

Setvar
This function sets an AutoCAD system variable to a given value and returns that value. The variable
name must be in double quotes. eg:

(setvar "blipmode" 0) returns 0 and will switch blipmode off. 1 would switch it on again.

Doing Arithmetic
AutoLisp provides a number of arithmetic functions and although the format of these functions is
consistent with other AutoLisp functions (function first, followed by values), it is not one we are familiar
with from school. The important thing to remember is that the order of the values is consistent with
what we already know. In other words (/ 27 3) is the same as 27 divided by 3.

(+ 1 1) returns 2.

(­ 2 1) returns 1.
(* 2 2) returns 4.

(/ 2 1) returns 2.

(1+ 1) returns 2 (Incremented).

(1­ 2) returns 1 (Decremented).

Polar
This function returns the point at an angle (in radians) and distance from a given point.

(polar pnt1 ang1 dist1) where pnt1, ang1 and dist1 are 3 previously assigned variables.

Inters
Examines two lines and returns the point where they intersect even if they do not physically cross one
another.

(inters pnt1 pnt2 pnt3 pnt4) where pnt1 and pnt2 are the end points of one line and pnt3

and pnt4 are the end points of another.

AutoCAD commands in AutoLISP


Any AutoCAD command can be used inside your lisp program BUT one must remember that they
have to be used exactly as you would in AutoCAD and your RETURN is a double set of Quotes ("").
eg:

(command "line" pnt1 pnt2 "") draws a line from pnt1 to pnt2 and the "" acts as a return to

terminate the command.

Not all commands require termination since some, like circle are self terminating.

(command "circle" cen cir) where cen is the centre of the circle and cir is a point on the

circumference.

You can try this out using some values at the command prompt to see how this works:

(command "circle" "100,100" "150,150")

Note: values in expressions must be enclosed in quotes whereas variable names are not.

The following code will draw a square using a polyline, specifying 4 points and then C to close:

(command "pline" "50,50" "50,70" "70,70" "70,50" "c")
Elements from a List
When you used (setq a (getpoint)) you assigned the X and Y coordinate numbers to
variable a. That Variable now is a list that may look like (5 10). If you want to look at the list in
variable a, AutoLISP gives you a convenient way to do that from the command line.

!a Placing the ! (exclamation mark character) in front of the variable will display the value or values of

that variable.

Car (X co-ordinate or 1st element)


The primary command for taking a list apart, (car) gives you the first element of a list. If the value of
variable a is the list (5 10), then:

(setq b (car a)) would assign to the variable b the value of the first element in a which is 5.

Cdr (second and remaining elements)


This is the secondary command for taking a list apart. (cdr) gives you the second and remaining
elements of the list, in other words; everything after the first element. If the value of variable a is the

list (2 5 7 9 11), then:

(setq b (cdr a)) would assign to variable b the second and remaining elements of the list in
variable a which is (5 7 9 11).

Cadr (Y co-ordinate or 2nd element)


This always produces the second element of a list. Assuming the value of variable a is the list (5 10),

then:

(setq b (cadr a)) would give b the value 10.

Caddr (Z co-ordinate or 3rd element)


This always produces the third element of a list. Assuming the value of variable a is the list (3 7

5) then:

(setq c (caddr a)) would assign the value 5 to variable c.

Example Programs
Drawing things
This program draws a rectangle by pointing to two points

(defun c:retan (/ pl p2 p3 p4)
(setq pl (getpoint "\nfirst corner of rectangle: "))
(setq p3 (getcorner "\nsecond corner of rectangle: "))
(setq p2 (list (car pl)(cadr p3)))
(setq p4 (list (car p3)(cadr pl)))
(command "line" pl p2 p3 p4 "c")
(princ)
)

Converting data
(dtr) converts degrees to radians

(defun dtr (a)

(* pi (/ a 180)) )

(rtd) converts radians to degrees

(defun rtd (a)

(/ (* a 180) pi)

Things to strings
strcase (string case)

Changes a string of text from lower case to upper case, leaving upper case characters as they are. eg:

(strcase "Hello") returns "HELLO"

(strcase a) returns the alphabetic characters in variable a from lower case to upper case.

strcat (string cat)

Returns two or more separate strings as one. eg:

(strcat "H" "ello") returns "Hello"

(strcat a b) returns two strings in variable a & b as one.

strlen (string length)
Returns the length, of the characters of a string. eg:

(strlen "hello") returns 5.

(strlen a) returns the length of a string in variable a.

substr (substitute string)

Returns a part of a string, from a specified position, ending either at the end or another specified
position. eg:

(substr "Hello 2) returns "ello".

(substr "Hello 2 1) returns "e".

(substr "Hello" 3 2) returns "ll"

List Manipulation
The apostrophe character, ' serves a special function in AutoLISP. For example, if a group of items is

preceded by an apostrophe, it is treated as a list. eg:

'(20 10 5) is treated as a list.

Angle
Returns an angle between two points in radians. To use that angle in AutoCAD you have to convert it
back to decimal degrees. eg: (setq a (angle pnt1 pnt2)) sets the angle
between pnt1 and pnt2 to the variable a.

To use a:

(command "text" pnt1 "40" a t) The text command with a height of 40, rotation angle


assigned to variable a and a text string to variable t. But a is not the correct rotation angle because it

is in radians.

Append
Takes any number of specified lists and joins them together as one list. eg:

(append '(10 20) '(30 40)) returns the list: (10 20 30 40).

(append a b) returns the list in variable a and the list in variable b as one.
Distance
Measures the distance from two known points. eg:

(setq dist1 (distance pnt1 pnt2)) returns the distance between pnt1 and pnt2 and


assigns the distance to a variable called dist1.

Length
Returns the number of elements in a list. eg:

(length '(a b c d)) returns 4.

Member
Looks for a match and returns that and the rest of the list eg:

(member 'c '(a b c d e)) returns (c d e).

Nth
Returns the nth element in a list, where n is the number of the element to return. (Zero is the first
element). eg:

(nth 3 '(a b c d)) returns d.

Assoc (associative)
Often used with the (subst) function; the (assoc) function lets you search for a specific element,

then assign that element to a variable.

Lets assume variable b is the list ((10 5.5 2.7)(40 5)) and you are looking for a value 40. You want to
pull out the entire element and assign it to a variable c. eg:

(setq c (assoc 40 b))

This assigns the entire element containing the 40 in the list b to variable c. Now c is a list that looks

like this: (40 5).

Subst (subsitute)
Allows you to substitute one aspect for another. When substituting ALWAYS substitute the new item for
the old in the list. Now lets substitute 20 for the 5 in the variable c.

(setq b1 (subst '(40 20) c b))
Now b1 is the new list.

'(40 20) is the new element substituted for the old element (40 5) c, found in list b.

If you want to use a variable which represents the value…

(setq bl (subst '(40 h) c b)) … looks like it should work, but it does not. The new element

will look like this: (40 h).

(subst) cannot interpret variables. You need to construct a new variable containing the entire list
element, then use the new variable in the (subst)function.

Cons (construct)
Constructs a new list with the new element placed at the begining. Assume variable c contains the
following list: (40 5). Also, assume variable h contains the real number 20.0 then:

(setq d (cons (car c) h)) Remember, (car c) gives you 40. Therefore, (car c) is the new
first element, followed by the value of h. Thus it produces a new list d (40 20.0).

Now we substitute:

(setq b1 (subst d c b)) That substitutes the new element found in variable d for the old
element found in variable c. (In the list found in variable b) and assigns the new list to b1.

Conversions
Angtos (angle to string)
Takes an angle in radians and converts it into a string, using a specific format. Angtos has two
arguments, the first controls the format and the second controls the precision.

Angtos Mode Format

0 Degrees

1 Degrees/minutes/seconds

2 Grads

3 Radians

4 Surveyor's units

Assuming variable a has an angle in radians. eg:


(angtos a 0 4) returns "180.0000" where 0 is the format (degrees) and 4 is the precision, in this

case, 4 decimal places.


(angtos a 0 0) returns "180"
(angtos a 1 4) returns "180d0"0""

Fix
This function returns the convertion of a real number to an integer and drops the remainder. eg:

(fix 8) returns 8
(fix 8.6) returns 8

Float
This function returns the convertion of an integer to a real number. (One can use either real or an
integer.) eg:

(float 8) returns 8.0000


(float 8.6) returns 8.6000

Ascii
Returns the convertion of the first character of a string into its ASCII character code. (an integer) eg:

(ascii "a") returns 97
(ascii "A") returns 65, upper and lower case characters have different ascii character codes.
(ascii "BLUE") returns 66
(ascii "BALL") returns 66, only the first character is evaluated.

Chr
Returns the convertion of an Integer representing an ASCII character code into a single character
string. eg:

(chr 65) returns "A"


(chr 66) returns "B"

Atof (ascii to float)


Returns the convertion of a string into a real number. eg:

(atof "9.3") returns 9.3000


(atof "2") returns 2.0000
Rtos (real to string)
Returns the convertion of a real number to a string with a specified format.

Rtos Mode Format

1 Scientific

2 Decimal

3 Engineering (feet & decimal inches)

4 Architectural (feet & fractional inches)

5 Arbituary fractional units

The real number can be set according to mode and precision. eg:

(rtos 7.2 1 4) returns "7.200OE+00"


(rtos 7.2 2 2) returns "7.20"

Itoa (integer to ascii)


Returns the convertion of an integer into a string. eg:

(itoa 25) returns "25"

Atoi (ascii to integer)


Returns the convention of a string into an integer. eg:

(atoi "25") returns 25

Conditionals
In AutoLisp, the equals character (=) is not an assignment function. In other words, it is not used to

assign a value to a variable as it is in some other programming languages. AutoLisp uses


the (setq) function to perform this task. In AutoLisp, the equals character is used to test if items are

equal, it does not make them equal. This is very useful if we are trying to test certain conditions. For
example, we can begin to construct tests with an outcome such as "if one thing is equal to another
thing, do something". That's what conditionals are all about; they allow your program to make
decisions.
If
(if) is the standard if-then-else statement. In AutoLISP you may only match one if statement with a

then statement. eg:

(if (= a b) (setq b 5 (setq b 6))

If a is equal to b, then b will be assigned the value 5. If it is not, then b will be assigned the value 6.

Cond (conditional)
This function accepts any number of lists as arguments. It evaluates the first item in each list (in order
supplied) until one of these items is a value other than nil. eg: A user's response string is variable s.

(cond
  ((= s "Y") 1)
  ((= s "y") 1)
  ((= s "N") 0)
  ((= s "n") 0)
  (t nil)
)

This function tests the response and returns 1 if it is "Y" or "y", and 0 if it is "N" or "n",
and nil otherwise.

Repeat
Similar to a loop but repeat will only go through the commands as many times as is told. eg:

(setq a 10)
(setq b 100)
(repeat 3
  (setq a (+ a 10))
)
(setq b (+ b a))
)

Returns 140.
While
Is another loop control command available in AutoLISP. A loop is necessary if you want to repeat a
command. However, unless you have a way of controlling it, the program will run forever and hang you
up. eg:

(setq a "w") Sets up the controlling variable to a value other than nil.


(while a The loop will continue, begining with the commands that follow, until the variable a is set

to nil.
(…some functions…) Are the functions that are performed in the loop.
(if (= c d) (setq a nil)) Evaluates if c is equal to d, and if so, sets the loop controlling
variable a to nil to end the loop.
) A closing parenthesis closes the loop, and program will continue with the commands after this.

Entities
An entity is the smallest object you can place on your screen. The following are entities: LINE,
CIRCLE, ARC, TEXT, POLYLINES, etc. Entities are stored and referenced in the drawing database.
They can be changed and manipulated using AutoLISP to suit your needs. Each entity has a massive
definition in AutoCAD's database. eg: The data for a single line contains the following info:

Entity name, Entity type, Layer, Color, Beginning X Y coordinate, Ending X Y coordinate, Line type,
etc. You can modify any of the above aspects. An example of an entity list:

( ­ 1 <Entity name: 60000014) (0 "CIRCLE") (8 . "LAYER1")

(10 . 50.000 100.000) (40 . 60.000)

It is an entity list of a circle on layer LAYER1, center point relative to 0,0 of 50.0,100.0 , and a radius of
60.0

Entsel and Ssget (select entities and selection sets)


Both give you a way of selecting the entities for the selection set. (entsel) only selects one entity at
a time. You may not use WINDOW or CROSSING to select entities. (ssget) however lets use
WINDOW or CROSSING as well as other selection techniques. You will mostly be using (ssget).

(setq a (ssget)) will prompt you to select objects. You have now created a selection set with a
specific name, <Selection set:l> ,assigned to variable a, or use filter option (setq a (ssget "X" 
'((0 . "TEXT")))) to search database for certain entities or codes.
Ssname (get entity name)
Lets you secure the name of the entity. The name of the entity is realy a hexadecimal number,
therefore don't expect to see a name like LINE, or CIRCLE etc. The name of your entity might be
60000018.

Lets assume variable a is the selection set and variable i is set to 0. (setq i 0) To set Counter
variable. (setq na (ssname a i)). This assigns nathe entity name found in the selection set a at
index number i. Remember that a selection set may contain more than one entity name. You can

point to each entity by using its relative number in the selection set. eg: Entity 1 is Index 0 , Entity 2 is
Index 1 , etc.

Entget (get entity list)


This command actually pulls out, or extracts, the entity list. The entity list can be assigned to a
variable. (setq b (entget na)) That assigns to b the entire entity list for that entity name.

Subst (substitute new for old)


Allows you to substitute one aspect for another. Assume variable b is the name of the list and
variable c contains the value of the element: (40 . 60.0000) (setq bl (subst '(40 . 
30.0000) c b)) ;bl is now the new list. '(40 . 30.0000) is the new element substituted for the
old element c found in list b.

Sslength
Gives you the length or number of selections made.

Entmod (entity modification)


Gives you the ability to take the newly modified entity list and write it back to the database to update
the drawing. Now that you have a new list in the variable b1, you want to make bl the permanent list
in your drawing database. (entmod bl) You should see the change appear on the screen.

More Examples
Change Cross Hair Angle
This program permits you to draw lines perpendicular to other lines. The program measures the angle
of the line chosen, and shifts the SNAP ANGLE to the angle of that line. Use ORTHO ON and draw
perpendicular to your chosen line.
(defun c:perpdon (/ a b pntl pnt2 angl) (graphscr)
(setq a (entsel))
(setq b (entget (car a)))
(setq pntl (cdr (assoc 10 b)))
(setq pnt2 (cdr (assoc 11 b)))
(setq angl (angle pntl pnt2))
(setvar "snapang" ang1)
(princ)
)

(defun c:perpdoff (setvar "snapang" 0)
(princ)
)

Erase Screen
Erases everything on the drawing screen. If you are in a ZOOM ALL position, the program erases
everything within the limits of the drawing.

Note: if you accidentally invoke this command, you can recover with OOPS.

(defun c:erasescr (/ l u)
(setq l (getvar "limmin"))
(setq u (getvar "limmax"))
(command "erase" "w" l u "")
(princ)
)

Change Layer
Lets you select objects by any selection method and change their layer. The target layer is chosen by
simply pointing to an object on the desired layer. All objects selected will then change to that target
layer. To test this program, you will need to create a drawing with objects on different layers.

(defun c:chlayer (/ a1 a2 n index b1 b2 d1 d2 b3)
(graphscr)
(prompt "\nselect entities to be changed: ")
(setq a1 (ssget))
(prompt "\npoint to entity on target layer: ")
(setq a2 (entsel))
(setq n (sslength a1))
(setq index 0)
(setq b2 (entget (car a2)))
(setq d2 (assoc 8 b2))
(repeat n
(setq b1 (entget (ssname a1 index)))
(setq d1 (assoc 8 b1))
(setq b3 (subst d2 d1 b1))
(entmod b3)
(setq index (+ index 1))
)
(princ)
)

Now let's examine the program line by line.

(defun c:chlayer (/ a1 a2 n index b1 b2 d1 d2 b3)

Defines the function with all local variables.

(graphscr)

Changes to graphics screen.

(prompt "\nSelect entities to be changed: ")

This is a prompt statement.

(setq a1 (ssget))

Allows you to select the objects to be changed. The selection set is assigned to variable al.

(prompt "\npoint to entity on target layer: ")

This is a prompt statement.

(setq a2 (entsel))

This is a special type of selection statement that allows you to select only one entity.

(setq n (sslength a1))

Measures the number of entities in the selection set in variable a1.


(setq index 0)

Sets the variable called index to 0.

(setq b2 (entget (car a2)))

This statement gets the entity list from a2. Thus, a2 is assigned the entity list.

(setq d2 (assoc 8 b2))

This looks for the code 8 in entity list a2, then assigns the sublist to d2.

(repeat n

This begins the loop that pages through the selection set.

(setq bl (entget (ssname a1 index)))

This gets the entity list and assigns it to b1.

(setq d1 (assoc 8 b1))

Gets the sublist code 8 (the layer).

(setq b3 (subst d2 d1 b1))

Substitutes the new d2 layer for the old d1 layer in the entity list a1, and assigns it to the new entity
list b3.

(entmod b3)

Updates the new entity list in the database.

(setq index (+ index 1))

Increases the index variable by 1, making it ready for the next loop. The first ) closes the repeat
loop. (princ) exits quietly. The second ) closes the function.

Substitute text
This program lets you choose a line of text and substitute another line at exactly the same place.

(defun c:subtext (/ a b d e d1 b1 y)
(prompt "\nSelect text line: ")
(setq a (entsel))
(setq b (entget (car a)))
(setq d (assoc 1 b))
(prompt (cdr d))(terpri)
(setq e (getstring 1))
(setq d1 (cons (car d) e))
(setq b1 (subst d1 d b))
(entmod b1)
(setq y (getstring "\nIs this correct ­ Y : "))
(if (= (srtcase y) "N") (entmod b))
(princ)
)

Text - Own Distance, Own Height


This program lets you change the distance between multiple text lines. In addition to the standard start
point and height, you are asked to enter the distance between text lines. You may enter as many text
lines as you wish. To stop the program, enter an asterix (*).

(defun tex (/ p1 a b c d e f)
(setq pl (getpoint "\nStarting point: "))
(setq a (getdist p1 "\nEnter height: "))
(setq c (getdist p1 "\nline spacing: "))
(setq d "T")
(while d
(setq e (getstring 1 "Text: "))
(command "text" pl a "0" e)
(setq pl (list (car p1)(­ (cadr p1) c)))
(setq f (getstring))
(if (= f "*")(setq d nil))
)
(princ)
)

Global Text Height Change


This program allows you to globally change the size of text within a WINDOW or CROSSING without
affecting other entities.

(defun chtext (/ a ts n index b1 b c d b2)
(setq a (ssget))
(setq ts (getreal "\nEnter new text size"))
(setq n (sslength a))
(setq index 0)
(repeat n
(setq b1 (entget (ssname a index)))
(setq index (1+ index))
(setq b (assoc 0 b1))
(if (= "TEXT" (cdr b))
(progn
(setq c (assoc 40 b1))
(setq d (cons (car c) ts))
(setq b2 (subst d c b1))
(entmod b2))))
(princ)
)
Topic này được mở để thảo luận và chia sẽ những kinh nghiệm sử dụng trình
soạn Visual LISP Editor với các bạn mới bắt đầu và những ai có nhu cầu. Chúng
tôi chân thành đón nhận những hướng dẫn; góp ý và các câu hỏi, vướng mắc
được đặt ra trong quá trình sử dụng VLIDE, từ đó anh em thảo luận để có hướng
giải quyết vấn đề, ngỏ hầu phục vụ anh em được tốt hơn. Chúng tôi không mong
đợi những comment không mang tính đóng gốp; ly khai và cực đoan, xin lỗi vì
chúng tôi chưa được rèn luyện công phu "né đá". Chân thành cám ơn sự quan
tâm và mong chờ sự chia sẽ, đóng gốp của tất cả các bạn trong diễn đàn. Cầu
chúc niềm vui; sức khỏe và thành công cho các bạn!

Sơ lược về Visual LISP Editor

Một chương trình AutoLISP có thể được viết bằng bất cứ chương trình soạn thảo
văn bản nào (Notepad; WordPad; MS.Word; Notepad++), sau đó lưu lại với đuôi
*.LSP. Tuy nhiên, với các trình soạn thảo này, chúng ta chỉ thuần túy vi ết code
mà không hề được hỗ trợ các công cụ để có thể chạy thử, tìm lỗi và gỡ lỗi.
AutoCAD chính nó đã cung cấp một trình soạn thảo Visual LISP, thỏa mãn được
các đòi hỏi trên.

Chân thành cám ơn các bạn đã tham gia thảo luận trong
topic: Gia_Bach; Tue_NV; Doan Van Ha; Song Nhi : ndtnv ;

Mục lục tổng kết một số tiện ích của Visual LISP Editor đã được thảo luận trong
topic

1/- Kiểm tra và gỡ lỗi code, tham khảo tại: [#6] và [#49].

2/- Giải phóng bộ nhớ bằng cách chuyển danh sách biến toàn cục thành biến cục
bộ, tham khảo tại: [#19]; [#21]; [#22] và [#50].

3/- Quản lý lisp bằng tiện ích Project, tham khảo tại: [#20] và [#24].

4/- Chức năng AutoComplex, tham khảo tại: [#26].

5/- Định dạng code, tham khảo tại: [#30].

6/- Xem cú pháp hàm trực tiếp trong VLIDE, tham khảo tại: [#38].

7/- Xem trước giao diện DCL, tham khảo tại: [#40].

8/- Đóng gói ứng dụng, tham khảo tại: [#43].

9/- Và các tiện ích khác, đang chờ các bạn bổ xung ...

Similar topics from web:


Chapters 3, 4 and 5. Using AutoLISP/Visual LISP functions
Autodesk
Chapters 1 and 2. Introduction to AutoLISP/Visual LISP
Can anyone explain the design decisions behind Autolisp/visual lisp ...
Visual Lisp: how to call functions in external C++ DLL
AutoLISP: Select block by name | AutoCAD Tips
Beginning Visual LISP


Báo cáo bài đăng

Đã đăng Tháng 5 13, 2013


Dẫn nhập

Topic này được mở để thảo luận và chia sẽ những kinh nghiệm sử dụng trình
soạn Visual LISP Editor với các bạn mới bắt đầu và những ai có nhu cầu. Chúng
tôi chân thành đón nhận những hướng dẫn; góp ý và các câu hỏi, vướng mắc
được đặt ra trong quá trình sử dụng VLIDE, từ đó anh em thảo luận để có hướng
giải quyết vấn đề, ngỏ hầu phục vụ anh em được tốt hơn. Chúng tôi không mong
đợi những comment không mang tính đóng gốp; ly khai và cực đoan, xin lỗi vì
chúng tôi chưa được rèn luyện công phu "né đá". Chân thành cám ơn sự quan
tâm và mong chờ sự chia sẽ, đóng gốp của tất cả các bạn trong diễn đàn. Cầu
chúc niềm vui; sức khỏe và thành công cho các bạn!

Sơ lược về Visual LISP Editor

Một chương trình AutoLISP có thể được viết bằng bất cứ chương trình soạn thảo
văn bản nào (Notepad; WordPad; MS.Word; Notepad++), sau đó lưu lại với đuôi
*.LSP. Tuy nhiên, với các trình soạn thảo này, chúng ta chỉ thuần túy vi ết code
mà không hề được hỗ trợ các công cụ để có thể chạy thử, tìm lỗi và gỡ lỗi.
AutoCAD chính nó đã cung cấp một trình soạn thảo Visual LISP, thỏa mãn được
các đòi hỏi trên.

Chân thành cám ơn các bạn đã tham gia thảo luận trong
topic: Gia_Bach; Tue_NV; Doan Van Ha; Song Nhi : ndtnv ;

Mục lục tổng kết một số tiện ích của Visual LISP Editor đã được thảo luận trong
topic

1/- Kiểm tra và gỡ lỗi code, tham khảo tại: [#6] và [#49].

2/- Giải phóng bộ nhớ bằng cách chuyển danh sách biến toàn cục thành biến cục
bộ, tham khảo tại: [#19]; [#21]; [#22] và [#50].

3/- Quản lý lisp bằng tiện ích Project, tham khảo tại: [#20] và [#24].

4/- Chức năng AutoComplex, tham khảo tại: [#26].

5/- Định dạng code, tham khảo tại: [#30].

6/- Xem cú pháp hàm trực tiếp trong VLIDE, tham khảo tại: [#38].
7/- Xem trước giao diện DCL, tham khảo tại: [#40].

8/- Đóng gói ứng dụng, tham khảo tại: [#43].

9/- Và các tiện ích khác, đang chờ các bạn bổ xung ...

Mời các Bác tiếp tục chia sẽ những kinh nghiệm sử dụng Visual LISP Editor!
Similar topics from web:
Chapters 3, 4 and 5. Using AutoLISP/Visual LISP functions
Autodesk
Chapters 1 and 2. Introduction to AutoLISP/Visual LISP
Can anyone explain the design decisions behind Autolisp/visual lisp ...
Visual Lisp: how to call functions in external C++ DLL
AutoLISP: Select block by name | AutoCAD Tips
Beginning Visual LISP

AutoLISP
LISP for AutoCAD
Plain and Simple AutoLISP Routines | Facebook
Help: Lesson 2: Using Visual LISP Debugging Tools (AutoLISP)
Determine in which line of AutoLISP code an error exists
Sử dụng AutoLisp trong AutoCad

Em là người mới bắt đầu học LISP, món này rất cần thiết đây!

@ Bác Thaistreetz ơi, Bác là một trong các cao thủ trong ngành này, bác chia
sẽ những kinh nghiệm của mình để hướng dẫn tụi em với, tựa đề bằng tiếng Anh
thế mọi người cũng hiểu được mà, như Slogen của Bác đấy thôi, cũng toàn tiếng
Anh cả đấy chứ!

Trong bài: [yêu cầu] Lisp vẽ hình chữ nhật ,


line: http://www.cadviet.com/forum/topic/71167-yeu-cau-lisp-ve-hinh-chu-nhat/
Đã có các bác: Duy782006; Tue_NV và bác Doan Van Ha viết giúp bạn ấy rồi, em
thấy vấn đề không phải khó lắm, cũng viết một lisp, nhưng không chạy được, vì
còn sai nhiều chỗ, các Bác chắc đọc code sẽ phát hiện nhiều chỗ sai của em.
Tuy nhiên, em mong muốn các Bác có thể hướng dẫn cách sử dụng các công cụ
của Visual LISP Editor để phát hiện lỗi và sửa lỗi, từ đó những người mới học như tụi
em sẽ rút ra những bài học kinh nghiệm!

Em xin trình bày lại yêu cầu của bạn ấy: Nhập vào 2 điểm và một khoảng offset,
vẽ hình chữ nhật nhận 2 đỉnh ấy làm 2 đỉnh chéo, kết quả là HCN được offset từ
HCN chuẩn ra hay vào trong một khoảng bằng khoảng nhập vào. Code của
em đây:
(defun pxy(d x y) (polar (polar d 0 x) (* 0.5 pi) x))
(defun SN(id / )
(setq D1 (getpoint "\nVui long pick diem Bottom Left\n")
D3 (getcorner D1 "\nVui long pick diem Top Right\n"))
(setq an (getint "\nVui long nhap khoang offset: <110>\n")) (if (= an
nil) (setq an 110))
(setq bn (- 0 an))
(setq D2 (list (car D1) (cadr D3))
D4 (list (car D3) (cadr D1)))
(cond
((= id 1) (setq D11 (pxy D1 bn bn)
D22 (pxy D2 bn an)
D33 (pxy D3 an an)
D44 (pxy D4 an bn))
((= id 2) (setq D11 (pxy D1 an an)
D22 (pxy D2 an bn)
D33 (pxy D3 bn bn)
D44 (pxy D4 bn an)))))
(Command "_pline" D11 D22 D33 D44 "C")
(princ))
(defun C:SN+() (SN 1))
(defun C:SN-() (SN 2))

Song Nhi đọc thêm cái này để tham khảo. Viết bằng Visual lisp hay Notepad++
đều có những ưu/nhược điểm riêng.
Tôi thì mê Notepad++ hơn.
Trong link này các comments còn bỏ sót rất nhiều điều hay của N++, tự tìm hiểu
dần sẽ thấy thôi.
http://www.cadviet.com/forum/topic/5795-dung-chuong-trinh-nao-de-viet-lisp/

1/- Các bạn xem đoạn code mẫu sau


(defun c:test ( / ss i sl total entity elist )
(if (setq ss (ssget '((0 . "LINE"))))
(progn
(setq i -1 sl (sslength ss) total 0)
(while (<= (setq i (1+ i)) sl)
(setq entity (ssname ss i)
elist (entget entity)
total (+ total (distance (cdr (assoc 10 elist)) (cdr
(assoc 11 elist))))))
(princ (strcat "\nTotal Length: " (rtos total)))))
(princ))

Tất nhiên, với kiến thức và kinh nghiệm của các bạn, các bạn có thể đọc và gỡ
lỗi một cách thủ công. Tuy nhiên, trong bài này chúng tôi trình bày cách dùng
công cụ của Visual LISP IDE để xác định vị trí lỗi và gỡ lỗi đó.
Trước tiên, bạn khởi động AutoCAD và nhập lệnh VLIDE (hoặc VLISP) để mở
chương trình Visual LISP IDE, mở một file mới, copy đoạn code mẫu trên vào.
Vẽ một vài line trong CAD để kiểm tra, Trở lại VLIDE load code bằng biểu tượng
load hoặc tổ hợp phím: Ctrl+Alt+E
Chạy thử bằng cách nhập lệnh: TEST tại command line, chúng ta sẽ nhận được
thông báo lỗi như sau:
; error: bad argument type: lentityp nil
Và trở lại VLIDE, kiểm tra: Debug » Break on Error tùy chọn này đã được check,
nghĩa là VLIDE đã đặt một điểm break tại vị trí lỗi.

2/- Xác định vị trí lỗi


Để xác định vị trí lỗi, ta vào: Debug » Last Break Source (hoặc tổ hợp phím:
Ctrl+F9)

Reset lại điểm break bằng cách: Debug » Reset to Top Level (hoặc tổ hợp phím:
Ctrl+R). Vậy chúng ta đã xác định được vị trí lỗi, nhưng còn phải xác định vì sao
lỗi tại đó nữa?!!

3/- Xác định nguyên nhân lỗi


Để giúp trả lời câu hỏi này, VLIDE có một vài công cụ khác mà chúng ta có thể
sử dụng.

3.1/- Adding Break Points: Ta chèn thêm những điểm break để kiểm soát từng
đoạn code nhỏ. Trong trường hợp này lỗi xảy ra trong vòng lặp (while, cách
chèn: Đặt nháy tại vị trí chèn và Debug » Toggle Break Point (hoặc nhấn phím:
F9)

3.2/- Watching Variables: VLIDE cũng cho phép chúng ta theo dõi biến được sử
dụng trong các code, hiển thị giá trị của nó và giá trị của những biến liên đới với
nó. Double-click vào một biến nào đó và View » Watch Window (hoặc tổ hợp
phím: Ctrl+Shift+W) để xem giá trị, theo dõi thêm một biến liên đới với nó bằng
cách tô chọn biến đó và Debug » Add Watch (hoặc nhấn phím: Ctrl+W). Trong
trường hợp này ta chọn 2 biến “i” và “entity”.

3.3/- Animating the Code: Trong CAD, chạy thử đoạn code một lần nữa, chúng ta
nhập: TEST tại command line. Sau khi trở lại VLIDE chúng ta
vào Debug » Animate và đánh dấu tùy chọn này check. Sau đó
vào Debug » Continue (hoặc chọn biểu tượng mũi tên xanh trên thanh Debug,
hoặc tổ hợp phím Ctrl+F8)

Các giá trị của các biến trong cửa sổ Watch giúp chúng ta điều tra được nguyên
nhân lỗi. Trong trường hợp này, giá trị của “entity → nil” khi “i → 3”, điều này cho
thấy với i=3 đã thoát khỏi điều kiện kiểm tra của vòng lặp, do đó “entity → nil”.
Reset lại điểm break bằng cách: Debug » Reset to Top Level (hoặc tổ hợp phím:
Ctrl+R) và xóa tất cả các điểm break bằng cách Debug » Clear all Break
Points (hoặc tổ hợp phím Ctrl+Shift+F9). Sau đó vào Debug » Animate và hủy
đánh dấu tùy chọn này uncheck.

4/- Sửa lỗi


Với thiết định ban đầu i=-1, vậy nó điều kiện vòng lặp sẽ được thực thi đến khi
i=(sl-1) thì dừng và thoát ra, như vậy ta có thể sửa lại code như sau:
(defun c:test ( / ss i sl total entity elist )
(if (setq ss (ssget '((0 . "LINE"))))
(progn
(setq i -1 sl (sslength ss) total 0)
(while (< (setq i (1+ i)) sl) ;;; “<=” da duoc thay bang
“<” ;;;
(setq entity (ssname ss i)
elist (entget entity)
total (+ total (distance (cdr (assoc 10 elist)) (cdr
(assoc 11 elist))))))
(princ (strcat "\nTotal Length: " (rtos total)))))
(princ))
Đó chỉ là một cách, tùy bạn có thể sửa bằng cách khác, vd: thiết định ban đầu
cho i=0 chẳng hạn…

5/- Tham khảo thêm tài liệu trợ giúp của VLIDE
Các bác so sánh nhiều e e khập khiễng. Có đến mấy topic bàn về cái ni r ồi
- Về các tiện ích về cách thức sử dụng, trình bày ... N++ chắc chắn sẽ có thể ăn
đứt VL, đơn giản là vì N++ code mở, các bác thấy thiếu cái j thì xắn tay lên vi ết
cho nó. Từ khóa thiếu thì thêm, k nhận in hoa thì xử, màu mè chán thì chỉnh ...
nói chung là thiên biến vạn hóa, plug addin vô số ...
- Về các chức năng liên quan đến chất lượng sản phẩm, check hàng, đì búc đì
biếc các thứ thì vl chuyên về nó rồi, cãi j

Em thì viết = N++, sửa lỗi mò, nhưng vote dùng cả 2, mở file = N++ và VL cùng
lúc, qua lại chớp nhoáng, xuất chiêu nhẹ nhàng mà khí lực vô biên

@TL : bác Thái đường cũng hứa viết giúp mình cái tut đó, rồi mất hút ^^. Bạn làm
cùng chỗ a Thái ?
Quản lý LISP bằng Project
Vừa tiện dụng cho Autoload, vừa tiện dụng cho Find trong VLIDE rất hiệu quả,
ứng dụng cho việc test LISP bằng một project: Vault thì thật mau chóng!
@ Bác Gia_Bach: Cám ơn Bác! Bác hướng dẫn bằng hình ảnh thật cụ thể và dễ
hiểu, tuy nhiên, Bác đã để lại một vài “sơ xuất” lyky đã đánh dấu trên hình này
nè! Lyky đã nhận ra Bác rồi?!

Một lần nữa xin cám ơn Bác đã quan tâm đến vấn đề và nhiệt tình hướng dẫn anh
em! Chúc Bác thật nhiều SK và nhiều thật nhiều thành công trong công vi ệc n ữa
nhé!

@ ThuyLinh: Tiếp thu ý kiến, hôm sau nhất định không ghi tiếng Anh nữa!
Đã đăng Tháng 5 16, 2013
Vào lúc 16/5/2013 tại 17:21, Doan Van Ha đã nói:
[CHECKING TEXT <Untitled-0> loading...]
.
; Check done.

Bác thử làm thế này xem sao: Tools >> Environment Options >> General
Options ---> Check buttom đầu tiên, như hình vẽ sau là okei!
Ý nghĩa các buttom khác tham khảo tại: Diagnostic Tab (General Options
Dialog Box)/Help
Chúc các bạn buổi tối thật vui!

Bác thử làm thế này xem sao: Tools >> Environment Options >> General
Options ---> Check buttom đầu tiên, như hình vẽ sau là okei!
Ý nghĩa các buttom khác tham khảo tại: Diagnostic Tab (General Options
Dialog Box)/Help
Nếu sửa như trên mà vẫn không xuất hiện Global variables, bạn vui lòng kiểm
tra trang sau:
Chúc các bạn buổi tối thật vui!
Hề hề hề.
Bác này có nhẽ phải đổi nick thành Song ..... Phi mất thôi. Chơi nhiều cước độc
quá. Cánh đi mót như tui thiệt khó đỡ.
Hề hề hề,
Cám ơn bác Song .....(phi) Nhi vì qua các chiêu của bác t ụi này mót đ ược thêm
mấy miếng phòng thân và tránh đòn khi đi mót trên đồng lạ bác ạ....
Hề hề hề,....
Khi bạn mở một Project, VLISP sẽ hiển thị một cửa sổ liệt kê các Lisp trong
Project đó:

Mặc định, VLISP liệt kê các Lisp theo thứ tự các bạn đã nạp nó vào Project,
hoặc bạn có thể vào Project Properties để thay đổi thứ tự này theo ý bạn.

Bên dưới thanh tiêu đề là 5 biểu tượng. Liệt kê như sau:


1. Project Properties: Hộp thoại này cho phép bạn xem đường dẫn của mỗi Lisp,
nạp thêm, loại ra, sắp xếp lại các Lisp, xem và thay đổi tùy chọn trình biên dịch
Compolation Mode.
2. Load Project FAS

3. Load Source Files


4. Build Project FAS
5. Rebuild Project FAS
Nếu bạn kích chuột phải vào một Lisp nào đó trong danh sách, VLISP hiển thị
một menu ngữ cảnh chứa một số chức năng. Ví dụ, bạn đã biết cách để nạp/loại
Lisp vào/ra các Project. Remove File nhanh chóng loại bỏ một Lisp, nhưng Add
File chỉ đơn thuần hiển thị hộp thoại Project Properties.
Tóm tắt các lệnh trên menu ngữ cảnh:

1. Edit: Chỉnh sửa Lisp được lựa chọn.


2. Add File: Mở hộp thoại Project Properties để nạp thêm Lisp vào.
3. Remove File: Loại bỏ các Lisp được chọn ra khỏi Project.
4. Load: Tải FAS cho các Lisp được lựa chọn. Nếu không có file FAS, tải file
nguồn AutoLISP.
5. Load Source: Tải file nguồn AutoLISP.
6. Check Syntax: Kiểm tra cú pháp của Lisp được lựa chọn.
7. V.v…

Các bạn nghiên cứu thêm ở: Using the Project Window to Work with Project
Files

P/S:
@ Song Nhi: Hảo Song Nhi! Đối với những Lisp đã check rồi và "dọn rác" theo
cách anh Gia_Bach đã hướng dẫn, sau khi check lại sẽ không còn Global Var, trừ
trường hợp vì ý đồ khác của người viết!

@ Phamthanhbinh: Cám ơn bác đã quan tâm đến vấn đề, mong chờ sự hướng dẫn
từ Bác - Chúc Bác thật nhiều sức khoẻ nhé! Ah, Song Nhi (trong Lộc đỉnh ký) thì
giỏi môn điểm huyệt chứ Bác, con gái ai người ta đi phi cước - mốt nữa ế chồng
chết! ^-^
Tue_NV còn hay thường dùng chức năng AutoComplex của VL (Có thể là các
hàm của Lisp hoặc khi đã Load Project thì có thể sử dụng bộ hàm con do mình
viết sẵn trong Project để coding nhanh chóng
Đơn giản viết vài chữ rồi Control+Shift+Spacebar
Vào lúc 17/5/2013 tại 14:34, Tue_NV đã nói:
Tue_NV còn hay thường dùng chức năng AutoComplex của VL (Có thể là các
hàm của Lisp hoặc khi đã Load Project thì có thể sử dụng bộ hàm con do mình
viết sẵn trong Project để coding nhanh chóng
Đơn giản viết vài chữ rồi Control+Shift+Spacebar
Xin hỏi anh Tuệ một chút, khi dùng Apropos (Control+Shift+Spacebar) thì phải
nhấp chột phải vào hàm rồi copy to clipboard rồi lại paste hay sao. Nếu như vậy
thì bất tiện hơn nhiều so với Backup/Auto-completion của N++.

Nó tùy thuộc vào mức độ hoàn thiện của từ khóa gợi ý của bạn.
Chức năng này không chỉ có tác dụng với hàm mà còn có tác dụng với cả bi ến
trong cửa sổ soạn thảo. Với các hàm và biến đã sử dụng trong cửa sổ soạn thảo
thì bạn chỉ cần nhấn tổ hợp Ctrl_space, nếu từ khóa gợi ý đến nhiều hàm hoặc
biến thì cứ nhấn thêm 1 vài lần đến khi ra được hàm hoặc biến cần vi ết.

Xin hỏi anh Tuệ một chút, khi dùng Apropos (Control+Shift+Spacebar) thì phải
nhấp chột phải vào hàm rồi copy to clipboard rồi lại paste hay sao. Nếu như vậy
thì bất tiện hơn nhiều so với Backup/Auto-completion của N++.

AutoComplete : Nó cũng giống như N++. Khi bạn đã có bộ hàm con trong
Project. Bạn bấm nút Load nó lên và sử dụng từ khoá gợi ý là nó Complete cho
mình. Nhưng ưu điểm hơn N++, vì N++ có thể bạn phải viết thêm các hàm để
Complex, nhưng với VL thì tất cả hàm con được load, tất cả các hàm Lisp đã có
thể Complete được rồi. Không phải copy paste đâu bạn
Mặc dù, đây chỉ là một vấn đề rất nhỏ, em cũng xin được trình bày, nhằm
mục đích phục vụ cho các bạn mới bắt đầu như em! Vấn đề Visual LISP Code
Formatting
VLISP có thể phân loại được các thành phần trong code và gán cho m ỗi lo ại đó
một màu sắc (có thể hiểu chỉnh lại theo thị hiếu cá nhân). Điều này, giúp cho
chúng ta có thể trực quan phát hiện một điều bất thường nhỏ nào đó, ví dụ đơn
giản, nếu bỏ lỡ một dấu " (quotes) thì phần code tiếp theo sau sẽ hiển thị bằng
một màu hồng (theo mặc định màu text string là màu hồng - bạn có thể hiệu
chỉnh thành màu khác). Hoặc, nếu bạn viết chưa đúng tên hàm, tên hàm sẽ
không chuyển sang màu xanh (Blue), giúp bạn nhận biết và sửa lại...

Một số LISP trong diễn đàn / mục Viết lisp theo yêu cầu, sau khi down về, nó
không còn giữ được format ban đầu mà chỉ đơn thuần nằm trên một dòng, Tuy
nhiên, điều này không hề là "lisp bị lỗi như thế" như các bạn nói, một cách
format đơn giản bằng VLISP, như sau: Tools » Format Code in Editor (Ctrl-Alt-
F) hoặc: Tools » Format Code in Selection (Ctrl-Shift-F). Hoặc chỉ đơn giản là
bạn hãy chọn vào các biểu tượng trên thanh công cụ: TOOLS, mô tả trong hình
sau:

Mặc dù chỉ là một vấn đề rất nhỏ, em cũng hi vọng là nó có thể giúp ích cho một
số ít các bạn mới bắt đầu học LISP giống như em!
Chúc anh chị em trên diễn đàn một ngày cuối tuần thật ý nghĩa và nhiều niềm
vui!

@ lyky: em là men chứ đâu là women đâu, nhầm nhé!


@ Tue_NV & ThuyLinh313: Cảm ơn 2 anh chị đã hướng dẫn một tiện ích thật hay!

Về ý thứ 2 của Song Nhi thì không phải bao giờ cũng có thể format các lisp bị lỗi
nằm trên 1 dòng trở về 1 lisp đúng.
Điều này chỉ làm được khi trong dòng đó không chứa các string giải thích. VD
đơn giản dưới đây thì không thể format được, mà yêu cầu người format phải hiểu
bản chất code lisp nữa.
(defun HA();Test1 (setq a 1);Test2 (setq b 2))

AutoComplete : Nó cũng giống như N++. Khi bạn đã có bộ hàm con trong
Project. Bạn bấm nút Load nó lên và sử dụng từ khoá gợi ý là nó Complete cho
mình. Nhưng ưu điểm hơn N++, vì N++ có thể bạn phải viết thêm các hàm để
Complex, nhưng với VL thì tất cả hàm con được load, tất cả các hàm Lisp đã có
thể Complete được rồi. Không phải copy paste đâu bạn
Anh Tuệ có thể giải thích một chút(hoặc hướng dẫn cách làm) làm sao VL hiểu
được các hàm mà không cần copy paste không. Thanks.

Làm sao VL hiểu được các hàm mà không cần copy paste không. Thanks.

VLISP sẽ tự động hiểu và gợi ý cho bạn những hàm đã load: " Tuỳ thuộc vào mức
độ hoàn thiện của từ khoá bạn nhập", giống như chức năng Auto-
Correction của điện thoại khi bạn viết tin nhắn vậy đó, đối với tiếng latin thì bạn
có thể tắt chức năng này đi, vì không mấy hiệu quả, đối với tiếng Hoa (nói chung
là Hán tự), chức năng này là mặc định, và ngược lại, nó tỏ ra rất hiệu quả!

Có cần phải copy - paste gì đâu bạn?! Sau khi VLISP hiển thị dãy hàm gợi ý lên,
bạn dùng chuột chọn đúng hàm bạn muốn là được! Thực sự không hiểu bạn nói
copy/paste như thế nào nữa, vì có muốn copy/paste cũng đâu có cách nào làm
được?!! Bạn cứ mở trình Visual LISP Editor lên, vọc thử là sẽ hiểu được mà! Đối
với mọi hàm có sẵn khác, cũng đều ứng dụng được!

@ Doan Van Ha: Cám ơn bác đã nhắt nhở! Khi có chú thích thì sau khi format
xong chúng ta phải làm thủ công lại mới được ạ!
@ duy267: Bác có thể nói cụ thể hơn là bạn đã copy -paste như thế nào không?
ó cần phải copy - paste gì đâu bạn?! Bạn cứ mở trình Visual LISP Editor lên, vọc
thử là sẽ hiểu được mà! Đối với mọi hàm có sẵn khác, cũng đều ứng dụng được!

Mình đã thử nhưng vẫn phải copy-paste. Mình đã làm sai chăng? Ví dụ khi mình
gõ "(get", nhấn Cltr+Shift+Space thì hiện ra một đống hàm bắt đầu bằng "get".
Bây giờ mình muốn chọn hàm "getint" thì phải làm thế nào?
Với N++ thì khi bạn gõ tới đâu nó sẽ hiểu tới đó và bạn có thể dùng phím mũi tên
để chọn hàm rất tiện. Thanks.

Vào lúc 19/5/2013 tại 00:25, duy267 đã nói:


Mình đã thử nhưng vẫn phải copy-paste. Mình đã làm sai chăng? Ví dụ khi mình
gõ "(get", nhấn Cltr+Shift+Space thì hiện ra một đống hàm bắt đầu bằng "get".
Bây giờ mình muốn chọn hàm "getint" thì phải làm thế nào?
Với N++ thì khi bạn gõ tới đâu nó sẽ hiểu tới đó và bạn có thể dùng phím mũi tên
để chọn hàm rất tiện. Thanks.

Có 1 số TH ngoại lệ như hàm get hiện ra hộp thoại Apropos result. Sao bạn
không gợi nhớ thêm từ cho nó để nó hiện ra danh sách xổ xuống như trên hình
vẽ mình post.

- Bạn thử gõ geti rồi Ctrol+Shift+Space


- Bạn thử gõ getc rồi Ctrol+Shift+Space
- Bạn thử gõ ent rồi Ctrol+Shift+Space
- Bạn đã có 1 project hãy thử làm HD của Tue_NV ở bài vi ết trên

Bạn đã xem hình mình post ở bài viết trên thì thấy sau khi bấm chữ -> có 1 danh
sách xổ xuống và chọn thôi (giống N++)
Từ danh sách xổ xuống thì chọn bằng chuột. Nếu hàm đã hoàn chỉnh tất nhiên
sẽ tự complete
VLISP cái này ưu điểm hơn N++ nhiều. Tue_NV dùng các hàm VL, VLA ..... và
các hàm trong bộ project của mình thì coding nhanh, gọn và nhàn hơn r ất
nhiều. N++ dẫu có thêm hàm cho chức năng Complete thì sao đủ bằng VL được?
Trong quá trình coding, nhiều lúc không nhớ chính xác cú pháp c ủa hàm, chúng
ta sẽ làm cách nào?
Đối với MS. Excel; VBA … Sau khi các bạn nhập hàm, sẽ xuất hiện một dòng
nhắc cú pháp, ví dụ:

Đối với Visual LISP IDE, mặc dù không trực quan như vậy, nhưng khi cần thiết –
chúng ta không cần thiết phải phải truy cập một cách gián tiếp – bằng cách vào
Help hoặc vào Internet để tìm kiếm. Một cách trực tiếp là chúng ta tô chọn đối
tượng muốn tìm hiểu, vào Help trên thanh Tools (hoặc tổ hợp phím Ctrl+F1)

Chúc các bạn thật nhiều niềm vui! Mong chờ sự chia sẽ kinh nghiệm sử dụng
trình VLISP của các bạn!

P/S: @ Tue_NV: Cám ơn Bác đã hướng dẫn chúng tôi chức năng AutoComplex,
vote Bác. Xin được hỏi thêm Bác là sau khi chọn, các hàm được in ra dưới dạng
chữ IN HOA, làm sao để sau khi chọn, hàm in ra với dạng chữ thường vậy Bác?
Chúc Bác thật nhiều sức khỏe và thành công trong công vi ệc!
Chuyển qua lại giữa chữ thường và chữ in hoa ở đây:
Ở đây chúng ta không nói về kiến thức để thiết kế một giao diện DCL, chúng ta
chỉ đơn thuần xét đến chức năng xem trước giao diện DCL trong VLISP. Các bạn
có thể tham khảo thêm về DCL: Tại đây

Trước tiên, các bạn copy đoạn code sau, paste vào cửa sổ soạn thảo (Ctrl+N)
của VLISP, lưu lại với tên là: *.DCL

LAYER:dialog {
label="Chuc nang xem truoc DCL";
spacer_1;
:boxed_radio_column{
label="Cai dat Layer";
:radio_button{
label="Su dung Layer hien
huu";

key="IsCuLA";
}
:radio_button{
label="Cai dat Layer";
key="IsSetLA";
}
:popup_list{
key="La";
}
}
ok_cancel;
}
Vào Tools » Interface Tools » Preview DCL in Editor (Preview DCL in Selection) .

VLISP chuyển sang cửa sổ ACAD và hiển thị hộp thoại xem trước như sau:

Chúng ta sử dụng chức năng này để thiết kế hộp thoại DCL, bởi DCL được vi ết
toàn bằng code, trong khi hộp thoại của các ngôn ngữ lập trình hướng đối t ượng
khác, được thiết kế trực quan!
Không cần phải save as. Muốn chuyển đổi định dạng code trong một cửa sổ soạn
thảo chỉ cần vào tool, window attributes, rồi cái gì đó (dòng thứ hai thì phải),
lựa chọn định dạng code muốn đổi

Bác Thaistreetz đang hướng dẫn anh em tiện ích gì của VLISP vậy ạ? Em có làm
theo hướng dẫn trên: Vào Tools / Window Attributes / Configure Current ... (dòng
thứ 2)

Trong cửa sổ này:


1. Cho phép điều chỉnh lại màu sắc hiển thị cho code
2. Transparent foreground
3. Transparent background
4. Sets tab spacing
5. Sets the left margin

Em không hiểu chuyển đổi định dạng code là ntn? Bác Thaistreetz làm ơn giải
thích rõ vấn đề này được không ạ?

Đóng gói một ứng dụng VLX bằng VLISP

Bạn muốn đóng gói một ứng dụng bao gồm LSP và hộp thoại DCL, Visual LISP
có thể giúp bạn điều này qua các bước sau đây:
1. Trong menu file VLISP chọn: Make Application>New Application Wizard.
2. Trong trang đầu tiên: nếu không kèm theo DCL --> chọn: Simple, ngược lại
chọn: Expert.
3. Trong Application Location, tìm đến đường dẫn chứ file LISP. Và đặt tên ứng
dụng tại Application Name.
4. Xác định các tập tin LSP mà bạn cần tạo ứng dụng.
5. Thêm các tập tin DCL.

Cụ thể theo hình sau:


Chúc các bạn cuối tuần thật vui vẻ!
Vào lúc 26/5/2013 tại 15:23, Doan Van Ha đã nói:
Bổ sung thêm 2 ý của SongNhi:
1). Ngoài LSP và DCL, còn đóng gói được một số kiểu file khác nữa.
2). Số file đóng gói là có giới hạn.

2) Giới hạn là bao nhiêu bác? Tue_NV đóng gói nhiều 30 file lsp mà chẳng th ấy
giới hạn??????
Có 2 lần tôi đóng gói nhiều file. Nhớ như thế này:
- 1 lần tầm 10 files (không nhớ chính xác lắm).
- 1 lần đúng 13 files. Đóng 12 thì OK, đóng 13 thì NO.
Không tìm ra quy luật. Chẳng hiểu do số file hay dung lượng file hay gì gì n ữa,
mà sự việc là thế.

Sự việc là thế, là chưa chắc chắn, bác lại đưa ra câu khẳng định thế :lol:
Có 1 cách khử quy luật chưa biết này là gom tất cả file Lisp vào 1 file Lsp duy
nhất rồi đóng gói

@bạn Nhacotung : Phiền bạn post bài sang topic khác nhé. Mình tạm xoá bài
viết của bạn trong topic này.
Ở topic này đang thảo luận đến việc sử dụng VL.

Chạy Debug code LISP bán tự động

Vào lúc 14/5/2013 tại 10:20, lyky đã nói:


Sau khi trở lại VLIDE chúng ta vào Debug » Animate và đánh dấu tùy chọn này.

Vào lúc 15/5/2013 tại 14:50, Doan Van Ha đã nói:


12). Về check lỗi: VL ưu việt hơn N++ (xin xem thêm bài viết của Lyky ở trên, dù
nó chưa thực sự đầy đủ).

Hôm nay SN xin được trình bày cách chạy Debug bán tự động, không dùng ti ện
ích Animate, nghĩa là khi chạy debug chúng ta không check chọn Animate
trong tab Debug. Vẫn chạy trên đoạn code cũ trong #6, như sau:
(defun c:test ( / ss i sl total entity elist )
(if (setq ss (ssget '((0 . "LINE"))))
(progn
(setq i -1 sl (sslength ss) total 0)
(while (<= (setq i (1+ i)) sl)
(setq entity (ssname ss i)
elist (entget entity)
total (+ total (distance (cdr (assoc 10 elist)) (cdr
(assoc 11 elist))))))
(princ (strcat "\nTotal Length: " (rtos total)))))
(princ))
1. Trước tiên, SN liệt kê một số phím nóng cần dùng:

Step Into : F8
Step Over : Sh-F8
Step Out : Ct-Sh-F8

Continue : Ct-F8
Reset to Top Level : Ct-R
Quit Current Level : Ct-Q

Watch Window: Ct-Sh-W


Add Watch : Ct-W

Toggle Breakpoint : F9
Last Breakpoint : Ct-F9
Clear All Breakpoint: Ct-Sh-F9

Load Selection : Ct-Sh-E


Load Text in Editor : Ct-Alt-E
Check Selection : Ct-Sh-C
Check Text in Editor: Ct-Alt-C

2. Các bước 1; 2; 3.1 Adding Break Points và 3.2 Watching Variables thực hiện
như hướng dẫn #6. Đến 3.3 chúng ta không dùng tiện ích Animate, thực hiện như
sau: Cho chạy lại đoạn code đến khi gặp "điểm dừng" đầu tiên dùng F8
(Continue) để chạy dần từng bước một (hoặc Sh-F8) và theo dõi sự thay đổi giá
trị của 2 biến “i” và “entity” trên cửa sổ Watch Window. Việc sửa lỗi sau khi xác
định nguyên nhân lỗi - thực hiện như cũ.

Thật ra, không phải do tốc độ chạy Debug bằng Animate quá nhanh làm các bạn
không theo dõi kịp! Bạn có thể tuỳ chỉnh tốc độ này tại:

Đơn vị là mili giây (10-3 giây). Tuy nhiên, với các làm bán tự động này, các bạn có
thể kiểm tra giá trị của bất kỳ biến nào (mặc dù chưa được add vào Watch
Window) tại mỗi vị trí dừng, bằng cách: tô chọn biến đó chọn: Load Selection
(hoặc: Ct-Sh-E). Giá trị sẽ hiển thị trên Visual LISP Console.

Ngoài ra, SN còn muốn liệt kê thêm một số phím nóng giúp bạn kiểm tra nhanh
từng cụm ()
Ct-[: Chuyển dấu nháy đến ( mở đầu khối hoàn chỉnh phía trước.
Ct-]: Chuyển dấu nháy đến ) kết thúc khối hoàn chỉnh phía sau.

Ct- Sh-[: Tô chọn khối hoàn chỉnh (...) phía trước vị trí dấu nháy hiện tại.
Ct- Sh-]: Tô chọn khối hoàn chỉnh (...) phía sau vị trí dấu nháy hiện tại.

Mời các Bác tiếp tục chia sẽ những kinh nghiệm sử dụng trình soạn thảo VLISP
IDE!
Vào lúc 16/5/2013 tại 15:15, gia_bach đã nói:
Thêm chức năng "thu gom rác" : biến toàn cục -> biến cục bộ

Vào lúc 17/5/2013 tại 10:38, lyky đã nói:


@ Song Nhi: Hảo Song Nhi! Đối với những Lisp đã check rồi và "dọn rác" theo
cách anh Gia_Bach đã hướng dẫn, sau khi check lại sẽ không còn Global Var, trừ
trường hợp vì ý đồ khác của người viết!

Trong vấn đề giải phóng bộ nhớ sau khi chạy LISP cũng còn nhiều vấn đề khác,
cần được quan tâm, trước tiên bạn cần nắm các khái niệm biến cục bộ; biến toàn
cục và các tính chất của nó, nếu cần thiết các bạn có thể tham khảo tại đây,
hoặc tìm kiếm trên diễn đàn.

Danh sách trả về trong tiện ích kiểm tra của VLIDE sẽ liệt kê tất cả các đối
tượng được xác định trong code. Danh sách này có thể bao gồm: Các ký hiệu
bảo vệ (chẳng hạn như các hàm hoặc các hằng số được bảo vệ). Nếu các đối
tượng đó đều vô tình cục bộ hóa, chương trình của bạn có thể không chạy như
mong đợi ...

Vì vậy, các bạn cần lưu ý thêm, khi thanh lọc bộ nhớ bằng cách chép danh sách
xuất ra của biến toàn cục vào phía sau: (defun( /, cần loại ra các đối tượng sau
đây, không thanh lọc chúng, như sau:

1. Ký hiệu bảo vệ (được đánh dấu màu xanh), chẳng hạn như các hàm hoặc các
hằng số được bảo vệ (ví dụ: Vlax-true).

2. Đối tượng trong DCL được xác định tại thời gian chạy (chẳng hạn như: $key,
$reason, $value, $data).

3. Từ Pause, như có thể được sử dụng trong command expressions,


vd: (command "rotate" pause ""...

4. Biến mà bạn muốn giữ lại giá trị sau khi chạy vì mục đích khác (nào đó!?),
danh sách các biến trả về bởi các tiện ích kiểm tra được sắp xếp theo thứ tự
abc, cho nên bằng cách đặt trước tên biến toàn cục với dấu sao (*) hoặc ... , làm
cho nó xuất hiện ở đầu của danh sách để chúng ta có thể dễ dàng loại bỏ ra.

Không nhất nhiết check đối với một LISP đầy đủ, đối với một file tổng hợp nhiều
LISP, bạn cũng có thể Check toàn bộ, bằng cách chọn Check edit window trên
thanh công cụ Tools. Danh sách trả ra tổng hợp như sau:
Đối với danh sách trả về sau khi check, các biến ở dạng chữ in hoa, về mặt hình
thức nếu bạn muốn chuyển về chữ thường, hãy chạy list đó qua hàm sau:
(defun VarList (lst) (vl-princ-to-string (mapcar '(lambda ( x )
(strcase (vl-princ-to-string x) t)) lst)))
;;; Vi du:
(VarList '( C a d V i e t. c o m)) ---> "(c a d v i e t. c o m)"
Sau đó, bạn hãy lựa chọn những đối tượng mà bạn muốn cục bộ hóa, chép vào
phía sau: (defun( / để giải phóng bộ nhớ, tiết kiệm dung lượng và hạn chế tương
tác giữa các LISP với nhau!
Đối với danh sách trả về sau khi check, các biến ở dạng chữ in hoa, nếu bạn
muốn chuyển về chữ thường, hãy chạy list đó qua hàm sau:
(defun VarList (lst) (vl-princ-to-string (mapcar '(lambda ( x )
(strcase (vl-princ-to-string x) t)) lst)))
;;; Vi du:
(VarList '( C a d V i e tt)) ---> "(c a d v i e tt)"
........
Visual LISP Editor đã có sẳn các công cụ

này :

Vào lúc 3/6/2013 tại 21:43, Song Nhi đã nói:


Chạy Debug code LISP bán tự động

Hôm nay SN xin được trình bày cách chạy Debug bán tự động, không dùng ti ện
ích Animate, nghĩa là khi chạy debug chúng ta không check chọn Animate
trong tab Debug.

Thực ra, chúng ta có thể linh động hơn một chút xíu - bằng cách, trong lúc chạy
thủ công, đang ở một bước nào đó, bạn cũng có thể gọi tiện ích animate lên và
Ctrl+F8 để tiếp tục chạy tự động. Tuy nhiên, điều ngược lại không thực hiện được,
nghĩa là nếu đã bắt đầu chuyển qua chạy bằng animate, chúng ta chỉ có thể
thoát ra: abort evaluation, thoát lệnh và trả sang màn hình acad.

Ngoài ra, chức năng watching variables xem như tiện dụng để theo dõi sự liên
đới của các biến. Tuy nhiên, có thể là sẽ rất khó xem đầy đủ với các list dài,
chẳng hạn ... Do đó, nếu chỉ xem và theo dõi sự thay đổi giá trị của một biến nào
đó, chúng ta có thể sử dụng console window để xem giá trị sau mỗi thay đổi.

Một điều nhỏ nữa là bạn cần lưu ý, uncheck tiện ích animate sau khi chạy xong,
nếu không, khi bạn trở lại acad, sử dụng một lệnh nào đó liên quan đến file LISP
hiện hành, sẽ vấp phải sự "delay" vì y cứ tưởng bạn đạng chạy debug
(animate chỉ dùng để chạy debug mà thôi!).

Trở lại một vấn đề quen thuộc là Autoload LISP, chúng ta có rất nhiều cách như
sau:

1. Dùng Startup Suite.


2. Bổ xung Autoload vào file Acad.lsp hoặc Acadxxxxdoc.lsp…

Tuy nhiên, đối với những cách này, file LISP mà bạn muốn đặt Autoload cần phải
nằm trong Support (Trừ phi bạn biên đầy đủ đường dẫn của nó!), Có thể là bất
tiện và khó khăn trong việc trao đổi (Share - Copy – Move…). Chúng ta có th ể
dùng một cách khác, cách này phù hợp với các bạn xài trình soạn Visual LISP
IDE để coding và test LISP, ứng dụng Project vào vi ệc Autoload. Khi đó, Folder
chứa các file LISP bạn cần Autoload, có thể đặt ở một nơi nào tùy thích, miễn là
thuận tiện cho bạn!

2.1 Trước tiên, bạn cần có sẵn một Project.


2.2 Sau đó, bạn vào Options > Files > Support File Search Path > Add > Nh ập
(hoặc Browse) đến Project mà bạn cần Autoload với tên đầy đủ của Project đó
(có đuôi *.prj)

2.3 Move Up lên đầu, để được load trước (chuyện này không cần thiết lắm!)

2.4 Apply > OKei.

Từ nay, bạn muốn thêm bớt file LISP cần Autoload vào Project rất dễ dàng
(tương tự như Startup Suite). Tuy nhiên, khi máy (hoặc Acad) bị sự cố đột ngột –
chúng ta cũng không sợ mất LISP (vì bạn có thể tạo Project trên các ổ đ ĩa khác
C).

https://www.cadviet.com/forum/topic/1793-giao-di%E1%BB%87n-h
%E1%BB%99p-tho%E1%BA%A1i-trong-autolisp/
The Visual LISP Editor - Part 1
by Kenny Ramage

 See also:

 The Visual LISP Editor - Part 2

This tutorial is a crash course in using the Visual LISP Editor, and is not intended to be detailed or fully

comprehensive. The aim is to show you the main functions of the Editor with the intention of getting you up

and running as quickly as possible.

Right, enough waffle, let's get started. Fire up AutoCAD and open a new drawing. Now choose Tools

AutoLISP Visual LISP Editor from the pull-down menu. If you don't see the pull-down menu,

enter menubar at the command prompt and set the value to 1.

The Visual Lisp Editor will open and should look like this :

Let's start off by having a look at the Visual LISP Console window :
The VLISP Console window is similar in some respects to the AutoCAD Command window, but has a few

extra features. You enter text into the Console window following the Console prompt which looks like this :

_$

Type this in the Console prompt and then press "Enter" :

_$ (setq a "Test")

Now type this and again press "Enter" :

_$ a

Your Console window should look like this :

To view the value of a variable at the AutoCAD Command prompt, you must precede the variable name with

an exclamation mark. ( ! ) In VLISP, you simply type the variable name.

Unlike the AutoCAD Command window, where pressing SPACEBAR causes expression evaluation, text

input at the VLISP Console prompt is not processed until you press ENTER. This permits you to do the

following in the Console window:


 Continue an AutoLISP expression on a new line. To continue entering an expression on a new line,

press CTRL +ENTER at the point you want to continue.

 Input more than one expression before pressing ENTER. VLISP evaluates each expression before

returning a value to the Console window.

 If you select text in the Console window (for example, the result of a previous command or a

previously entered expression), then press ENTER, VLISP copies the selected text at the Console

prompt.

The VLISP Console window and the AutoCAD Command window differ in the way they process the

SPACEBAR and TAB keys. In the VLISP Console window, a space plays no special role and serves only as

a separator. In the AutoCAD Command window, pressing the SPACEBAR outside an expression causes

AutoCAD to process the text immediately, as if you had pressed ENTER.

Using the Console Window History


You can retrieve text you previously entered in the Console window by pressing TAB while at the Console

prompt. Each time you press TAB, the previously entered text replaces the text at the Console prompt. You

can repeatedly press TAB until you cycle through all the text entered at the Console prompt during your

VLISP session. After you’ve scrolled to the first entered line, VLISP starts again by retrieving the last

command entered in the Console window, and the cycle repeats. Press SHIFT + TAB to scroll the input

history in the opposite direction. For example, assume you entered the following commands at the Console

prompt:

(setq origin (getpoint "\nOrigin of inyn sign: "))

(setq radius (getdist "\nRadius of inyn sign: " origin))

(setq half-r (/ radius 2))

(setq origin-x (car origin))

(command "_.CIRCLE" origin radius)

To retrieve commands entered in the Console window :

1. Press TAB once. VLISP retrieves the last command entered and places it at the Console prompt :
_$ (command "_.CIRCLE" origin radius)

2. Press TAB again. The following command displays at the Console prompt :

_$ (setq origin-x (car origin))

3. Press TAB again. VLISP displays the following command :

_$ (setq half-r (/ radius 2))

4. Now press SHIFT+ TAB . VLISP reverses direction and retrieves the command you entered after

the previous command :

_$ (setq origin-x (car origin))

5. Press SHIFT+ TAB again. VLISP displays the following command :

_$ (command "_.CIRCLE" origin radius)

This was the last command you entered at the Console prompt.

6. Press SHIFT+ TAB again. Because the previous command retrieved was the last command you

entered during this VLISP session, VLISP starts again by command you entered in the Console

window :

_$ (setq origin (getpoint "\nOrigin of inyn sign: "))

Note : If you enter the same expression more than once, it appears only once as you cycle through the

Console window input history. You can perform an associative search in the input history to retrieve a

specific command that you previously entered. To perform an associative search of the Console input

history :

1. Enter the text you want to locate. For example, enter (command at the Console prompt :

_$ (command

2. Press TAB. VLISP searches for the last text you entered that began with (command :

_$ (command "_.CIRCLE" origin radius)


If VLISP does not find a match, it does nothing (except possibly emit a beep). Press SHIFT+ TAB to

reverse the direction of the associative search and find progressively less-recent inputs.

Interrupting Commands and Clearing the Console


Input Area
To interrupt a command entered in the Console window, press SHIFT + ESC. For example, if you enter an

invalid function call like the following:

_$ ((setq origin-x (car origin)

((_>

Pressing SHIFT + ESC interrupts the command, and VLISP displays an "input discarded" message like the

following :

((_> ; <input discarded>

_$

If you type text at the Console prompt, but do not press <Enter>, then pressing ESC clears the text you

typed. If you press SHIFT + ESC, VLISP leaves the text you entered in the Console window but displays a

new prompt without evaluating the text.

If you type part of a command at the Console prompt, but activate the AutoCAD window before pressing

<Enter>, VLISP displays a new prompt when you next activate the VLISP window. The text you typed is

visible in the Console window history, so you can copy and paste it, but you cannot retrieve the text by

pressing TAB , because it was not added to the Console history buffer.

When you're ready, let's continue to Part 2.

The Visual LISP Editor - Part 2


by Kenny Ramage

 See also:
 The Visual LISP Editor - Part 1

Right, enough messing about. Let's load some coding. Choose File New File and then copy and paste

this coding into the text editor :

(defun C:SLOT ( )

(setvar "CMDECHO" 0)

(setvar "BLIPMODE" 0)

(setq oldsnap (getvar "OSMODE"))

(setq diam (getdist "\nSlot Diameter : ")

lngth (getdist "\nSlot Length : "))

(while

(setq pt1 (getpoint "\nInsertion point:"))


(setvar "OSMODE" 0)
(setq pt2 (polar pt1 0.0 (/ (- lngth diam) 2.0))
pt3 (polar pt2 (/ pi 2.0) (/ diam 4.0))
pt4 (polar pt3 pi (- lngth diam))
pt5 (polar pt4 (* pi 1.5) (/ diam 2.0))
pt6 (polar pt5 0.0 (- lngth diam)))

(command "PLINE" pt3 "W" (/ diam 2.0) "" pt4


"ARC" pt5 "LINE" pt6 "ARC" "CLOSE")
(setvar "OSMODE" oldsnap)
);while
(princ)
);defun
(princ)

The coding should look like this in the text editor :

Before we go any further, let's have a wee chat about the colors. As soon as you
enter text in the VLISP Console or text editor windows, VLISP attempts to
determine if the entered word is a built-in AutoLISP function, a number, a string,
or some other language element. VLISP assigns every type of element its own
color. This helps you detect missing quotes or misspelled function names. The
default color scheme is shown in the following table.

AutoLISP Language Element Color


Built-in functions and protected symbols Blue
Strings Magenta
Integers Green
Real numbers Teal
Comments Burgundy, on gray background
Parentheses Red
Unrecognized items (for example, user variables) Black
You can change the default colors. But, do yourself a favour. Don't!

Selecting Text
The simplest method to select text is to double-click your left mouse button. The amount of text selected

depends on the location of your cursor.

 If the cursor immediately precedes an open parenthesis, VLISP selects all the following text up to

the matching close parenthesis.

 If the cursor immediately follows a close parenthesis, VLISP selects all preceding text up to the

matching open parenthesis.

 If the cursor immediately precedes or follows a word, or is within a word, VLISP selects that word.

Hint : Would you like help on any AutoLisp function? Double-click on the function name to select it, and

then select the "Help" toolbar button. Help for the specific function will be displayed.

To load the "Slot" lisp routine, select the "Load active edit window" toolbar button :

This loads your coding into memory. To run the routine, type this at the Console prompt :

_$ (c:slot)

The program should now run, switching over to the AutoCAD screen when required. You can also just run a

selection of code if you desire. Select the lines of code you would like to run and choose the "Load

selection" toolbar button, and then press "Enter."


Only the lines of code you selected will be run, Great for debugging.

Talking about debugging, Place the cursor in front of the (defun C:SLOT () statement and press "F9". This

places a "Breakpoint" into your program. Now run the program again. Execution should stop at the

Breakpoint mark. Now press "F8". By continuously pressing "F8" you can "single step" through your whole

program :

Let's go one step further. Select the "diam" variable and then select the "Add Watch" toolbar button :

The "Watch" dialog box will appear :

Note how the variable "diam" is listed along with it's present value. Repeat this process for all the other

variables until the Watch" dialog looks like this :


Now run the program again, still "single" stepping through. Notice how the values of the variables change

as the program proceeds.

OK let's liven things up a bit. Select "Ctrl-Shift-F9" to clear all breakpoints. Now select the "Debug" pull

down menu and then "Animate". Now run the program again.

Hey, it's running automatically! Take note of the variables changing in the "Watch" window as the program

does it's thing.

Well that's about it in regards to the Visual LISP Editor. The editor has a lot more functions than I've shown

you here, but these I feel, are some of the more important ones to get you started.
An Introduction to the Visual
LISP IDE
The Visual LISP IDE (rather, more precisely: Visual LISP Integrated Development
Environment (VLIDE) - but that's a bit of a mouthful), is an excellent developer tool &
resource supplied as standard with the majority of full versions of AutoCAD.

Even if you are just starting to program in LISP, in my opinion, the VLIDE is essential
and can be a great learning aid.

This tutorial will demonstrate how to get started with the VLIDE, and, to keep things
relatively clear, I won't be delving too deeply into the multitude of tools available to
the developer.

Introduction
To begin, open AutoCAD to a blank drawing and type VLIDE at the command line.

A window should appear, containing two or more smaller windows including the
Console Window & Trace Window (more on these later).

Let's begin by opening a New File in which we can start to construct a program. To do
this, go to File » New File (alternatively using the shortcut: Ctrl+N).

In the window that appears, we can start to construct our LISP program. As an
example, copy or type the following code into the blank editor window:

(defun c:test ( )

(princ "\nI can now use the VLIDE.")


(princ)
)

You will notice that the functions, brackets, strings and other items are highlighted
accordingly:
The syntax highlighting is a great visual aid, and also helps prevent protected symbols
such as function names being used as names for variables, as they are highlighted
accordingly.

At this point, we can study the code in more detail, and, if not sure about how a
function is to be used, we can immediately get information about that function using
the VLIDE Help Documentation. A tutorial on how to do this can be found here.
Also, we can open an existing LISP file to edit the contents in the VLIDE Editor
Window - to do this, either go to File » Open File or use the shortcut Ctrl+O.

Loading a Program
OK, so we've just constructed a program in the Visual LISP IDE, now to test it out!

As you may know, loading a program into AutoCAD can sometimes be tedious, as the
LISP file needs to be saved, then either loaded using the Appload command, or maybe
the ACADDOC.lsp. But, you'll be pleased to know, loading programs in the VLIDE
is much simpler.
There are three equivalent ways to load a program: by going to Tools » Load Text in
Editor; by clicking on the relevant toolbar icon on the Tools toolbar; or simply by
using the shortcut Ctrl+Alt+E.

Upon loading the program, the Visual LISP Console window will appear indicating
whether the code has been loaded successfully.

Now, having loaded the example code above, we can go back to the AutoCAD window,
and at the command line type: test to start the program.

The Visual LISP Console


The Console Window can be activated by going to View » LISP Console or using the
shortcut F6.
The Console will immediately evaluate an entered LISP expression, whether it be a
call to a function, the function itself, or maybe a variable. This is handy for
experimenting with functions & expressions without having to create an entire
program.

A Few Examples
Evaluating a LISP Expression
_$ (+ 2 2)
4
Variable Evaluation
_$ (setq var 1.4142)
1.4142
_$ var
1.4142
Protected Symbol Evaluation
_$ actrue
1
_$ defun
#<SUBR @0fbfaaf0 DEFUN>
Calling a Function (using the example code from earlier)
_$ (c:test)

I can now use the VLIDE.

Further Information
This tutorial has covered the basics of the Visual LISP Integrated Development
Environment (VLIDE) - the Editor offers many essential debugging tools to get you out
of a fix when code goes wrong, and furthermore other tools to format code at the
touch of a button. Be sure to explore the VLIDE Help Documentation detailing how to
get the most out of the VLIDE.

How to Run an AutoLISP


Program
Saving the AutoLISP File
Before we can run any programs we must make sure that the program file (.lsp file in
this case) resides on the system.
If you are downloading programs from my site, the method of saving the AutoLISP file
may depend on the browser you are using. For example, IE8 may prompt you to save
the file directly to your computer, but I believe Firefox allows you to view the file
contents in the browser itself, in which case, you can either go to File » Save Page
As making sure that the Save as Type panel is set to All Files; or, you can simply
copy the contents into an open Notepad file and save this as 'filename.lsp' (again,
ensuring File Type is set to 'All Files').

Note that the filename used to save the source code is arbitrary and will not affect the
program in any way - however, the majority of users use the function syntax (and
perhaps include the program version) for convenience.

Loading the Program


Method 1: Using AppLoad
At the AutoCAD command line, type AppLoad (alternatively go to Tools » Load
Application).
Select the program file as previously saved and click Load to load the program into the
current drawing session. Click Close to close the Appload Dialog.

The command line should display whether the program has indeed loaded
successfully, and any loading messages the author may have decided to include.

Method 2: Using the ACADDOC.lsp


Another way to load an AutoLISP program is to include a load call in the
ACADDOC.lsp.
Everytime a new drawing is opened, AutoCAD will search the Support Paths for any
ACADDOC.lsp files, and will proceed to load the first one it discovers.

First we must check that an ACADDOC.lsp file exists - to do this type at the AutoCAD
command line:

(findfile "ACADDOC.lsp")

If this returns a filepath, navigate to the existing ACADDOC.lsp file and in the steps
that follow, amend its contents.

Else, you can create a new ACADDOC.lsp file by opening a new Notepad document (or
other plain text editor) and saving it as ACADDOC.lsp in an AutoCAD Support Path
(ensuring the Save As Type panel is once again set to All Files).

In the ACADDOC.lsp, add a line similar to this:

(load "C:\\MyFolder\\MyLISP.lsp" "MyLISP Failed to Load")


If the LISP file does not reside in the AutoCAD Support Path, a full filepath is needed
so that the LISP file may be located; in this case, be sure to use double
backslashes when specifying the path.

When finished, open a new drawing and the LISP files should load.

Note: if using this method to load many LISP files on startup is causing drawings to
open slower, refer to my tutorial on the use of AutoLoad to demand load LISP files.

Method 3: Using the Visual LISP Integrated


Development Environment (VLIDE)
This method is aimed primarily at developers, as the VLIDE offers many debugging
utilities when writing & loading code.
To load a program using this method, type VLIDE at the AutoCAD command line. In
the window that subsequently appears, go to File » Open
File (alternatively, Ctrl+O), and select the previously saved file.
Now go to Tools » Load Text in Editor (alternatively, Ctrl+Alt+E)

Running the Program


If the program has loaded successfully, you can now proceed to run the program in
the current drawing session.

The syntax (command name) to call the program may be displayed in the author's
loading messages, or perhaps noted in the program header. If it cannot be found in
either of these locations, you can inspect the source code itself to determine the
command to use.
The syntax will be located after the c: in a defun function call, for example:
(defun c:MyCommand ( )
...
In the above example, the command would be MyCommand.
If the c: does not appear after the defun function, this indicates that the function is a
subfunction and is designed to be called from another program.

When the command syntax is known, it may be typed at the AutoCAD command line
to invoke the program.

Loading Programs Automatically

Loading Programs
Automatically
This tutorial aims to guide you through the various methods which can be used to load
a program automatically on startup.

If you have a toolbox of LISP programs that you use regularly, it would be tedious to
have to load each and every program whenever a drawing is opened. Thankfully, I
shall introduce two methods to accomplish this task, each with their own advantages
in different situations.

Method 1: Using the Startup Suite


This is perhaps the most user-friendly method to automatically load a program at
startup, as the user needn't have any LISP experience whatsoever.

Firstly, type AppLoad at the AutoCAD command-line (alternatively, go to Tools » Load


Application).
In the dialog that subsequently appears, click on the Contents button beneath
the Startup Suite heading:
A secondary dialog will consequently appear, to which programs to be loaded on
startup may be added. To do this, click Add and navigate to the desired program.

All programs listed in the above panel will be loaded every time a drawing is opened.

The method of using the Startup Suite to load programs automatically does have a
few disadvantages however: should the user wish to migrate his or her programs to
another computer, all programs will need to be added to the Startup Suite on the new
computer.

There have also been a few known bugs surrounding the Startup Suite in past
versions of AutoCAD. For these reasons, I shall introduce another method which,
although requires the user to have some basic knowledge of AutoLISP, overcomes
these difficulties.

Method 2: Using the ACADDOC.lsp


Upon opening a drawing or starting a new drawing, AutoCAD will search all listed
support paths including the working directory for a file with the filename: ACADDOC.lsp.
If one or more such files are found, AutoCAD will proceed to load the first file found.

With this knowledge one can edit or create an ACADDOC.lsp to include any AutoLISP
expressions to be evaluated upon startup.

Things get a little complicated should there exist more than one ACADDOC.lsp file, so,
to check if such a file already exists, type or copy the following line to the AutoCAD
command line:

(findfile "ACADDOC.lsp")
Should a filepath be returned, in the steps that follow, navigate to this file and amend
its contents. Else, if the above line returns nil, you can create your
own ACADDOC.lsp in Notepad or the VLIDE and save it in an AutoCAD Support Path.
One clear advantage to using the ACADDOC.lsp to automatically load programs is that,
upon migration, it may easily be copied from computer to computer, or indeed reside
on a network to load programs on many computers simultaneously.

The Load Function


The load function will evaluate all AutoLISP expressions found within a file with a
supplied filename (if found), effectively loading an program file (.lsp/.fas/.vlx) into the
current drawing session.
The load function takes two arguments:
(load <filename> [on failure])
Where filename is the filename of a program file to load, and on failure is an
optional argument to be returned should the program fail to load (this is usually a
string or nil).

If the program file resides in an AutoCAD Support Path, the filename need only be the
name of the file to load; else a full filepath is required to locate the file, for example:

File Residing in AutoCAD Support Path:


(load "MyProgram" "MyProgram Failed to Load.")
(load "MyLISP.lsp" "MyLISP Failed to Load.")
File Residing Elsewhere:
(load "C:\\My Folder\\MyProgram.vlx" "MyProgram Failed to Load.")
Note that should the file extension be omitted, the load function will add .vlx, .fas,
.lsp (in that order) stopping when a file is found.
Although the on failure argument is optional, I would recommend to include it in the
load statement, else the function will return an error should the file fail to load.

Using this knowledge we can populate our ACADDOC.lsp file with load statements to
be evaluated when the ACADDOC.lsp file is loaded on startup.

In this way, the ACADDOC.lsp may look something like this:

(load "C:\\MyPrograms\\MyLISP.lsp" "MyLISP Failed to Load.")


(load "F:\\My Folder\\MyApp.fas" "MyApp Failed to Load.")
(load "MyProgram" "MyProgram Failed to Load.")
To aid in the construction of an ACADDOC.lsp utilising the load function I have
constructed an ACADDOC.lsp Creator Program which can write statements to the
ACADDOC.lsp to load all programs in a directory (and subdirectories) - saving you all
the tedious typing.
One disadvantage of using the load function arises when the user wishes to load a
large number of programs. This method will load every program into memory
everytime a drawing is opened, hence should a large number of programs require
loading, there may be a noticeable increase in the time taken to open a drawing.
To avoid this time delay, programs can be 'demand-loaded', i.e. loaded as and when a
user needs them; for this I introduce the AutoLoad function.

The AutoLoad Function


The AutoLoad function enables a user to load an AutoLISP file when a specific
command is entered at the command line. This can greatly reduce the time taken to
open a drawing and the memory used should the user wish to load many programs
automatically as programs are only loaded into the drawing session when required by
the user.
The AutoLoad function takes the following format:
(autoload <filename> <cmdlist>)
Where filename is the name of an AutoLISP file and follows much the same rules as
with the load function: should the AutoLISP file reside in an AutoCAD Support Path,
only the filename is needed, else a full filepath is required.
The cmdlist is a list of commands that, upon the user typing a command present in
the list, the filename supplied will be loaded into the current drawing session.

This method is best demonstrated with an example. Consider the following LISP
program:

(defun c:DrawLine ( / p q )

(if (and (setq p (getpoint "\nSpecify First Point: "))


(setq q (getpoint "\nSpecify Next Point: " p)))
(entmake (list (cons 0 "LINE") (cons 10 (trans p 1 0)) (cons 11
(trans q 1 0))))
)
(princ)
)
The above program will simply construct a line between two selected points; but,
more importantly for this example, it may be called with the syntax: DrawLine.
Let's assume the above code is saved to a LISP file in an AutoCAD Support Path
called: LineProgram.lsp.

To demand-load this program automatically we could include this line in the


ACADDOC.lsp:

(autoload "LineProgram" '("DrawLine"))


Now, upon opening a drawing or creating a new drawing, should the user
type DrawLine at the command line, the LineProgram.lsp file will be loaded into the
drawing session and the program will start.
Should the program file contain more than one command, additional commands may
be added to the list supplied to the AutoLoad function, hence triggering the load of the
supplied file upon the user typing any command present in the list.

Further Information
Further information about the functions I have demonstrated in this tutorial may be
found in the VLIDE Help Documentation. Struggling to access the help? See my
tutorial here.

An Introduction to Script
Writing
Scripts are very different to AutoLISP programs - a Script is merely a list of AutoCAD
commands to be executed one after the other, as if the user were typing them at the
command-line.

In an AutoCAD Script, a space or new-line is interpreted as the user pressing Enter,


hence, if we wanted to use a script to draw a circle at the origin with a radius of 5, we
could use the following in a script file:
SELECT ALL
_.circle _non 0,0,0 5

The following code represents the above Script line with spaces shown for clarity:

_.circle•_non•0,0,0•5•
Note the space after the 5 representing the user pressing Enter to submit the entered
radius to complete the command (a new blank line could also have been used in the
script file for the same result).

At this point, you may be slightly confused by some of the prefixes & command
parameters used in the above example, so here is a short explanation of the purpose
of each item:

o _ (underscore)
Non-localised command prefix: this prefix ensures that the English name of a
command is used, irrelevant of the language of the version in which it is
invoked. For example, if we have a Script calling the LINE command, by prefixing
the command name with an underscore (i.e. _line) the same Script can be used
in, say, a French version of AutoCAD, without needing to replace every
occurrence of 'line' with 'ligne'.

Note that this prefix should also be used with command keywords to allow for
cases in which the keyword does not use the the same 'key letter' when
translated to another language.
o . (period)
Non-redefined command prefix: this prefix is used to account for commands that
have been redefined, ensuring that the original standard command is used and
not a redefined version.
o non (or 'none')
This is an Object Snap modifier (similar to end or mid) which instructs the
command to ignore any active Object Snap modes for the next point input. The
modifier keyword is prefixed with an underscore to account for non-English
versions of AutoCAD, as described above.

For English versions of AutoCAD in which no commands have been redefined, the
underscore & period prefixes are not absolutely necessary, however, it is good
practice to include them to enable compatibility with all versions without any effect on
the performance or operation of the Script.

Now its your turn...


Try it for yourself: select the above code (that is, the Script code without the spaces
displayed) and copy it into a new Notepad file (or other plain text editor), save the file
as filename.scr (the filename may be anything you like, but ensure that the Save As
Type panel is set to All Files):
Then, in a blank new AutoCAD drawing type SCRIPT at the command line, and select
the saved script file to run it. If you're lucky, you might just see a circle of radius 5
appear at the origin.

Now, this all seems pretty clever so far, but huge amounts of time can be saved if we
extend this idea to more than one drawing.

Processing Multiple Drawings


If we issue the OPEN command within our script and specify a filename to open, the
script will proceed to open the specified drawing and continue evaluating the
remainder of the script file on the newly opened drawing.
When specifying a drawing to open, be sure to enclose it with quotation marks as this
accounts for any spaces in the filepath - otherwise these spaces will be interpreted as
the user pressing Enter.
SELECT ALL
_.open "C:\My Folder\Drawing1.dwg" _.circle _non 0,0,0 5 _.qsave
_.close
_.open "C:\My Folder\Drawing2.dwg" _.circle _non 0,0,0 5 _.qsave
_.close
_.open "C:\My Folder\Drawing3.dwg" _.circle _non 0,0,0 5 _.qsave
_.close
With spaces displayed:
_.open•"C:\My
Folder\Drawing1.dwg"•_.circle•_non•0,0,0•5•_.qsave•_.close
_.open•"C:\My
Folder\Drawing2.dwg"•_.circle•_non•0,0,0•5•_.qsave•_.close
_.open•"C:\My
Folder\Drawing3.dwg"•_.circle•_non•0,0,0•5•_.qsave•_.close•
This script will open Drawing1.dwg, create a circle centered at the origin with a radius
of 5, and then proceed to save the drawing and close it before moving
onto Drawing2.dwg.
Observe that there is no space after the final close command for the first two lines,
as the new-line in the Script file will be interpreted as the user pressing Enter, and
will issue this final command before proceeding to open the next drawing.

You can also load & call AutoLISP programs from within scripts, and so, to make the
scripting more robust, you might consider creating an AutoLISP program to execute
all operations on the drawing, and then merely use the script to open each drawing,
load & evaluate the AutoLISP program, then finally save and close the drawing.

Upon viewing the above example, you can probably already see where the next time
saving can be made: in the writing of the script. After all, who would want to type all
those filenames manually? The Solution: Script Writer.

Script Writer
Function Syntax WScript
Current Version 1.2
Download ScriptWriterV1-2.lsp
View HTML Version ScriptWriterV1-2.html

Program Description
The aim of this program is to reduce the
construction of an AutoCAD Script to a single
line.
The program assumes the user is conversant in writing scripts for AutoCAD, if not,
refer to my tutorial: An Introduction to Script Writing.

This program is designed to greatly reduce the time involved in writing scripts as an
alternative to the usual scripting programs available.

Upon starting the program, the user is presented with a dialog interface. Near the top,
the user may enter a Script Line - this is the list of commands that will be performed
on each drawing in the selected directory (and subdirectories).

The user only needs to write the first line of the script, which will be performed on
every drawing in the selected directory; this is achieved through the use of a special
token string to represent the drawing filename in the line of script operations.

Example
Consider the example from my script writing tutorial:

_.open "C:\My Folder\Drawing1.dwg" _.circle 0,0,0 5 _.save _Y


_.close
_.open "C:\My Folder\Drawing2.dwg" _.circle 0,0,0 5 _.save _Y
_.close
_.open "C:\My Folder\Drawing3.dwg" _.circle 0,0,0 5 _.save _Y
_.close

To avoid having to construct the whole script, we can convert the first line for use with
the Script Writer program, as follows:

_.open *file* _.circle 0,0,0 5 _.save _Y _.close

The program will then replace this token with the filename of each drawing in the
selected directory (and subdirectories), and subsequently run the constructed script.

Additional Controls
The programs provides additional buttons to save even more time in writing the script
line operations: the user may quickly insert the *file* token or clear the existing line
by pressing the Filename and Clear buttons respectively.
Scripts may also be saved for later use, or existing scripts may be loaded into the
program using the Load / Save buttons.

Preview

Instructions for Running


Please refer to How to Run an AutoLISP Program.

Localising Variables
This is a practice that, in my experience, many new AutoLISP programmers overlook -
sometimes resulting in elusive bugs in their programs.

This tutorial will give a brief overview of the defun function and moreover explain why
localising variables is a good habit to get into. I have tried not to go into the small
details in this tutorial to keep things clear.

Some Background on the 'Defun'


Function
For a more complete overview on the defun function, read the help documentation
provided in the Visual LISP Editor (VLIDE). Not sure how to access the help? See my
tutorial on Retrieving Information about a Function.
The purpose of defun is clear from its name: define function. defun may be used to
create a program that the user may call from the command line by typing the symbol
used to name the function, or perhaps to create a subfunction which may be called
from within another function to perform a particular task.
The defun function is used in the following way:
(defun <symbol> ([arguments] [/ variables]) <expressions>)

Here,

o symbol is the name of the function (if prefixed with 'c:' the function may be called
from the command line).
o arguments are symbols representing data that the function requires when called
(more about these some other time).
o variables are the symbols used to hold data within the function.
o expressions are all the statements that make up the function itself.

Examples
(defun test ( arg1 arg2 / var1 var2 ) ;; Function taking two
arguments, with two local variables

;; Expressions
(setq var1 (* arg1 2.0) var2 (+ arg2 3))

(print (- var2 var1))


(princ)

) ;; End of defun
(defun c:MyCommand ( / a b c ) ;; Function with three local variables

(setq a 1.0 b 2 c 3)

(print (- b (/ a c)))
(princ)
)
(defun myfunc ( x y ) ... ) ;; Function takes two arguments
(defun myfunc ( / a b ) ... ) ;; Function has two local
variables
(defun myfunc ( x / temp ) ... ) ;; One argument, one local
variable
(defun myfunc ( ) ... ) ;; No arguments or local
variables

Why Localise the Variables?


If a symbol is included within the 'variables' argument of the defun statement, when
calling the function, memory space is made available to hold any data later bound to
that symbol, and furthermore the data is disassociated with the symbol after the
function has completed; hence the symbol will now point to whatever data it held
before the function was called, or may be nil.

All else aside, this is certainly a 'cleaner' method, as, any variables set within the
function are 'cleaned up' afterwards, and hence cannot interfere with other programs
using the same symbols for variable names, or indeed waste space in the memory.

What are the Consequences?


Usually, programmers will see no difference in the behaviour of a function with
variables localised or not - but there are a few cases in which one can receive
unexpected results, and such bugs are sometimes hard to spot.

Take this example (Notice no variables are localised):

(defun c:test ( )

(foreach x '(1 2 3 4 5)
(setq lst (cons x lst))
)

(print lst)
(princ)
)
Upon running the above code, the following will be displayed at the command line (be
sure you know why it is reversed):
(5 4 3 2 1)

Now, in the same AutoCAD session, if we run the code again, we receive:

(5 4 3 2 1 5 4 3 2 1)
The list has doubled! This is because the variable lst still holds the list data even after
the function has completed. Hence, when evaluated for the second time, new values
are added the existing list.

This certainly highlights one major issue, but what if we had another function, also
without localised variables, using the same symbol for a variable name?

(defun c:test ( )

(foreach x '("1" "2" "3" "4" "5")


(setq lst (cons x lst))
)

(print lst)
(princ)
)

Upon running the above code, we now have a list containing a mixture of data types -
this is getting really messy!

("5" "4" "3" "2" "1" 5 4 3 2 1 5 4 3 2 1)

To avoid these issues, we localise the variables:

(defun c:test ( / lst )

(foreach x '(1 2 3 4 5)
(setq lst (cons x lst))
)

(print lst)
(princ)
)
Now we can be confident that everytime we run the program, the value of lst will be
consistent everytime:
(5 4 3 2 1)

Prompting with a Default


Option
Contents
 Introduction
 Note 1: On Prompt String Format
 Note 2: On Global Variables
 Case 1: Forcing User Input (No Default)
 Case 2: Preset Default Option
 Case 3: Dynamic Default
 Beyond the Examples

Introduction
This tutorial describes various ways in which to prompt for user input whilst offering a
default option available for selection by the user pressing ENTER , SPACE or right-
clicking at the prompt.

Note 1: On Prompt String Format


In order to create a professional looking program, I usually try to closely match the
standard prompting format utilised by AutoCAD. The idea is to create an application
that can be cleanly integrated into the AutoCAD environment with minimal user
training.

To achieve correct display of available options when Dynamic Input is enabled


(i.e. DYNMODE = 1 toggled with F12 ), the prompt string must be formatted in the
following way:
[Option1/Option2/Option3] <Option1>
In the above example, Options 1, 2 & 3 are available for user selection with Option
1 as a default option - selected upon the user pressing Enter.

Note 2: On Global Variables


In the examples that follow, global variables are used to effectively 'remember' a
default option after program completion. To indicate where global variables are
utilised, the variable names are prefixed with global:; this furthermore decreases the
risk of variable names clashing with unlocalised variables from other programs.

I would note that the prefixes are used for no other purpose: in AutoLISP, they
constitute standard variable names.

Read my tutorial on Localising Variables to understand the possible consequences of


using duplicate unlocalised variable names between programs.

Case 1: Forcing User Input (No


Default)
This is the simplest case in which there is no default option available. I use
the initget function with bit code 1 to force the user to make a selection from the
available options; hence in this case no conditional error trapping is required to
ensure user input, since the only way the user can bypass the prompt is to exit the
program using ESC .
(initget 1 "Alpha Beta Gamma")
(setq ans (getkword "\nChoose [Alpha/Beta/Gamma]: "))
Bit code 1 of the initget function prevents the user from responding to the request by
pressing ENTER , thus forcing the user to select from the Alpha, Beta & Gammaoptions.

Case 2: Preset Default Option


In this case, a default option is available, however it is the same option everytime.
The default option is hard-coded into the prompt string and may be selected by the
user pressing ENTER at the prompt.

Version 1
(initget "Alpha Beta Gamma")
(setq ans (cond ((getkword "\nChoose [Alpha/Beta/Gamma] <Alpha>: "))
("Alpha")))
In the above code, the option Alpha is hard-coded as the default option.
If the user presses ENTER at the prompt, the getkword expression returns nil and so
the cond function moves on to evaluate the next test condition: this is the default
string "Alpha" which is a non-nil value and is hence returned by the cond function.

Version 2
(initget "Alpha Beta Gamma")
(if (null (setq ans (getkword "\nChoose [Alpha/Beta/Gamma] <Alpha>:
")))
(setq ans "Alpha")
)
This second version uses the same logic as the first, however the conditional
operator cond is replaced by an if statement. Hence, if the variable ans is nil, the
default option is bound to it.

Case 3: Dynamic Default


In this case, the variable global:ans is intended to be global (not localised in the
function definition in which it is used). Since it is global, it does not lose any value
bound to it following program completion.
(if (null global:ans)
(setq global:ans "Alpha")
)
(initget "Alpha Beta Gamma")
(if (setq tmp (getkword (strcat "\nChoose [Alpha/Beta/Gamma] <"
global:ans ">: ")))
(setq global:ans tmp)
)
In the above code, the variable global:ans is first checked for a non-nil value: this is
to ensure that, upon the first run of the program there is a default to be offered to the
user.
Upon the first run of the program, the variable global:ans will be nil and so
the if statement will bind the value "Alpha" to it - this will be the first-time default.
The if statement which follows reverses the logic used in the previous examples: if
the user has responded with some input (i.e. the getkword function has returned a
non-nil value), the global variable global:ans is updated to store the new input (even
if the user may have explicitly selected the same option as the default).
Conversely, if the user has pressed ENTER at the prompt, the getkword function will
return nil and the global:ans variable will retain its existing value as the default
option selected by the user.
If the program is then run a second time, the variable global:ans now has a value,
and so the test expression in the first if statement returns nil. Therefore, in the
expressions that follow, the last selected option as held by the global:ans variable is
used as the default.

Beyond the Examples


In all of the above the examples, I have used the getkword function to prompt the
user to select one of a predefined set of options, however, the methods & logic
illustrated above could equally be applied to the other getXXX user input functions
(e.g. getreal, getdist etc.) with the exception of getstring which returns an empty
string ("") on null input.

The only additional consideration when generalising to other functions is the required
conversion from the data type of the default value to the string which is used to
display the user prompt.

For example, when prompting the user to specify an integer value, the itoa (integer-
to-ASCII) function must be used so that the default value may be concatenated with
the user prompt using the strcat (string concatenation) function:
(if (null global:int)
(setq global:int 1)
)
(initget 6)
(if (setq tmp (getint (strcat "\nEnter a positive non-zero integer <"
(itoa global:int) ">: ")))
(setq global:int tmp)
)
Similarly, in the following example, the numerical value of the global variable is
converted to a string formatted in decimal format to 3 decimal places using
the rtos(real to string) function:
(if (null global:dis)
(setq global:dis (+ pi pi))
)
(initget 4)
(if (setq tmp (getdist (strcat "\nSpecify circumference <" (rtos
global:dis 2 3) ">: ")))
(setq global:dis tmp)
)

Error Handling
Ever used a program only to discover some time later that your Object Snaps have
been mysteriously cleared? Or maybe AutoCAD is suddenly behaving differently?
These are tell-tale signs that you have aborted a program that is not equipped with an
appropriate error handler.

This tutorials aims to teach you how to create an error handler for your programs to
deal with the clean-up operation when something in the code goes wrong.

What can go Wrong?


Errors can arise in many forms: from a null user input, to attempting a division by
zero; although, what most users don't realise is that thumping the Esc key during
program execution is also considered an error and will hence abort the program
instantaneously. This usually induces the situation in which users find themselves
manually resetting their osnap settings. This is where a suitable error handler comes
into its own.

The *error* Function


The *error* function is a user-definable function which will be evaluated when
AutoCAD encounters an error when executing an AutoLISP expression.
The *error* function takes a single string argument, which is supplied by AutoCAD
when an error is encountered during program evaluation. This string describes the
error which has caused the *error* function to evaluate.

The standard error handler used by AutoCAD will simply print this argument to the
command line; you can see this behaviour first hand by typing at the command line
something like:
(itoa nil)

This will in turn cause the standard error handler to evaluate and print the following
message at the command line:

; error: bad argument type: fixnump: nil


Indicating that we have passed a value of nil to the itoa function, which was
expecting an integer (indicated by the fixnump message).

Creating an Error Handler


The main purpose of an error handler is to restore a user's AutoCAD environment
back to its original settings should something in a program goes wrong. To accomplish
this, we can redefine the *error* function.
(defun c:test ( / *error* )

(defun *error* ( msg )


(princ "error: ")
(princ msg)
(princ)
)

(getstring "\nPress Esc to force an error...")


(princ)
)
When running the above program using the command test at the command line,
upon pressing Esc at the prompt, the program will be aborted and the error handler
will be evaluated.
Notice that the above *error* function takes a single argument: msg which, when
the *error* function is evaluated, is passed a string describing the error which has
occurred; the above function then proceeds to print this message to the command
line. This particular function emulates the standard AutoCAD error handler.
Note that the *error* symbol is declared as a local function (localised) - this
ensures that the default AutoCAD error handler is restored following completion of the
program. For more information on localising symbols, see my tutorial on Localising
Variables.

A More Professional Error Handler...


At this point you might have noticed that upon pressing Esc at the prompt, above the
error handler will print a message similar to:
error: Function cancelled
Of course, many users will regularly press Esc to exit a program, so a developer would
want to suppress this error message in order to better emulate the behaviour of
standard AutoCAD commands.
However, at the same time, we would also want to print any other critical error
messages to the command line when an error has occurred outside of the user's
control.

To achieve this, we can define the *error* function in the following way:
(defun c:test ( / *error* )

(defun *error* ( msg )


(if (not (member msg '("Function cancelled" "quit / exit
abort")))
(princ (strcat "\nError: " msg))
)
(princ)
)

(rtos (getreal "\nPress Esc to exit, press Enter to force an


error ..."))
(princ)
)
The above if statement simply says:
"If the error message is neither "Function cancelled" nor "quit / exit abort", then
print the message."
Now, upon testing the above code, should the user hit Esc at the prompt, the error
handler will not print an error message; however, if the user hits Enter at the prompt,
the rtos function is supplied with a nil argument and the error handler will print the
relevant error message.

Resetting the User Environment


Sometimes programs will change system variables during execution to achieve certain
results; however, if the user presses Esc at some point after a system variable has
been altered and not yet reset, without the use of an appropriate error handler the
system variable will not be reset to its original value.

We can reset any settings changed by the program through the use of a user-defined
error handler, as the following example demonstrates:

(defun c:test ( / *error* osm )

(defun *error* ( msg )


(if osm (setvar 'osmode osm))
(if (not (member msg '("Function cancelled" "quit / exit
abort")))
(princ (strcat "\nError: " msg))
)
(princ)
)

(setq osm (getvar 'osmode))


(setvar 'osmode 0)
(rtos (getreal "\nPress Esc to exit, press Enter to force an
error ..."))

(setvar 'osmode osm)


(princ)
)
The above code will first assign the current setting of the OSMODE system variable to a
local variable (osm) before setting the system variable to 0. The program will then
restore the original setting following the prompt.
Should the user hit Esc (or Enter) at the prompt, the locally defined *error* function
is evaluated.
The error handler tests the local variable osm for a non-nil value, and, should the
original setting of the OSMODE system variable be available, the system variable is reset
to this value.

Restoring the Previous Error Handler


In all the examples featured in this tutorial, I have localised the *error* symbol. This
ensures that, following completion of the program, the *error* symbol reverts to the
value it held before the program was evaluated (of course this value may be [and
usually is] nil).

We can witness this behaviour by considering the following code:

(defun *error* ( msg )


(princ "\n*error* outside of test program.")
(princ)
)

(defun c:test ( / *error* )

(defun *error* ( msg )


(princ "\n*error* inside of test program.")
(princ)
)

(getstring "\nPress Esc to force an error...")


(princ)
)
Upon calling the program with test at the command line and pressing Esc at the
prompt, the following message will be displayed:
*error* inside of test program.
Now, due to the localisation of the *error* symbol in the program, the *error* symbol
will now revert to its previous value: that which is defined outside of the program's
function definition.

So, if we now type at the command line:

(itoa nil)

The previously defined error handler will evaluate, to display the message:
*error* outside of test program.
To reset to the default error handler, we can clear the value of the *error* symbol:
(setq *error* nil)
If AutoCAD encounters an error during program execution and the *error* symbol
is nil, the default, in-built error handler will be evaluated to print the error message
as mentioned earlier in this tutorial.

An Alternative to Function Localisation


Here I will demonstrate another method to reset the previous error handler following
program completion, without localising the *error* function symbol. Some error
handling tutorials that I have witnessed utilise this method, but note that it will
perform in exactly the same way as the localisation of the *error* symbol, moreover,
in my opinion the localisation is a cleaner and more readable solution.

Consider the following code:

(defun c:test ( / myerr olderr )

(defun myerr ( msg )


(setq *error* olderr)
(princ "\n*error* inside of test program.")
(princ)
)

(setq olderr *error*


*error* myerr
)
(getstring "\nPress Esc to force an error...")

(setq *error* olderr)


(princ)
)

I'm sure that you would concur that the above alternative method is far less succinct
than a simple symbol localisation; however, let us dissect the code to reveal the
process that is occurring.

First, we define a function myerr taking a single string argument: msg. This function
will act as our redefined error handler.

Next, we have these lines:

(setq olderr *error*


*error* myerr
)
Here, we are assigning the current function defintion held by the *error* symbol to a
local variable: olderr, and pointing the *error* symbol to our new function
definition: myerr.
This means that if the program encounters an error and the *error* symbol is
evaluated, our locally defined function myerr will be evaluated.
Now, since we are not localising the *error* symbol, the previous definition
of *error* must be restored 'manually'. This needs to occur not only at the end of the
program but also within the myerr function so that, should the program be aborted via
the error handler, the previous error handler defined is still restored.

This restoration is accomplished by the line:

(setq *error* olderr)


Hence assigning the previously stored function definition to the *error* symbol.

Further Information
The Visual LISP IDE Help Documentation offers further information regarding error
handling in AutoLISP - be sure to read the following topics:

AutoLISP Reference » AutoLISP Functions » E Functions » *error*


AutoLISP Developer's Guide » Using the AutoLISP Language » AutoLISP Basics »
Error Handling in AutoLISP
For an introduction into using the Visual LISP IDE, see my tutorial: An Introduction to
the Visual LISP IDE.

Mapcar & Lambda


In my experience, the mapcar and lambda functions are two of the least understood
functions in the AutoLISP programming language, however, when understood and
used correctly, they can replace superfluous code and are powerful functions for
dealing with lists.

The Mapcar Function


Put simply, mapcar will evaluate a function on every element of one or more lists and
return a list of the result of each such evaluation.
The mapcar function is used in the following way:
(mapcar <function> <list-1> <list-2> ... <list-n>)
Where function is a function to be evaluated on each item in the supplied list(s); this
can be any function, user-defined or otherwise, taking any number of arguments.
list-1 ... list-n are a number of lists equal to the number of arguments required
by the function to be evaluated. Hence if used with a function requiring a single
argument, such as strcase (without the case flag), only one list need be supplied.

Let me clarify this explanation with an example.


Example 1
Assume we have the following list of strings:

("adam" "ben" "claire" "david")

Suppose we wish to convert each of these strings into uppercase (capitals).

We could approach this task in a number of ways, for example, using


the foreach function to shuffle through the list and create a new list of uppercase
strings:
(foreach str (reverse '("adam" "ben" "claire" "david"))
(setq lst (cons (strcase str) lst))
)
The resultant value of the lst variable would then be:
_$ lst
("ADAM" "BEN" "CLAIRE" "DAVID")
However this same task can be accomplished with more concision using
the mapcar function:
_$ (mapcar 'strcase '("adam" "ben" "claire" "david"))
("ADAM" "BEN" "CLAIRE" "DAVID")
Since the strcase function requires a single argument (a string) when converting to
uppercase, only one list is supplied: the list of strings to be converted to uppercase.
The result: mapcar evaluates the strcase function on each element of the supplied list
- this is equivalent to:
_$ (list (strcase "adam") (strcase "ben") (strcase "claire") (strcase
"david"))
("ADAM" "BEN" "CLAIRE" "DAVID")
Notice also that mapcar has been supplied with the function strcase prefixed with an
apostrophe so that the strcase symbol is not evaluated, but rather treated as an
argument for the mapcar function. This could also be achieved using the quote function
in the following way:
_$ (mapcar (quote strcase) (quote ("adam" "ben" "claire" "david")))
("ADAM" "BEN" "CLAIRE" "DAVID")
Or using the function function to declare strcase as a function:
_$ (mapcar (function strcase) (quote ("adam" "ben" "claire"
"david")))
("ADAM" "BEN" "CLAIRE" "DAVID")

Functions with More than One


Argument
In the example above, the strcase function is demonstrated, and only one list is
supplied as strcase only requires a single argument when converting to uppercase;
but what if we want to use a function that requires multiple arguments?
Example 2
Consider the following example to add the items of two lists:

_$ (mapcar '+ '(1 2 3 4 5) '(3 4 5 6 7))


(4 6 8 10 12)
Here mapcar is supplied with the + function, which takes any number of numerical
arguments and adds them together. Hence in the above example, mapcar will evaluate
the + function on each member of each list and return a list of the results:
(4 6 8 10 12) = ((+ 1 3) (+ 2 4) (+ 3 5) (+ 4 6) (+ 5 7))
If the supplied lists are unequal in length, mapcar will cease evaluation when the
shortest list has been processed, e.g.:
_$ (mapcar '+ '(1 2 3 4 5) '(3 4 5))
(4 6 8)

The Lambda Function


Let's go back to our original list of strings:

("adam" "ben" "claire" "david")

Suppose that we wish to convert each string to 'Titlecase' such that the first letter of
each word is capitalised, for example:

("Adam" "Ben" "Claire" "David")


We could again implement a method using the foreach function, and shuffle through
our list:
(foreach str (reverse '("adam" "ben" "claire" "david"))
(setq lst (cons (strcat (strcase (substr str 1 1)) (substr str
2)) lst))
)
But we could also use mapcar to avoid the need to reverse the list and involve the
extra variables. However, there is no function in LISP that allows us to capitalise the
first letter of a word, so how to can we provide mapcar with a function to evaluate?
Since the function supplied to mapcar is arbitrary, one possible solution could be to
define a function ourselves and supply it:
(defun titlecase ( str )
(strcat (strcase (substr str 1 1)) (substr str 2))
)

_$ (mapcar 'titlecase '("adam" "ben" "claire" "david"))


("Adam" "Ben" "Claire" "David")
Here we have defined a function titlecase which takes a single argument str, and
returns the value of this argument with the first letter capitalised.
But this means that we now have an extra function definition in our code that may
only be used once and could potentially be located elsewhere in the code, making it
far less readable. A far better way to accomplish this task would be to use
the lambda function.
The lambda function defines an anonymous function (a defun without a name if you
like) and is usually used when the overhead of defining a new function is not justified
- as in our case.
(mapcar '(lambda ( s ) (strcat (strcase (substr s 1 1)) (substr s
2))) '("adam" "ben" "claire" "david"))
The code is now far more comprehensible since the operations performed by the
anonymous lambda function are in-line with the flow of the code.

Further Examples
The mapcar and lambda functions are best illustrated and understood using examples,
so here are a few more for you to study:

Example 3
Adding one to each element of a list:

_$ (mapcar '1+ '(1 2 3 4 5))


(2 3 4 5 6)

Example 4
Adding two to each element of a list, using a defined function:

(defun addtwo ( x ) (+ x 2))

_$ (mapcar 'addtwo '(1 2 3 4 5))


(3 4 5 6 7)
Using an anonymous lambda function:
_$ (mapcar '(lambda ( x ) (+ x 2)) '(1 2 3 4 5))
(3 4 5 6 7)

Example 5
Concatenating a string with an integer, using a defined function taking two
arguments:

(defun join ( str int ) (strcat str (itoa int)))

_$ (mapcar 'join '("a" "b" "c") '(1 2 3))


("a1" "b2" "c3")
Using an anonymous lambda function taking two arguments:
_$ (mapcar '(lambda ( str int ) (strcat str (itoa int))) '("a" "b"
"c") '(1 2 3))
("a1" "b2" "c3")
Example 6
One final example to scramble the brain: a function to return the average point of a
list of points:

(defun averagepoint ( lst / n )


(setq n (float (length lst)))
(mapcar '/ (apply 'mapcar (cons '+ lst)) (list n n n))
)
Notice that the above function exploits the fact that mapcar will cease evaluation when
the shortest list is exhausted, since calling the function with 3D points will result in a
3D average point, and supplying 2D points will result in a 2D average point:
_$ (averagepoint '((2 3 1) (2 4 1) (1 5 1)))
(1.66667 4.0 1.0)

_$ (averagepoint '((2 3) (2 1) (5 1)))


(3.0 1.66667)
Observe that this behaviour could also be obtained by using a lambda function to
perform the division:
(defun averagepoint ( lst / n )
(setq n (float (length lst)))
(mapcar (function (lambda ( x ) (/ x n))) (apply 'mapcar (cons '+
lst)))
)

Further Reading
If this tutorial has sparked your interest in all things mapcar and lambda, the following
publication from the Autodesk University written by Darren Young also provides an
outline of mapcar, lambda and the apply function:
LISP: Advance Yourself Beyond A Casual Programmer

Selection Set Processing


There are several ways to iterate over all objects in a selection set, some methods are
more intuitive, others are more efficient.

Below I will provide some examples to demonstrate a variety of different methods and
I'll try my best to give a brief explanation on how each method works and the
efficiency of its operation.

In all of the following examples, the user will be prompted to make a selection of
objects and the example program will iterate over the selection set, printing the entity
type of each entity, (or object name of the VLA-Object in the case of the Visual LISP
example).
Many of the examples have been expanded to use several variables for simplicity and
readability and could subsequently be shortened by nesting expressions, but that is
not the intention of this tutorial.

Contents
 Method 1: while
 Method 1a: Reverse while
 Method 2: repeat
 Method 2a: Reverse repeat
 Method 3: ssnamex
 Method 4: ssdel
 Method 4a: Reverse ssdel
 Method 5: Visual LISP ActiveX

Method 1: while
SELECT ALL
(defun c:test1 ( / e i n s x )
(if (setq s (ssget))
(progn
(setq i 0
n (sslength s)
)
(while (< i n)
(setq e (ssname s i)
x (cdr (assoc 0 (entget e)))
i (1+ i)
)
(print x)
)
)
)
(princ)
)
The above function utilises a while loop to iterate over the selection set. A counter
variable i is initialised at 0, and a limiting variable n is assigned the size of the
selection set, i.e. the number of items in the set.
The test condition for the while loop will evaluate to T (true) providing the counter is
less than the number of items in the set.
The counter variable is then sequentially incremented within the while loop, ensuring
termination of the loop when all entities have been processed.
Note that all selection sets have a zero-based index, and hence the first entity in the
selection resides at index 0, with the last entity at index sslength - 1 (i.e. the
number of items in the selection set minus one).

Method 1a: Reverse while


SELECT ALL
(defun c:test1a ( / e i s x )
(if (setq s (ssget))
(progn
(setq i (1- (sslength s)))
(while (<= 0 i)
(setq e (ssname s i)
x (cdr (assoc 0 (entget e)))
i (1- i)
)
(print x)
)
)
)
(princ)
)

This example uses the same logic as the preceding example, except the counter
variable is initialised at the last index in the set, and decremented within the loop until
it reaches zero.

This approach removes the need for the 'restricting variable' as required by the
previous example.

Method 2: repeat
SELECT ALL
(defun c:test2 ( / e i s x )
(if (setq s (ssget))
(progn
(setq i 0)
(repeat (sslength s)
(setq e (ssname s i)
x (cdr (assoc 0 (entget e)))
i (1+ i)
)
(print x)
)
)
)
(princ)
)
The above function also uses a counter variable i which is incremented within
the repeat loop to iterate over the set, however, since the number of items in the set
can be determined before the loop is executed (using sslength), this more
efficient repeat loop may be utilised to iterate over the set a number of times equal to
the number of items in the set.

Why more efficient? Because there is no longer a test condition to be evaluated on


each pass of the loop.

Method 2a: Reverse repeat


SELECT ALL
(defun c:test2a ( / e i s x )
(if (setq s (ssget))
(repeat (setq i (sslength s))
(setq e (ssname s (setq i (1- i)))
x (cdr (assoc 0 (entget e)))
)
(print x)
)
)
(princ)
)
Analogous to the reversed example of the while loop (Method 1a), this rather more
concise (but perhaps less readable) example will initialise the counter variable i at the
number of items in the set, whilst using the return of this setq expression to supply
the repeat function with the number of iterations for the loop.
The counter variable is then immediately decremented within the loop (so as to start
the processing at the (sslength - 1)th entity), and again, the return of
this setqexpression is supplied to the ssname function.

This example has a negligible difference in efficiency to the previous example, but is
more concise.

Method 3: ssnamex
SELECT ALL
(defun c:test3 ( / s )
(if (setq s (ssget))
(foreach e (ssnamex s)
(if (= 'ename (type (cadr e)))
(print (cdr (assoc 0 (entget (cadr e)))))
)
)
)
(princ)
)
The ssnamex function can be used to return information about how a selection set was
collected. This information also includes all of the entity names in the selection.
The above example will iterate over the list returned by ssnamex and process the
entities contained therein.

However, do not be deceived into thinking that this method is efficient simply because
it looks more concise than the previous examples...

The ssnamex function is a process intensive function and is slow to evaluate,


furthermore, the foreach loop may iterate a number of times greater than the number
of items in the set as the ssnamex function includes additional information about any
window selections (or other selection methods) that the user may have used.

Method 4: ssdel
SELECT ALL
(defun c:test4 ( / e s )
(if (setq s (ssget))
(while (setq e (ssname s 0))
(print (cdr (assoc 0 (entget e))))
(ssdel e s)
)
)
(princ)
)
This method iterates over a selection set by sequentially removing the first entity from
the set and exploiting the inherent behaviour of the selection set.

A selection set may be viewed as an array of entities. Each entity occupies a position,
or index, in the array, with the first entity occupying index 0.

When an entity is removed from the selection set, so as not to have a 'gap' in the
array, all entities occupying the positions above the removed entity are shifted down
to occupying the lower positions, thus filling the 'gap' created by the removed entity.

In this way, there will always be an entity occupying index 0 for as long as the
selection set is not empty.

However, the process of continually shifting the entities to new indexes in the
selection set is unnecessary and largely inefficient and so this method should be
avoided when processing selection sets containing many objects.

Method 4a: Reverse ssdel


SELECT ALL
(defun c:test4a ( / e i s )
(if (setq s (ssget))
(progn
(setq i (sslength s))
(while (setq e (ssname s (setq i (1- i))))
(print (cdr (assoc 0 (entget e))))
(ssdel e s)
)
)
)
(princ)
)
Similar to the above technique of using the ssdel function to sequentially remove the
first entity from the selection set until no entities remain (Method 4), this method will
remove the entity at the (sslength - 1)th index in the selection set, therefore
avoiding the inefficiency introduced by shifting each entity to a lower index.
However, although the termination of the while loop in this example relies on the
selection set becoming empty after all entities have been processed, Method
1a andMethod 2a both demonstrate that removing an entity from the set is not
required in order to process the selection set in this manner, and hence these
methods are comparatively more efficient than the use of ssdel.

Method 5: Visual LISP ActiveX


SELECT ALL
(defun c:test5 ( / s )
(if (ssget)
(progn
(vlax-for o (setq s (vla-get-activeselectionset (vla-get-
activedocument (vlax-get-acad-object))))
(print (vla-get-objectname o))
)
(vla-delete s)
)
)
(princ)
)
(vl-load-com) (princ)
This method is useful when the program needs to operate on the VLA-Object
representations of the entities in the selection, and avoids the need to use the vlax-
ename->vla-object function to convert each entity to its equivalent VLA-Object
representation.

The method retrieves the ActiveSelectionSet Collection from the SelectionSets


Collection in the drawing and iterate over the VLA-Objects found therein.

Note however, that when using this method, the VLA SelectionSet Object should be
deleted from the SelectionSets Collection after use, as there is a limit to the number
of SelectionSets permitted in this Collection.

The Apostrophe and the


Quote Function
Contents
 Introduction
 The Apostrophe
 Constant Data
 Variable Data
 Function Arguments
 The Quote Function
 Run-time Evaluation
 Function References

Introduction
In my experience, very little documentation exists describing the purpose of the
apostrophe symbol in AutoLISP, and the explanations that I have encountered in
existing tutorials are usually quite brief and almost bypass the main purpose of this
operator.

Consequently, I have found that many novice AutoLISP programmers are often
confused when faced with this symbol in existing code, and can also be unaware of
when the apostrophe may and may not be used when writing code.
I have therefore put together an explanation that is hopefully comprehensible,
detailing the purpose of both the apostrophe operator and the
AutoLISP quote function, and the consequences of their use.

The Apostrophe
The apostrophe or single-quote character marks an expression or symbol as a literal
expression, to be taken at 'face-value' and not to be evaluated by the AutoLISP
interpreter.

The quoted expression may be any form of AutoLISP data, though the apostrophe is
usually used with lists or symbols, since most other forms of AutoLISP data (strings,
integers, reals) are already literal constants and hence do not require its use.

Constant Data
Expressions that contain constant or fixed data (that is, data that is unchanged when
evaluated) may be quoted as literal expressions, as there are no symbols within the
expression to be evaluated and consequently change the data content.

For example, consider the following list of integers:

_$ (list 1 2 3 4 5)
(1 2 3 4 5)
The above list is constructed by passing each integer as an argument to
the list function. The list function will then evaluate each of the supplied arguments
and will return a list containing all arguments in the order in which they were passed
to the function.
However, since each integer is a constant, there is no need for the data to be
evaluated by the list function, as the result will be unchanged.

Therefore, this list may quoted as a literal expression using the apostrophe to yield
the same result:

_$ '(1 2 3 4 5)
(1 2 3 4 5)

Similarly, consider the operation of constructing a list of dotted pairs:

_$ (list (cons 1 "a") (cons 2 "b") (cons 3 "c"))


((1 . "a") (2 . "b") (3 . "c"))
Here, each integer and string pair are passed as arguments and evaluated by
the cons function, which returns a dotted pair (since two atoms have been supplied);
each of the resulting dotted pairs are then passed as arguments and evaluated by
the list function to return the list as shown.
However, at each stage, the innermost data remains entirely unchanged, and
consequently, every evaluation of the cons & list function is redundant and
introduces inefficiency into the code.

The list of dotted pairs of constant data could equivalently be quoted as a literal
expression using the apostrophe to yield the same result without the evaluation of
three functions:

_$ '((1 . "a") (2 . "b") (3 . "c"))


((1 . "a") (2 . "b") (3 . "c"))

To offer a practical example, consider the list of dotted pairs which may be supplied to
the ssget function as the filter list argument.

The following example will retrieve a selection set of all Closed LWPolyline objects in
the drawing database:

(ssget "_X" '((0 . "LWPOLYLINE") (-4 . "&=") (70 . 1)))

Since the above filter list contains only constant data, the list may be quoted as a
literal expression using the apostrophe.

More information on the arguments available for use with the ssget function and the
filter list operators as used in this example can be found in my ssget Function
Reference.

Variable Data
There are of course limitations on when the apostrophe may be used to quote
AutoLISP data. One such limitation is when the data is not constant, but contains
symbols or expressions which, when evaluated, will yield different resulting data.

Consider the following example:

_$ (setq x 5)
5
_$ (list 1 2 3 4 x)
(1 2 3 4 5)
Here, the symbol x is assigned an integer value of 5; this symbol and the integers 1 to
4 are then passed as arguments to the list function.
Since each supplied argument is evaluated by the list function, the symbol x is
evaluated to yield the value 5, and the list is returned containing the evaluated value
of the symbol, as shown above.

However, observe the result when the list is quoted using the apostrophe:

_$ (setq x 5)
5
_$ '(1 2 3 4 x)
(1 2 3 4 X)
Since the apostrophe marks the list as a literal expression, the content of the list is
not evaluated by the AutoLISP interpreter, and the symbol x remains as a symbol in
the list.

This demonstrates what is meant by the terms 'literal' & 'face-value'.

Expanding on our previous practical example, let's say that we wish to prompt the
user to specify the name of a layer containing the Closed LWPolylines to be selected
by the ssget expression:
(if (snvalid (setq lay (getstring t "\nSpecify layer: ")))
(ssget "_X" (list '(0 . "LWPOLYLINE") '(-4 . "&=") '(70 . 1)
(cons 8 lay)))
)
Since the filter list now contains variable data as a result of the lay variable, the list
can no longer be quoted as a literal expression, but must be constructed using
the list function.
However, since three of the four dotted pairs contained in the filter list still contain
constant data, these dotted pairs may be quoted as literal expressions using the
apostrophe, with the final dotted pair constructed by passing the
two evaluated arguments to the cons function.

Function Arguments
Note that in the above examples the quoted lists would almost always be supplied as
arguments to other functions: whether that function is setq, to assign the data to a
variable; list, when constructing a list containing lists of constant data (as per the
last example); or perhaps ssget, as shown in the first selection example supplying
the ssget function with a quoted filter list argument; to name a few.

However, in general, the quoted argument need not necessary be a list, as the
following example demonstrates:

_$ (mapcar '+ '(1 2 3 4 5) '(6 7 8 9 10))


(7 9 11 13 15)
Here, the apostrophe is used to mark the + function as an argument for
the mapcar function, with the two list arguments also quoted since they contain
constant data.
Consider that if this function argument were not quoted, the function symbol would be
evaluated by the mapcar function to yield the pointer to its function definition, and
the mapcar function would consequently return a 'bad function' error.
The same logic applies when supplying an anonymous lambda function as the
functional argument to be evaluated by mapcar on every item in the given list(s), as
demonstrated by the following example calculating the midpoint between two points:
_$ (mapcar '(lambda ( a b ) (/ (+ a b) 2.0)) '(12.3 45.6 78.9) '(32.1
65.4 98.7))
(22.2 55.5 88.8)
For more information describing how the mapcar function operates, see my Mapcar &
Lambda tutorial.

To offer another example, consider the following getvar expression:


_$ (getvar 'osmode)
255
Here, the symbol osmode is quoted to ensure that the symbol is not evaluated when
passed as an argument to the getvar function. Since both
the getvar & setvarfunctions accept either a string or symbol argument, this
expression will then return the value of the OSMODE system variable, as demonstrated
above.
Consider that if the symbol argument was not quoted, the getvar function would
evaluate the argument to yield any value that has been assigned to the symbol in the
active document namespace (e.g. via a setq or set expression); if the symbol holds
no value (or indeed, holds a value other than a valid string or symbol argument),
the getvar expression would consequently error with a 'bad argument type: (or
stringp symbolp)' error.

Finally, observe the following expression which invokes the Visual LISP
ActiveX getboundingbox method (for example, as used by my Bounding
Box & Selection Set Bounding Box functions):
(if (setq ent (car (entsel)))
(vla-getboundingbox (vlax-ename->vla-object ent) 'pt1 'pt2)
)
The getboundingbox method requires three parameters: the VLA-Object whose
bounding box is to be calculated, and two symbol parameters to hold the values
output by the method.
The utilisation of output parameters enables the method to return multiple values, as
opposed to the single value returned following function evaluation (which happens to
be nil for this method).

When invoking the method, the symbol parameters are quoted to ensure that the
symbol itself is supplied as an argument to the method, rather than the value
obtained when such symbol is evaluated. Following successful evaluation of the
method, the supplied symbols are assigned the lower-left & upper-right WCS
coordinates describing the bounding box of the supplied VLA-Object.

The Quote Function


The AutoLISP quote function is the functional equivalent of the apostrophe symbol.
This function accepts a single argument which may be any AutoLISP expression and
simply returns the supplied expression without evaluating it.
As such, the quote function could be used in place of the apostrophe in our first
example in the following way:
_$ (quote (1 2 3 4 5))
(1 2 3 4 5)
Here, the list of integers is passed as an argument to the quote function, and, instead
of the first item in the list being evaluated as a function and resulting in a 'bad
function' error (as would occur if the list was evaluated), the supplied argument
is not evaluated, but simply returned by the quote function.

Similarly, the mapcar expressions from our previous examples could also be rewritten
using the quote function in place of the apostrophe:
_$ (mapcar (quote +) (quote (1 2 3 4 5)) (quote (6 7 8 9 10)))
(7 9 11 13 15)
However, where the second mapcar example is concerned, the lambda function may be
optimised when the code is compiled to a VLX or FAS file by substituting
the function function in place of the apostrophe or quote function:
_$ (mapcar (function (lambda ( a b ) (/ (+ a b) 2.0))) (quote (12.3
45.6 78.9)) (quote (32.1 65.4 98.7)))
(22.2 55.5 88.8)
The function function is identical to the quote function with the exception that it
instructs the Visual LISP compiler that the enclosed symbol or lambda expression is a
function argument which may be linked & optimised during compilation.
Since lambda expressions are defined at run-time, the Visual LISP compiler cannot
optimise these expressions during compilation, as is possible with built-in AutoLISP
functions or named functions defined with defun. Similarly, when quoted using the
apostrophe or quote function, the compiler treats the quoted lambda expression simply
as literal data, without linking or optimising the function.
However, by using function, the compiler is instructed to optimise the lambda function
during compilation to yield similar performance to built-in or named functions during
evaluation.
The function function can also be used with symbols defining any built-in or named
function, however, since these functions are already optimised when compiled, there
is very little gain in performance, if any.
Run-time Evaluation
Since the quote function operates in an identical manner to the apostrophe, it may
appear that this function is redundant since apparently the apostrophe could be used
in its place with far fewer keystrokes.
However, there are situations in which the quote function must be used in place of the
apostrophe to obtain the desired result.
One such example is literal expressions that are defined at run-time. (another
is quines...)

Consider the following simplified example:

_$ (eval (list 'defun-q 'fun '( / lst ) (list 'setq 'lst (list 'quote
(list 0.0 (* pi 0.5) pi (* pi 1.5))))))
FUN
When evaluated, the above expression will define the function fun which contains a
single setq expression assigning a list of four numerical items (multiples of π) to the
local variable lst.
I have intentionally defined the above function using a defun-q expression so that the
result of the function definition may be revealed when the symbol fun is evaluated:
_$ fun
((/ LST) (SETQ LST (QUOTE (0.0 1.5708 3.14159 4.71239))))
Following definition of the function, observe that the setq expression is now assigning
a literal list to the symbol lst, without repeated calculation of the list items, and more
importantly, without any loss of precision of each item (the displayed values are
truncated when displayed at the console for ease of viewing, however, these values
are still stored to the maximum level of precision available).
Consider that in order to obtain the same result using a quoted literal list, each
irrational multiple of π would need to be expressed in the code to around 15 decimal
places to achieve the same precision.

Alternatively, the function could be defined such that the arithmetic expressions are
included in the function definition:

_$ (defun-q fun ( / lst ) (setq lst (list 0.0 (* pi 0.5) pi (* pi


1.5))))
FUN

_$ fun
((/ LST) (SETQ LST (LIST 0.0 (* PI 0.5) PI (* PI 1.5))))
However, with the function defined in this way, the multiples of π are calculated and
re-calculated unnecessarily every time the function is evaluated, introducing
inefficiency. For the above example, this loss in performance is of course negligible
and one must also consider the negative effect on the readability of the code when
opting to define the function at run-time; however, if the list were to contain
potentially thousands of entries, the repeated calculation would soon become
noticeable.
Hence, this construct allows large literal lists which could be unmanageable to include
directly in the program source code to be constructed at run-time whilst
simultaneously retaining accuracy and improving efficiency.

To offer a concrete example of the quote function being used in this manner, consider
my GrText function. The quoted vector list which appears at the top of this function
definition is already quite large, but without the use of the run-time redefinition, the
literal list would be twice as large!

Function References
Below are links to the formal documentation for the various functions described
above.
As far as I am aware, there is no formal documentation for the apostrophe.
Quote Reference
Function Reference

quote (AutoLISP)

Returns an expression without evaluating it

Supported Platforms: Windows and Mac OS

Signature

(quote expr)

expr
Type: Integer, Real, String, List, Symbol, File, Subroutine, Ename (entity name), T, or nil

An AutoLISP expression.

Return Values
Type: Integer, Real, String, List, Symbol, File, Subroutine, Ename (entity name), T, or nil

The expr argument.

Examples

(quote a)

The previous expression can also be written as 'a. For example:


!'a

(quote (a b))

(A B)

Related Concepts

 Symbol-Handling Functions Reference (AutoLISP)

Related Reference

 list (AutoLISP)

unction (AutoLISP/Visual LISP IDE)

Tells the Visual LISP compiler to link and optimize an argument as if it were a built-in function

Supported Platforms: Windows only

Signature

(function symbol | lambda-expr)

symbol
Type: Symbol

A symbol naming a function.

lambda-expr
Type: Subroutine or List

An expression of the following form:

(LAMBDA arguments {S-expression}*)

Return Values
The result of the evaluated expression.

Remarks
The function function is identical to the quote function, except it tells the Visual LISP
compiler to link and optimize the argument as if it were a built-in function or defun.
Compiled lambda expressions that are quoted by function will contain debugging
information when loaded into the Visual LISP IDE.

Examples
The Visual LISP compiler cannot optimize the quoted lambda expression in the following
code:

(mapcar

'(lambda (x) (* x x))

'(1 2 3))

After adding the function function to the expression, the compiler can optimize
the lambda expression. For example:

(mapcar

(function (lambda (x) (* x x)))

'(1 2 3))

Related Concepts

 Function-Handling Functions Reference (AutoLISP)

Related Reference

 apply (AutoLISP)
 defun (AutoLISP)
 lambda (AutoLISP)

Building Association Lists: A


Simple Block Counter
Contents
 Introduction
 A Basic Framework
 Defining a Function
 Obtaining a Selection
 Processing the Selection
 Some Background on Association Lists
 What is an Association List?
 Constructing a Dotted Pair
 Constructing an Association List
 Retrieving an Item from an Association List
 Substituting an Item in an Association List
 Building the Block Counter
 Displaying the Results
 The Final Program

Introduction
This tutorial provides a step-by-step explanation of how to construct a simple block
counter program in AutoLISP, which will prompt the user for a selection of block
references and will output the quantities of each block in the selection to the AutoCAD
command-line.

The tutorial will demonstrate how to count the blocks by building an appropriate
association list to record the block names and their associated quantities - this
concept may then be applied to other applications which involve recording & updating
items of data.

The tutorial is aimed at those with a basic understanding of the AutoLISP language
and syntax, and, unlike most other tutorials written for beginners, the end result may
actually prove useful in real-world drafting work.

A Basic Framework
In the following steps, we shall first construct a basic framework for the block counter
program: defining a function which may be invoked from the AutoCAD command-line,
obtaining a selection of blocks to be counted, and constructing a means of iterating
over the selection.

Defining a Function
As the very first step, we shall define a function c:myblockcounter which will perform
all of the operations of the block counter:
SELECT ALL
(defun c:myblockcounter ( / ) ;; Define function
) ;; end defun
By prefixing the function name with c: the function may be evaluated directly at the
AutoCAD command-line using the command which follows this c: prefix,
i.e. myblockcounter.
A defun expression cannot be empty, so let us now include the expressions to be
evaluated when the function is invoked.
Obtaining a Selection
The first operation to be performed by the function is to obtain a selection of blocks to
be counted - for this we will use the ssget function.
The ssget function is a general selection function which may be used to obtain a
selection of multiple objects either from a user or automatically (a full reference
detailing all of the options offered by this function may be found here).
SELECT ALL
(defun c:myblockcounter ( / ) ;; Define function
(ssget) ;; Prompt the user to make a selection and return the
selection set if successful
) ;; end defun
Upon running the above program the user is prompted for a selection of objects, and,
if a valid selection is made, the function will return a pointer to the selection set,
otherwise, the function will return nil.
Notice that these values are returned at the command-line because
the ssget expression is the last expression evaluated within the defun expression and
therefore any value returned by the ssget function is then returned by
the defun expression.
However, as it stands, we cannot use the selection set returned by ssget, as the value
is not currently assigned to a variable and so cannot be referenced elsewhere in the
program. So we will now assign the value returned by ssget to a local variable sel.
SELECT ALL
(defun c:myblockcounter ( / sel ) ;; Define function
(setq sel ;; Assign the value returned by the following
expression to the symbol 'sel'
(ssget) ;; Prompt the user to make a selection and return the
selection set if successful
) ;; end setq
) ;; end defun
Note that the symbol sel has also been declared as a variable local to the
function c:myblockcounter within the symbol list for the defun expression - to
understand why this is important, see my tutorial on Localising Variables.
The current code still allows the user to select any object, so we can refine this
selection to only permit block references using an appropriate ssget filter list
argument:
SELECT ALL
(defun c:myblockcounter ( / sel ) ;; Define function
(setq sel ;; Assign the value returned by the following
expression to the symbol 'sel'
(ssget ;; Prompt the user to make a selection and return the
selection set if successful
'((0 . "INSERT")) ;; Filter the selection to block
references only (INSERTs)
) ;; end ssget
) ;; end setq
) ;; end defun
Finally, before we continue to attempt to process the selection of blocks, we should
first check whether the user has actually made a valid selection, or whether the user
has simply dimissed the prompt without selecting any block references.

For this, we can use an if statement:


SELECT ALL
(defun c:myblockcounter ( / sel ) ;; Define function, declare local
variables
(if ;; If the following expression returns a non-nil value
(setq sel ;; Assign the value returned by the following
expression to the symbol 'sel'
(ssget ;; Prompt the user to make a selection and return
the selection set if successful
'((0 . "INSERT")) ;; Filter the selection to block
references only (INSERTs)
) ;; end ssget
) ;; end setq
"Selection valid." ;; Then the selection was valid
"Selection invalid." ;; Else the selection was invalid
) ;; end if
) ;; end defun
Try the above program - if a valid selection is made, the function will return the result
of the 'then' argument ("Selection valid"), otherwise, the 'else' argument will be
returned ("Selection invalid").

Aside: you will note that, in AutoLISP, a conditional expression (such an if statement)
will be validated if the test expression returns any non-nil value - that is, the test
expression doesn't necessarily need to return T or True explicitly for the if statement
to be validated, for example consider the following:
(setq var 1)
(if var
(princ "Do this.")
(princ "Else do this.")
)
Here, the test expression is simply the symbol var - this symbol is evaluated by
the if function to yield any value it may have been assigned. In the above example,
the symbol var is a variable which has been assigned a value of 1. Since 1 is not equal
to nil, the if statement is validated and the 'then' argument will be evaluated.
Only if the test expression returns a value equivalent to nil will the 'else' expression
(if supplied) be evaluated.
Processing the Selection
Now that the function has been defined and we have obtained a selection of blocks
from the user, the program now needs to iterate over the selection to count the
number of occurrences of each distinct block.

For this, we can use Method 2a from my Selection Set Processing tutorial, which uses
a repeat expression to process each item in the set, starting with the item at the
highest index.
So, let us start by incorporating the repeat function into our existing code:
SELECT ALL
(defun c:myblockcounter ( / sel ) ;; Define function, declare local
variables
(if ;; If the following expression returns a non-nil value
(setq sel ;; Assign the value returned by the following
expression to the symbol 'sel'
(ssget ;; Prompt the user to make a selection and return
the selection set if successful
'((0 . "INSERT")) ;; Filter the selection to block
references only (INSERTs)
) ;; end ssget
) ;; end setq
(repeat ;; Repeat the enclosed expressions the following
number of times:
(sslength sel) ;; Return the number of items in the
selection set
) ;; end repeat
) ;; end if
) ;; end defun
Here, the repeat expression constitutes the 'then' argument for the if function; I
have omitted the 'else' argument, as it is not necessary to inform the user that no
objects were selected (they already know this!).
The sslength expression will return the number of items in our selection set sel and
will therefore cause the repeat expression to evaluate any enclosed expressions a
number of times equal to the number of objects selected by the user, hence
processing every selected block reference.

At this point it is worth noting that the sslength expression is the reason that
the if statement must be used: if the variable sel was nil, then (sslength
sel) would return an error (specifically, bad argument type: lselsetp nil), therefore,
the if statement ensures that the expression (sslength sel) is only evaluated if the
variable sel is non-nil and therefore contains a valid selection set.

Continuing with the 'Method 2a' structure, we can define an index variable idx and
access the block reference entity at each index in the selection set:
SELECT ALL
(defun c:myblockcounter ( / idx sel ) ;; Define function, declare
local variables
(if ;; If the following expression returns a non-nil value
(setq sel ;; Assign the value returned by the following
expression to the symbol 'sel'
(ssget ;; Prompt the user to make a selection and return
the selection set if successful
'((0 . "INSERT")) ;; Filter the selection to block
references only (INSERTs)
) ;; end ssget
) ;; end setq
(repeat ;; Repeat the enclosed expressions the following
number of times:
(setq idx ;; Assign the value returned by the following
expression to the symbol 'idx'
(sslength sel) ;; Return the number of items in the
selection set
) ;; end setq
(print ;; Print the following expression to the command-
line (just for testing)
(ssname sel ;; Retrieve the entity at the following
index
(setq idx (1- idx)) ;; Decrement the index
variable (since selection set indexes are zero-based)
) ;; end ssname
) ;; end print
) ;; end repeat
) ;; end if
) ;; end defun
To understand how this structure works, please read the Method 2a section of
my Selection Set Processing tutorial.

If we run the above program, selecting a set of blocks will cause each entity name in
the selection to be printed to the AutoCAD command-line, however, you will notice
something curious: selecting three block references will result in four entity names
being printed to the command-line, with the last entity name repeated e.g.:
SELECT ALL

Command: myblockcounter
Select objects: Specify opposite corner: 3 found

Select objects:

<Entity name: 7ffff7101f0>


<Entity name: 7ffff710200>
<Entity name: 7ffff710290> <Entity name: 7ffff710290>

Do not worry! - This isn't an error with the repeat expression.


The repeat function will evaluate the enclosed expressions a given number of times
and will then return the value that is returned by the last evaluated expression. In our
case, the last evaluated expression is the print expression, which itself will return the
value that is supplied to it (i.e. the entity name).
The if function will return the value returned by either the 'then' or 'else' arguments,
therefore, in our case, this is the value returned by the repeat function (i.e. the entity
name).
Finally, the defun expression will return the value returned by the last expression
evaluated within the function definition - which is of course the value returned by
theif function, and hence the extra entity name.
To avoid returning this value, we simply need to ensure that the last expression
evaluated within the function definition returns nothing (i.e. a null symbol). For this,
we can use either a (princ) or (prin1) expression:
SELECT ALL
(defun c:myblockcounter ( / idx sel ) ;; Define function, declare
local variables
(if ;; If the following expression returns a non-nil value
(setq sel ;; Assign the value returned by the following
expression to the symbol 'sel'
(ssget ;; Prompt the user to make a selection and return
the selection set if successful
'((0 . "INSERT")) ;; Filter the selection to block
references only (INSERTs)
) ;; end ssget
) ;; end setq
(repeat ;; Repeat the enclosed expressions the following
number of times:
(setq idx ;; Assign the value returned by the following
expression to the symbol 'idx'
(sslength sel) ;; Return the number of items in the
selection set
) ;; end setq
(print ;; Print the following expression to the command-
line (just for testing)
(ssname sel ;; Retrieve the entity at the following
index
(setq idx (1- idx)) ;; Decrement the index
variable (since selection set indexes are zero-based)
) ;; end ssname
) ;; end print
) ;; end repeat
) ;; end if
(princ) ;; Suppress the return of the last evaluated expression
(if)
) ;; end defun

As a final step before we construct the association list to record the occurrences of
each block in the selection, we first need to obtain the name of each block.
The block name will be used as the 'key' for each item in the association list, with an
associated integer value corresponding to the number of occurrences of the block
name in the selection.

To obtain any property of an entity, we can query the DXF data stored in the drawing
database for the entity (the entity name is simply a pointer to this DXF data) - to
obtain this data, we use the entget function.
The DXF data returned by entget is itself an association list: a list containing any
number of sublists, with each sublist containing two items of data: a 'key' and its
associated value. Such sublists are known as 'dotted pairs'.
The block name for a block reference entity is the value associated with DXF group 2,
that is, the value associated with the sublist whose first element is the integer 2.
To obtain this item from the DXF data association list, we can use the assoc function
coupled with the cdr to obtain the associated value, which is then assigned to a local
variable blk:
SELECT ALL
(defun c:myblockcounter ( / blk idx sel ) ;; Define function, declare
local variables
(if ;; If the following expression returns a non-nil value
(setq sel ;; Assign the value returned by the following
expression to the symbol 'sel'
(ssget ;; Prompt the user to make a selection and return
the selection set if successful
'((0 . "INSERT")) ;; Filter the selection to block
references only (INSERTs)
) ;; end ssget
) ;; end setq
(repeat ;; Repeat the enclosed expressions the following
number of times:
(setq idx ;; Assign the value returned by the following
expression to the symbol 'idx'
(sslength sel) ;; Return the number of items in the
selection set
) ;; end setq
(setq blk ;; Assign the block name to the variable 'blk'
(cdr ;; Retrieve the value associated with DXF group
2 (the block name)
(assoc 2 ;; Retrieve the DXF group 2 dotted pair
from the following DXF data
(entget ;; Retrieve the list of DXF data for
the following entity
(ssname sel ;; Retrieve the entity at the
following index
(setq idx (1- idx)) ;; Decrement the
index variable (since selection set indexes are zero-based)
) ;; end ssname
) ;; end entget
) ;; end assoc
) ;; end cdr
) ;; end setq
(print blk) ;; Print the block name to the command-line
(just for testing)
) ;; end repeat
) ;; end if
(princ) ;; Suppress the return of the last evaluated expression
(if)
) ;; end defun

Upon testing the above, you will see the block name for each selected block reference
printed to the command-line.

Note that this may return anonymous block names for dynamic block references in the
selection: this is because a dynamic block reference will reference an anonymous
block definition when its dynamic block parameters are altered from those defined in
its original block definition. To convert these anonymous block names to the true
name of the dynamic block, we could use my Effective Block Name functions,
however, this is beyond the scope of this tutorial.

Some Background on Association Lists


Now that we have the basic framework for our block counter program, we will now
construct the main block counting engine: the association list.

What is an Association List?


An association list is typically a list of dotted pairs: each dotted pair has a 'key' as the
first element, and an associated value as the second element. Though, in a general
sense, an association list in AutoLISP may be any list of lists.
Below is a simple example of an association list of dotted pairs, defined literally using
an apostrophe:
(setq alist
'(
("Item 1" . "Value 1")
("Item 2" . "Value 2")
("Item 3" . "Value 3")
)
)

Note that the keys and associated values need not necessarily be strings - since
AutoLISP is dynamically typed, these may be any AutoLISP data type, and
furthermore, items within the association list may also contain data of varying types.

The keys within an association list also do not need to be unique (as an example,
consider the vertex DXF data for an LWPOLYLINE entity), however, it is usually far more
useful if the keys are unique.

Constructing a Dotted Pair


Unlike a standard AutoLISP list, a dotted pair is a special form of list which differs in
the way in which is stored in memory.
Without delving into too much detail, a standard list in AutoLISP is known as a Linked
List. Each item in the list requires two memory locations (registers): the first (known
as the address register) stores the value of the list item; the second (known as the
decrement register) stores a pointer giving the location or address of the address
register of the next item in the list.
To access each register, we have the functions car (Contents of Address Register)
and cdr (Contents of Decrement Register). For a standard list, the car function will
therefore return the first item in the list, and the cdr function will return the
remainder of the list:
_$ (setq lst '(1 2 3 4 5))
(1 2 3 4 5)
_$ (car lst)
1
_$ (cdr lst)
(2 3 4 5)
Dotted pairs differ from standard lists in that rather than occupying two memory
registers for each list item, the key of the dotted pair occupies a single register, and
the associated value occupies a second adjacent register. Therefore, whilst
the car function will still return the first item (the key) of the dotted pair,
the cdr function will now return the second item (the associated value) of the dotted
pair as opposed to a list:
_$ (setq dpair '(1 . 2))
(1 . 2)
_$ (car dpair)
1
_$ (cdr dpair)
2
Similar to how a standard list is constructed, we can construct a dotted pair using
the cons function. When the second argument supplied to the cons function is an atom
(non-list data item), the cons function will return a dotted pair:
_$ (cons 1 2)
(1 . 2)

Constructing an Association List


In the above examples, the association lists were defined as literal expressions by a
preceding apostrophe - this approach is fine for constant data, however, when the
data is unknown and variable, the list must be constructed at run-time.

An association list may be constructed in the same way as a standard list or dotted
pair: using the cons function. When the second argument supplied to the consfunction
is a list, the cons function will add (push) the first argument onto the front of the list:
_$ (cons 1 '(2 3 4 5))
(1 2 3 4 5)

In this way, we can construct an association list by repeatedly pushing dotted pairs
onto a list:

_$ (setq alist (cons '(1 . 2) alist))


((1 . 2))
_$ (setq alist (cons '(3 . 4) alist))
((3 . 4) (1 . 2))
_$ (setq alist (cons '(5 . 6) alist))
((5 . 6) (3 . 4) (1 . 2))
In this example, the variable alist is initially undefined and hence the
symbol alist holds no value and is null. However, since a nil value is equal to an
empty list, the symbol alist is effectively a variable containing an empty list, which
can be passed as an argument to the cons function and then redefined by
the setq function.

Retrieving an Item from an Association List


As demonstrated earlier when retrieving the block name, to obtain an item from an
association list we can use the assoc function:
_$ (assoc "Item 2" alist)
("Item 2" . "Value 2")
The assoc function will return the first item in the association list whose key matches
the key provided.
Given the item returned by assoc (in this example, a dotted pair), we can obtain the
value associated with the key using the cdr function:
_$ (cdr (assoc "Item 2" alist))
"Value 2"

Substituting an Item in an Association List


So far we have demonstrated how to construct a dotted pair, which will be used to
record each block name and the associated quantity of the block in the selection; and
how to construct an association list, which will be used to store the various dotted
pairs.

Finally, it is necessary to understand how to substitute (and hence update) an item in


an association list, so that the quantity associated with each block name in the
association list may be incremented as the blocks are processed.

For this, we will use the subst function.


The subst function will substitute an item in place of all occurrences of another item in
a given list (which does not necessary need to be an association list):
_$ (subst 10 2 '(1 2 3 4 3 2 1))
(1 10 3 4 3 10 1)
Therefore, we can use the subst function to substitute dotted pairs with incremented
quantity values in place of existing dotted pairs in our association list. Since the block
names will be unique within the association list, we do not need to worry about
multiple items being substituted.
_$ (subst '("Block 3" . 2) '("Block 3" . 1) '(("Block 1" . 1) ("Block
2" . 5) ("Block 3" . 1)))
(("Block 1" . 1) ("Block 2" . 5) ("Block 3" . 2))
Building the Block Counter
Now, back to our block counter program -

Before we count the occurrences of each block, let us first demonstrate how we are
going to construct the dotted pairs and association list which will record the block
count data.

We can do this using the methods described above:

SELECT ALL
(defun c:myblockcounter ( / blk idx lst sel ) ;; Define function,
declare local variables
(if ;; If the following expression returns a non-nil value
(setq sel ;; Assign the value returned by the following
expression to the symbol 'sel'
(ssget ;; Prompt the user to make a selection and return
the selection set if successful
'((0 . "INSERT")) ;; Filter the selection to block
references only (INSERTs)
) ;; end ssget
) ;; end setq
(repeat ;; Repeat the enclosed expressions the following
number of times:
(setq idx ;; Assign the value returned by the following
expression to the symbol 'idx'
(sslength sel) ;; Return the number of items in the
selection set
) ;; end setq
(setq blk ;; Assign the block name to the variable 'blk'
(cdr ;; Retrieve the value associated with DXF group
2 (the block name)
(assoc 2 ;; Retrieve the DXF group 2 dotted pair
from the following DXF data
(entget ;; Retrieve the list of DXF data for
the following entity
(ssname sel ;; Retrieve the entity at the
following index
(setq idx (1- idx)) ;; Decrement the
index variable (since selection set indexes are zero-based)
) ;; end ssname
) ;; end entget
) ;; end assoc
) ;; end cdr
) ;; end setq
(setq lst ;; Redefine the 'lst' variable with the
following updated list data
(cons ;; 'Push' a new item onto the front of the list
(cons blk 1) ;; Construct a dotted pair whose
first key is the block name and value is 1
lst ;; The list to which the item should be added
(may be nil)
) ;; end cons
) ;; end setq
) ;; end repeat
) ;; end if
(print lst) ;; Print the association list to the command-line
(just for testing)
(princ) ;; Suppress the return of the last evaluated expression
(print)
) ;; end defun
Most importantly at this stage is to remember to declare our list variable lst as a local
variable to our function c:myblockcounter - since the setq expression is redefining
the lst variable with each iteration, it is vital that the value of this variable is null
before the loop is evaluated, else the data will be compounded for every use of the
function.

Upon testing the above program, we will receive an output similar to the following:

(("Block 1" . 1) ("Block 2" . 1) ("Block 1" . 1) ("Block 1" . 1)


("Block 2" . 1) ("Block 3" . 1))

Therefore we have now demonstrated how to construct a dotted pair for each block
name, and how to build an association list containing such dotted pairs.

To construct the block counter, it only remains to test whether the association list
already contains a dotted pair whose key is equal to the block name being processed,
and if so, increment the associated value, else add the new dotted pair to the
association list.

To achieve this, we will use the assoc and subst functions as described above:
SELECT ALL
(defun c:myblockcounter ( / blk idx itm lst sel ) ;; Define function,
declare local variables
(if ;; If the following expression returns a non-nil value
(setq sel ;; Assign the value returned by the following
expression to the symbol 'sel'
(ssget ;; Prompt the user to make a selection and return
the selection set if successful
'((0 . "INSERT")) ;; Filter the selection to block
references only (INSERTs)
) ;; end ssget
) ;; end setq
(repeat ;; Repeat the enclosed expressions the following
number of times:
(setq idx ;; Assign the value returned by the following
expression to the symbol 'idx'
(sslength sel) ;; Return the number of items in the
selection set
) ;; end setq
(setq blk ;; Assign the block name to the variable 'blk'
(cdr ;; Retrieve the value associated with DXF group
2 (the block name)
(assoc 2 ;; Retrieve the DXF group 2 dotted pair
from the following DXF data
(entget ;; Retrieve the list of DXF data for
the following entity
(ssname sel ;; Retrieve the entity at the
following index
(setq idx (1- idx)) ;; Decrement the
index variable (since selection set indexes are zero-based)
) ;; end ssname
) ;; end entget
) ;; end assoc
) ;; end cdr
) ;; end setq
;; If the block is already recorded in the list:
(if ;; If the following expression returns a non-nil
value
(setq itm ;; Assign the value returned by the
following expression to the symbol 'itm'
(assoc blk lst) ;; Attempt to retrieve a list
item whose first element is equal to the block name
) ;; end setq
;; Update the existing list entry:
(setq lst ;; Redefine the 'lst' variable with the
updated list data
(subst ;; Substitute the following list item in
the list
(cons blk (1+ (cdr itm))) ;; Increment the
number of occurrences recorded for this item in the list
itm ;; The existing item to be substituted
lst ;; The list in which to perform the
substitution
) ;; end subst
) ;; end setq
;; Else add a new entry to the list:
(setq lst ;; Redefine the 'lst' variable with the
following updated list data
(cons ;; 'Push' a new item onto the front of the
list
(cons blk 1) ;; Construct a dotted pair whose
first key is the block name and value is 1
lst ;; The list to which the item should be
added (may be nil)
) ;; end cons
) ;; end setq
) ;; end if
) ;; end repeat
) ;; end if
(print lst) ;; Print the association list to the command-line
(just for testing)
(princ) ;; Suppress the return of the last evaluated expression
(print)
) ;; end defun

To understand how this works, we can evaluate the expressions from the inside out
for a single iteration of the loop:

Let us assume that at some point in the process the variable lst contains the
following data:
(("Block 1" . 3) ("Block 2" . 1) ("Block 3" . 1))
Now let us observe what happens when the program encounters another block in the
selection with block name Block 2 by evaluating the various expressions from the
inside-out:
_$ (setq lst '(("Block 1" . 3) ("Block 2" . 1) ("Block 3" . 1)))
(("Block 1" . 3) ("Block 2" . 1) ("Block 3" . 1))
_$ (setq blk "Block 2")
"Block 2"
_$ (setq itm (assoc blk lst))
("Block 2" . 1)
_$ (cdr itm)
1
_$ (1+ (cdr itm))
2
_$ (cons blk (1+ (cdr itm)))
("Block 2" . 2)
_$ (subst (cons blk (1+ (cdr itm))) itm lst)
(("Block 1" . 3) ("Block 2" . 2) ("Block 3" . 1))
This is exactly how my Assoc++ function operates.

Upon testing the above program, we should now receive an association list detailing
the quantities of each block in the selection:

(("Block 1" . 3) ("Block 2" . 2) ("Block 3" . 1))

Displaying the Results


As a finishing touch, rather than printing the raw association list AutoLISP data to the
command-line, we can print the results to the command-line in a user-friendly format.

To achieve this, we can use a simple foreach loop to iterate over our association list
and print the data held by each dotted pair:
SELECT ALL
(defun c:myblockcounter ( / blk idx itm lst sel ) ;; Define function,
declare local variables
(if ;; If the following expression returns a non-nil value
(setq sel ;; Assign the value returned by the following
expression to the symbol 'sel'
(ssget ;; Prompt the user to make a selection and return
the selection set if successful
'((0 . "INSERT")) ;; Filter the selection to block
references only (INSERTs)
) ;; end ssget
) ;; end setq
(repeat ;; Repeat the enclosed expressions the following
number of times:
(setq idx ;; Assign the value returned by the following
expression to the symbol 'idx'
(sslength sel) ;; Return the number of items in the
selection set
) ;; end setq
(setq blk ;; Assign the block name to the variable 'blk'
(cdr ;; Retrieve the value associated with DXF group
2 (the block name)
(assoc 2 ;; Retrieve the DXF group 2 dotted pair
from the following DXF data
(entget ;; Retrieve the list of DXF data for
the following entity
(ssname sel ;; Retrieve the entity at the
following index
(setq idx (1- idx)) ;; Decrement the
index variable (since selection set indexes are zero-based)
) ;; end ssname
) ;; end entget
) ;; end assoc
) ;; end cdr
) ;; end setq
;; If the block is already recorded in the list:
(if ;; If the following expression returns a non-nil
value
(setq itm ;; Assign the value returned by the
following expression to the symbol 'itm'
(assoc blk lst) ;; Attempt to retrieve a list
item whose first element is equal to the block name
) ;; end setq
;; Update the existing list entry:
(setq lst ;; Redefine the 'lst' variable with the
updated list data
(subst ;; Substitute the following list item in
the list
(cons blk (1+ (cdr itm))) ;; Increment the
number of occurrences recorded for this item in the list
itm ;; The existing item to be substituted
lst ;; The list in which to perform the
substitution
) ;; end subst
) ;; end setq
;; Else add a new entry to the list:
(setq lst ;; Redefine the 'lst' variable with the
following updated list data
(cons ;; 'Push' a new item onto the front of the
list
(cons blk 1) ;; Construct a dotted pair whose
first key is the block name and value is 1
lst ;; The list to which the item should be
added (may be nil)
) ;; end cons
) ;; end setq
) ;; end if
) ;; end repeat
) ;; end if
;; Print the results (if they exist)
(foreach itm lst ;; For every 'itm' in the list given by 'lst'
(princ ;; Print the following to the command-line
(strcat ;; Concatenate the following strings
"\n" ;; (New-line character)
(car itm) ;; The block name
": " ;; An arbitrary separator for the data
(itoa (cdr itm)) ;; The number of occurrences of the
block, converted to a string
) ;; end strcat
) ;; end princ
) ;; end foreach
(princ) ;; Suppress the return of the last evaluated expression
(foreach)
) ;; end defun
You may have noticed that the foreach expression lies outside of the if statement,
and so the list variable lst may be nil when the foreach expression is evaluated.
This is not a problem since, as noted above, a nil value may be interpreted as an
empty list and so the foreach function will merely return nil without throwing an
error if the list argument is empty.
The foreach expression could alternatively be included as part of the 'then' argument
for the if function, which would also require the use of a progn expression so that
multiple expressions may be evaluated, but still supplied as a single argument for
the if function.

Testing the final program we will now receive an output similar to the following:

Block 1: 3
Block 2: 2
Block 3: 1

The Final Program


Reformatting the code and omitting the code comments from every line, we have the
following final program:

SELECT ALL
(defun c:myblockcounter ( / blk idx itm lst sel )
(if (setq sel (ssget '((0 . "INSERT"))))
(repeat (setq idx (sslength sel))
(setq blk (cdr (assoc 2 (entget (ssname sel (setq idx (1-
idx)))))))
(if (setq itm (assoc blk lst))
(setq lst (subst (cons blk (1+ (cdr itm))) itm lst))
(setq lst (cons (cons blk 1) lst))
)
)
)
(foreach itm lst (princ (strcat "\n" (car itm) ": " (itoa (cdr
itm)))))
(princ)
)

I hope you have enjoyed following this tutorial and writing the program for yourself!
Error Message
Troubleshooter
This page provides a brief guide detailing the possible causes of a selection of
common error messages received when executing an AutoLISP program.

Note that the list below is by no means a complete reference.

Error Message Possible Cause

malformed list
on input The code is missing one or more right parentheses.

extra right
paren on input The code has too many right parentheses.

malformed
string on The code contains a string which is missing a string delimiter ( " ).
input

too many
arguments A function has been evaluated with too many parameters.

too few
arguments A function has been evaluated with too few required parameters.

Function
cancelled The user has pressed the Esc key whilst running an AutoLISP function.

quit / exit
abort Either the (exit) or (quit) AutoLISP functions have been evaluated.

Application The user has pressed the Esc key whilst the program is evaluating
ERROR: Console
break the grread function without bit 3 (8) set in the allkeys parameter.

bad argument A function requiring a numerical argument has been passed an


type: numberp: argument of incorrect data type with the value noted in the error
<value>
message.

bad argument
type: fixnump: A function requiring an integer argument has been passed an argument
<value> of incorrect data type with the value noted in the error message.

bad argument
type: stringp A function requiring a string argument has been passed an argument of
<value> incorrect data type with the value noted in the error message.
Error Message Possible Cause

A function requiring a selection set argument has been passed an


bad argument argument of incorrect data type with the value noted in the error
type: lselsetp
<value> message. This is usually a result of passing
the sslength or ssnamex function a null selection set argument.

bad argument A function requiring an entity argument has been passed an argument
type: lentityp of incorrect data type with the value noted in the error message.
<value>
Usually a result of passing the entgetfunction a null entity argument.

bad argument
type: listp A function requiring a list argument has been passed an argument of
<value> incorrect data type with the value noted in the error message.

A function requiring a list argument has been passed an argument of


bad argument incorrect data type with the value noted in the error message. Can be
type: consp
<value> generated by passing any of the c..rfunctions, foreach, member, nth,
or vl-sort-i functions an invalid list argument.

A function requiring a file descriptor argument has been passed an


bad argument
type: FILE argument of incorrect data type with the value noted in the error
<value> message. Usually a result of passing princ, prin1 or print an invalid
second argument.

A function requiring a file descriptor argument has been passed an


bad argument
type: streamp argument of incorrect data type with the value noted in the error
<value> message. Usually a result of passing the closeAutoLISP function a null
or invalid argument.

bad argument A function requiring a VLA-Object argument has been passed an


type: VLA- argument of incorrect data type with the value noted in the error
OBJECT <value>
message.

bad argument A function requiring either a string or symbol argument has been
type: (or passed an argument of incorrect data type with the value noted in the
stringp
symbolp): error message. Usually a result of passing
<value> the getvar or setvar AutoLISP functions an invalid first argument.

bad argument Most likely the result of supplying either the vl-string-search or vl-
value: string
position out string-positionfunctions a character index which is outside of the
of range range of characters available for the supplied string argument, e.g. (vl-
<index> string-search "a" "abc" 4)

bad argument A function requiring a positive numerical value has been passed a
value: non-
Error Message Possible Cause

negative: negative argument. This error is usually a result of passing a negative


<value> value as the index parameter for the nthfunction.

The mode string argument (such as "_X") passed to the ssget function
bad ssget mode
string is invalid. See my ssget Function Reference for a list of valid mode
string arguments.

bad point The ssget function has been passed an invalid point list argument, or
argument none at all.

bad SSGET list One or more items in a filter list supplied to the ssget function is
value invalid.

Unknown The command you are attempting to call is not defined. This could be
command the result of a LISP program not being loaded, a command not being
"example".
Press F1 for available in the AutoCAD version you are running, or by including too
help. many 'enter' calls ("") in a command expression.

no function
definition: The Visual LISP ActiveX(COM) extensions for AutoLISP have not been
VLAX-GET-ACAD-
OBJECT loaded using the (vl-load-com) function. Add (vl-load-com) to
no function
definition:
your acaddoc.lsp or to the code you are trying to run, outside of any
VLAX-ENAME- function definition.
>VLA-OBJECT

The program is attempting to evaluate a function with name as noted in


no function
definition: the error message which is not defined. This could be the result of a
<name> missing function definition, or perhaps (vl-load-com) missing from the
code.

A symbol or variable whose value is not a function is being evaluated as


bad function: a function. Probable cause is a literal list not being quoted, causing the
<name> first item in the list to be evaluated as a function, e.g. (setq lst (1 2
3))

ActiveX Server The program is attempting to access a ActiveX Property or Method with
returned the
error: unknown the name as noted in the error message which is not available for the
name: <name> supplied VLA-Object.

ActiveX Server
returned an The program is attempting to use the vlax-safearray->list function to
error: Invalid convert an empty safearray to a list.
index
Error Message Possible Cause

The program is supplying an ActiveX Property or Method with an


ActiveX Server argument of the correct data type, however with invalid data for the
returned an
error: Type parameter. As an example: supplying a Paperspace Viewport to
mismatch the activeviewport property, or a Modelspace Viewport to
theactivepviewport property.

Automation The program is attempting to use the Item method of a VLA Collection
Error. Key not
found Object to access an item not present in that collection.

vlax-
safearray-fill
failed. The program is attempting to use the vlax-safearray-fill function to
Invalid populate a safearray with an incorrect number of items.
initialization
list.

divide by zero An divisor function (such as rem or /) is attempting to divide by zero.

function A function has been passed an argument of correct data type, but an
undefined for invalid value for the parameter. Usually caused by a mathematical
argument: function being passed an argument for which the operation is not
<value>
defined, e.g. supplying the sqrt function with a negative argument.
An Introduction to the Visual
LISP IDE
The Visual LISP IDE (rather, more precisely: Visual LISP Integrated Development
Environment (VLIDE) - but that's a bit of a mouthful), is an excellent developer tool &
resource supplied as standard with the majority of full versions of AutoCAD.

Even if you are just starting to program in LISP, in my opinion, the VLIDE is essential
and can be a great learning aid.

This tutorial will demonstrate how to get started with the VLIDE, and, to keep things
relatively clear, I won't be delving too deeply into the multitude of tools available to
the developer.

Introduction
To begin, open AutoCAD to a blank drawing and type VLIDE at the command line.

A window should appear, containing two or more smaller windows including the
Console Window & Trace Window (more on these later).

Let's begin by opening a New File in which we can start to construct a program. To do
this, go to File » New File (alternatively using the shortcut: Ctrl+N).

In the window that appears, we can start to construct our LISP program. As an
example, copy or type the following code into the blank editor window:

(defun c:test ( )

(princ "\nI can now use the VLIDE.")


(princ)
)

You will notice that the functions, brackets, strings and other items are highlighted
accordingly:
The syntax highlighting is a great visual aid, and also helps prevent protected symbols
such as function names being used as names for variables, as they are highlighted
accordingly.

At this point, we can study the code in more detail, and, if not sure about how a
function is to be used, we can immediately get information about that function using
the VLIDE Help Documentation. A tutorial on how to do this can be found here.
Also, we can open an existing LISP file to edit the contents in the VLIDE Editor
Window - to do this, either go to File » Open File or use the shortcut Ctrl+O.

Loading a Program
OK, so we've just constructed a program in the Visual LISP IDE, now to test it out!

As you may know, loading a program into AutoCAD can sometimes be tedious, as the
LISP file needs to be saved, then either loaded using the Appload command, or maybe
the ACADDOC.lsp. But, you'll be pleased to know, loading programs in the VLIDE
is much simpler.
There are three equivalent ways to load a program: by going to Tools » Load Text in
Editor; by clicking on the relevant toolbar icon on the Tools toolbar; or simply by
using the shortcut Ctrl+Alt+E.

Upon loading the program, the Visual LISP Console window will appear indicating
whether the code has been loaded successfully.

Now, having loaded the example code above, we can go back to the AutoCAD window,
and at the command line type: test to start the program.

The Visual LISP Console


The Console Window can be activated by going to View » LISP Console or using the
shortcut F6.
The Console will immediately evaluate an entered LISP expression, whether it be a
call to a function, the function itself, or maybe a variable. This is handy for
experimenting with functions & expressions without having to create an entire
program.

A Few Examples
Evaluating a LISP Expression
_$ (+ 2 2)
4
Variable Evaluation
_$ (setq var 1.4142)
1.4142
_$ var
1.4142
Protected Symbol Evaluation
_$ actrue
1
_$ defun
#<SUBR @0fbfaaf0 DEFUN>
Calling a Function (using the example code from earlier)
_$ (c:test)

I can now use the VLIDE.

Further Information
This tutorial has covered the basics of the Visual LISP Integrated Development
Environment (VLIDE) - the Editor offers many essential debugging tools to get you out
of a fix when code goes wrong, and furthermore other tools to format code at the
touch of a button. Be sure to explore the VLIDE Help Documentation detailing how to
get the most out of the VLIDE.

Retrieving Information
About a Function
This tutorial details how to quickly retrieve information about an AutoLISP function
using the Visual LISP IDE.

To begin, open the Visual LISP IDE in an AutoCAD drawing by typing VLIDE at the
command line.
Either open the relevant AutoLISP file containing a function to query (Ctrl+O), or
create a New File (Ctrl+N) and type a function into the window.
To retrieve information about a function, highlight the function (double-click on it),
then click on the beige help button on the Tools toolbar.
Alternatively, highlight the function and press Ctrl+F1, then Enter.

If available, the relevant help documentation for the highlighted function will
subsequently be displayed:
Debugging Code with the
Visual LISP IDE
Ever spent a few hours writing a fantastic program only to find that it crashes the first
time it is run?
Now where could that error have come from...?

If you've ever delved into the world of AutoLISP, (or any programming language for
that matter) I can almost guarantee that you will have, at some point, encountered an
error when writing & running a program - it's almost inevitable:

As soon as we started programming, we found out to our surprise that it wasn't as easy to get
programs right as we had thought. Debugging had to be discovered. I can remember the exact
instant when I realized that a large part of my life from then on was going to be spent in finding
mistakes in my own programs.
- Sir Maurice Wilkes

At this point most users will find themselves scouring the code for typos and other
such mistakes - a process which could take just as long as writing the program itself.

This tutorial aims to teach you how to use the debugging facilities offered by the
Visual LISP IDE (VLIDE) to immediately detect the point at which a program has
crashed and furthermore show you the steps you can take to determine why the code
has crashed at that particular point.
This tutorial assumes the user has a basic knowledge of how to use the Visual LISP
IDE. If you are not one of these users, I would suggest that you give this a read: An
Introduction to the Visual LISP IDE.
Contents
 Introduction
 An Example Program
 Where did the Code Fail?
 Why did the Code Fail?
 Adding Break Points
 Watching Variables
 Animating the Code
 Resetting the Environment
 Fixing the Code
 Further Information

An Example Program
Throughout this tutorial I shall demonstrate various debugging methods using the
following test code which simply prompts the user for a selection of line entities and
proceeds to print the combined total length of the lines to the AutoCAD command-
line.

SELECT ALL
(defun c:linelen ( / ent enx idx sel ssl tot )
(if (setq sel (ssget '((0 . "LINE"))))
(progn
(setq ssl (sslength sel)
tot 0.0
idx 0
)
(while (<= idx ssl)
(setq ent (ssname sel idx)
enx (entget ent)
tot (+ tot (distance (cdr (assoc 10 enx)) (cdr
(assoc 11 enx))))
idx (1+ idx)
)
)
(princ (strcat "\nTotal length of lines: " (rtos tot)))
)
)
(princ)
)
(Can you spot the error in the code already?)
Begin by opening AutoCAD and typing VLIDE at the command-line to open the Visual
LISP IDE. Open a New File (File » New File or Ctrl+N) and either type or copy the
above code into the editor window.

Firstly, let's see what error message we are receiving.

Draw a few lines in AutoCAD with which to test the program. Now load the code in the
editor window (Tools » Load Text in Editor or Ctrl+Alt+E), and run it in AutoCAD by
typing the command syntax 'linelen' at the command-line.

After selecting a few lines, you will receive this error message at the command-line:
; error: bad argument type: lentityp nil

Where did the Code Fail?


If done manually, this is probably the most tedious and time consuming element of
the debugging process: finding where exactly in the code the program has failed.
Luckily, the VLIDE offers an easy way to immediately determine the point at which a
program fails.

To answer this question, navigate back to the VLIDE and go to Debug » Break on
Error. Ensure this option is ticked.

By setting this option, the VLIDE will set a break point at the AutoLISP expression at
which the code fails. A break point is similar to a 'bookmark' in the code and will
cause the program to pause evaluation at the expression marked by the break point.
By instructing the VLIDE to automatically set a break point when the program
encounters an error, we can later return to this break point and quickly identify the
source of the error.

Be aware that assigning break points in the Visual LISP IDE does not modify the
AutoLISP file in any way, and such break points are not stored after the AutoLISP file
is closed.
Now, in AutoCAD, run the program again. When the code errors, navigate back to the
VLIDE window and go to Debug » Last Break Source (Ctrl+F9).

The expression at which the code has encountered an error should be highlighted in
the VLIDE Editor window:

Finally, reset the break point by going to Debug » Reset to Top Level (Ctrl+R); this
removes the break point and resets the paused interpreter (the object that evaluates
the AutoLISP code) to the start of the program.
So, now we know where the code fails, but why does it fail at that point?

Why did the Code Fail?


To help answer this question the VLIDE has a few other tools we can utilise.

Since we know that the error occurs within the while loop, we shall focus our
debugging efforts on that section of the code.

Adding Break Points


As noted earlier, break points pause evaluation of the AutoLISP code, this can be
thought of as similar to pressing the pause button on a cassette player - the reader
head is no longer 'evaluating' the magnetic tape in the cassette and converting it to
electric pulses sent to the speakers.

By pausing the AutoLISP interpreter, we can take control of the flow of evaluation,
starting & stopping the code when and where we like.

To do this, in the VLIDE Editor window, place your cursor in front of the opening
bracket of the while expression, click, and go to Debug » Toggle Break Point (F9).
The opening bracket of the while expression should be highlighted red.
Now place your cursor behind the closing bracket of the while expression and add
another break point following the same method as above.
Watching Variables
The Visual LISP IDE also allows us to 'watch' variables used in the code, displaying
their values as the code is evaluated. With this in mind, let's add a watch to the index
variable idx and the variable holding each line entity: ent.
To do this, double-click on any instance of the idx variable to highlight it and open the
Watch Window by going to View » Watch Window (Ctrl+Shift+W).

The variable idx should now appear in the Watch Window list, with a value
of nil (since it is local to the program and does not hold a value until the
relevant setqexpression is evaluated in the code).
With the Watch Window still open, double-click on any instance on the ent variable
and click on the Add Watch button in the Watch Window (the button with the glasses
symbol):

This variable should also now appear in the list, also with a value of nil.

Animating the Code


With our break points set & variables watched, we are now set to animate the code
evaluation.
Switch to the AutoCAD window, and run the program once more by again
typing linelen at the command-line.

When the code evaluation reaches our first break point, code evaluation will be
paused and the VLIDE Editor window will appear, highlighting the code between the
two break points. From here, we have complete control over the code evaluation. We
can step into and out of expressions and evaluate them as we please.

For now, go to Debug » Animate and ensure this option is ticked.


Now go to Debug » Continue (alternatively click on the green arrow on the Debug
Toolbar, or press Ctrl+F8).

The code should now start to evalute, expression by expression from the break point
set earlier:

Notice how the variables in the Watch Window will change their values as the
various setq expressions within the while loop are evaluated.
The values shown in the Watch Window reveal the cause of our error: the value of
the ent variable becomes nil when our integer selection set index variable idxreaches
2.
This indicates that no entity is found in the selection set sel at the index 2, meaning
that the test condition for the while loop is allowing the counter to get too high before
the test condition returns nil and hence ceases evaluation of the while loop.

Resetting the Environment


Now that we have identified the cause of our error, we can reset the VLIDE
environment.
Reset the AutoLISP interpreter by going to Debug » Reset to Top Level (Ctrl+R) - this
is analogous to pressing the 'Stop' button on our cassette player.
Clear all break points by going to Debug » Clear all Break Points (Ctrl+Shift+F9),
accepting the prompt.
Clear the Watch Window by clicking on the Clear Window button in the Watch Window.

Finally, go to Debug » Animate and Debug » Break on Error and uncheck these
options.

Fixing the Code


Now that we have identified where and why the code is failing, we can look to
implement a change in the while test condition and hopefully fix the error.
In my demonstration I have selected 2 line objects, and, since the selection set index
is zero-based (i.e. the first entity resides at index 0), the index variable idxshould
take integer values in the range 0 to 1.

With this knowledge, we can fix the code in the following way:

SELECT ALL
(defun c:linelen ( / ent enx idx sel ssl tot )
(if (setq sel (ssget '((0 . "LINE"))))
(progn
(setq ssl (sslength sel)
tot 0.0
idx 0
)
(while (< idx ssl) ;; Changed <= to <
(setq ent (ssname sel idx)
enx (entget ent)
tot (+ tot (distance (cdr (assoc 10 enx)) (cdr
(assoc 11 enx))))
idx (1+ idx)
)
)
(princ (strcat "\nTotal length of lines: " (rtos tot)))
)
)
(princ)
)
Further Information
For more information about the debugging capabilities of the Visual LISP IDE (VLIDE),
refer to the VLIDE Help Documentation:

A Shortcut to Localising
Variables
Introduction
When writing AutoLISP programs, declaring variables local to a program, or
colloquially, 'localising variables' is an important practice to follow.
Failure to declare a variable local to a program can, in some cases, lead to unforeseen
consequences as described in my tutorial on Localising Variables.

However, those who have written programs of reasonable length will know that
variable localisation can be a long and tedious process, often resulting in some
variables being mistyped or omitted completely.

Thankfully, the Visual LISP IDE (VLIDE) offers a much quicker way to declare
variables local. This tutorial will demonstrate a method to automatically report a list of
symbols defined in your program code, reducing the task of localisation to a simple
copy & paste operation.

Preliminary Setup
Before using the Checking utility offered by the Visual LISP IDE to report a list of
variables, first ensure the following settings are enabled in your environment. This
procedure will only need to be performed once.
First, open the Visual LISP IDE by typing 'VLIDE' at the AutoCAD command-line.
In the VLIDE, go to Tools » Environment Options » General Options

On the dialog that appears, navigate to the Diagnostic tab.


Ensure the Report statistics during syntax checking toggle is enabled.

Click OK on the dialog to submit these settings.

Checking the Code


Now that the necessary settings are enabled, we can proceed to use the Checking
utility to generate a list of variables for a program.

To serve as an example for this tutorial, open a New File in the VLIDE (File » New
File or Ctrl+N) and copy the following code into the editor window:
(defun c:test ( / )
(setq var1 1.0
var2 "abc"
var3 '(0 1 2 3 4)
)
(princ)
)
This very simple code defines three global variables, (var1, var2 & var3), which we
intend to declare local to the function c:test.
In the VLIDE, go to Tools » Check Text in Editor (alternatively, click the Check Edit
Window button on the Tools toolbar, or press Ctrl+Alt+C).
This utility will check the code for syntax errors and also return a list of global
variables defined in the code, the output may look something like this:

[CHECKING TEXT <Untitled-1> loading...]


.
; === Top statistic:
; Global variables: (VAR1 VAR2 VAR3)
; Function definition (with number of arguments): ((C:TEST . 0))
; Check done.
Now localising the variables becomes a simple task of copying the list of global
variables into the defun expression of the function definition.

Warning!
The list returned by the VLIDE checking utility will list all defined symbols in the code.
This list may include protected symbols, such as functions or protected constants. If
such symbols are inadvertently localised, your program may not run as expected.

When copying the list of global variables ensure you remove the following items:

o Protected symbols (highlighted blue), such as functions or protected constants


(e.g. :vlax-true).
o DCL Symbols defined at run-time, such as $key, $reason, $value, $data.
o The pause symbol, as may be used in command expressions.

o Variables that you intend to remain global.


Hint: The list of variables returned by the checking utility is sorted alphabetically, so
by prefixing global variable names with asterisks (*), these are likely to appear at the
front of the list and are easily removed.

Finishing Touches
If, like me, you are obsessed with the look and layout of your code, you may not like
to have a capitalised list of local variables.

If you fall into this category of individuals, consider the following function:

(defun VarList ( lst )


(vl-princ-to-string (mapcar '(lambda ( x ) (strcase (vl-princ-to-
string x) t)) lst))
)
_$ (VarList '(VAR1 VAR2 VAR3))
"(var1 var2 var3)"

Much nicer.

Further Information
The Checking utility available in the Visual LISP IDE has many more uses than merely
listing global variables; for more information about the full power of this tool, read the
following section of the Visual LISP IDE Help Documentation:

AutoLISP Developer's Guide » Using the Visual LISP Environment » Developing


Programs with Visual LISP » Checking for Syntax Errors » Using the Check
Command to Look for Syntax Errors

List Box Synchronisation


Updating a DCL List_Box Based on
User Selection from Another List_Box
Here I demonstrate a small example of how to update a secondary DCL list_box tile,
based on a user selection from a primary list_box tile. The example I present utilises
list_box tiles, however, the concept could very easily be applied to popup_list tiles by
merely substituting popup_list for list_box in the Dialog Control Language (DCL) file.
This tutorial assumes the reader knows how to work with DCL using LISP to a basic level.
The example I shall demonstrate incorporates two list_box tiles in a dialog,
displaying a selection of car makes & corresponding models for each make of car. The
dialog is designed to update the list of available models following a selection of make.

The Code
DCL File
Save this code in an AutoCAD Support Path as: listboxexample.dcl
SELECT ALL
// DCL File to be saved as listboxexample.dcl
// Example courtesy of Lee Mac © 2010 (www.lee-mac.com)

lbox : list_box { width = 25; fixed_width = true; alignment =


centered; }

listboxexample : dialog { label ="List Box Synchronisation"; spacer;


: row {
: lbox { key = "lst1"; label = "Make" ; }
: lbox { key = "lst2"; label = "Model"; }
}
ok_only;
}

LISP File
This may be saved using an arbitrary filename, for loading instructions see How to
Run an AutoLISP Program.
When loaded, start the program using ListBoxExample at the command line.
SELECT ALL
(defun c:listboxexample ( / *error* UpdateList data dclfile dclhandle
)

;; This program demonstrates how to update a secondary list_box


based
;; on user selection from a primary list_box.

;; Example courtesy of Lee Mac © 2010 (www.lee-mac.com)

;; Accompanying DCL File:

(setq dclFile "listboxexample.dcl")

;; Ensure this file resides in an AutoCAD Support Path

(defun *error* ( msg )

;; Error Handler - will unload the dialog


;; from memory should the user decide to hit Esc

(if dclHandle (unload_dialog dclHandle))


(or (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*")
(princ (strcat "\n** Error: " msg " **")))
(princ)
)

(defun UpdateList ( key lst )

;; This function updates the list_box associated with the


specified key
;; using the contents of the supplied lst

(start_list key)
(mapcar 'add_list lst)
(end_list)
)

;; Data used to Populate List_Boxes:


;; I've chosen to use this list structure because it suits the
data,
;; but there are many other possibilities.

(setq Data
'(
("Audi" ("TTS Quattro" "TT RS" "S3 Quattro" "S4 Quattro" "S5
Quattro" "RS5 Quattro" "RS6 Quattro"))
("BMW" ("M3" "M5" "M6" "X5" "Z3" "Z4"))
("Porsche" ("911" "924" "928" "930" "944" "Boxster" "Cayenne"
"Cayman"))
("Jaguar" ("XF" "XJ6" "XJR" "XKR" "X-Type" "S-Type"))
)
)

;; Start of Main Routine


;; Lots of Error Trapping to make sure the Dialog Loads:

(cond
( (<= (setq dclHandle (load_dialog dclFile)) 0)

(princ "\n--> DCL File not Found.")


)
( (not (new_dialog "listboxexample" dclHandle))

(setq dclHandle (unload_dialog dclHandle))


(princ "\n--> Dialog Definition not Found.")
)
( t
;; Dialog Loaded Successfully.

(or *Make* (setq *Make* "0"))


(or *Model* (setq *Model* "0"))

;; Set up some default selections, for the first-time running


of the program.
;; The variables *Make* & *Model* are intended to be global and
hence will
;; remember the user's last selections.

;; Populate the List_Boxes:

;; List_Box 'lst1'
(UpdateList "lst1" (mapcar 'car Data))
(set_tile "lst1" *Make*)

;; List_Box 'lst2'

(UpdateList "lst2" (cadr (nth (atoi *Make*) Data)))


(set_tile "lst2" *Model*)

;; Action_tile Statements:
;; These control what happens when the user interacts with a
tile in the dialog.

(action_tile "lst1"
(strcat
"(UpdateList \"lst2\" (setq lst2 (cadr (nth (atoi (setq
*Make* $value)) Data))))"
"(setq *Model*"
" (set_tile \"lst2\""
" (if (< (atoi *Model*) (length lst2)) *Model* \"0\")"
" )"
")"
)
)

;; Here, when the user selects an item from 'lst1', the


UpdateList subfunction
;; is fired to update the items in list_box 'lst2'.

;; list_box 'lst2' is also set to the value of *Model* if the


index is
;; available for the selected item, else the first item is
selected.

;; Note that $value is a string containg the index of the item


;; that the user has selected.

(action_tile "lst2" "(setq *Model* $value)")

;; Dialog setup, lets start it:

(start_dialog)
(setq dclHandle (unload_dialog dclHandle))
)
)
(princ)
)

The Result
Remembering Dialog
Position
This tutorial demonstrates how to 'remember' the position of a DCL dialog so that it
may appear in that position the next time the program is used.

This tutorial assumes the reader knows how to work with DCL using LISP to a basic level.

The example code shown below uses a global variable (namely *screenpoint*) to
store the position of the dialog. This data is stored as a 2D list representing the
position of the dialog on the screen. Alternatively, the positional data could be
converted to a string and stored in the registry to remember the dialog position
between drawing sessions.

To better understand how this screen coordinate is used to position the dialog, refer
to the VLIDE Help Documentation on the new_dialog & done_dialog functions -
seehere if you are unsure how to find this information.

The Code
DCL File
Save this code in an AutoCAD Support Path as: test.dcl
SELECT ALL
// DCL File to be saved as test.dcl
// Example courtesy of Lee Mac © 2011 (www.lee-mac.com)

test : dialog { label = "Test Dialog";


spacer;
: text { label = "Move me"; alignment = centered; }
spacer;
: button { key = "accept"; is_default = true; label = "I'm Done"; }
}

LISP File
This may be saved using an arbitrary filename, for loading instructions see How to
Run an AutoLISP Program.
When loaded, start the program using test at the command line.
SELECT ALL
(defun c:test ( / *error* dcl dch )

;; Example by Lee Mac 2011 - www.lee-mac.com

;; Demonstrates how to remember a dialog screen


;; position for next use.

;; Requires accompanying file: test.dcl to be


;; saved in an AutoCAD Support Path.

;; Error Handler so that we may unload the dialog


;; from memory should the user hit Esc.

(defun *error* ( msg )


(if dch (unload_dialog dch))
(or (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*")
(princ (strcat "\n** Error: " msg " **")))
(princ)
)

;; Plentiful Error trapping to make sure


;; dialog is loaded successfully.

(cond
(
(not
(and
(setq dcl (findfile "test.dcl")) ;; Check for DCL file
(< 0 (setq dch (load_dialog dcl))) ;; Attempt to load it
if found
)
)

;; Else dialog is either not found or couldn't be loaded:

(princ "\n** DCL File not found **")


)
(
(not (new_dialog "test" dch "" (cond ( *screenpoint* ) ( '(-1
-1) ))))

;; If our global variable *screenpoint* has a value it will be


;; used to position the dialog, else the default (-1 -1) will
be
;; used to center the dialog on screen.
;; Should the dialog definition not exist, we unload the dialog
;; file from memory and inform the user:

(setq dch (unload_dialog dch))


(princ "\n** Dialog could not be Loaded **")
)
(t

;; Dialog loaded successfully, now we define the action_tile


;; statements:

(action_tile "accept" "(setq *screenpoint* (done_dialog 1))")

;; The dialog screen position is returned by the done_dialog


;; function, so we store this in our global variable
*screenpoint*
;; for next time.

(start_dialog)

;; Display the dialog - we can use the return of start_dialog


;; to determine whether the user pressed OK or Cancel.

(setq dch (unload_dialog dch))

;; We're done, unload the Dialog from memory.


)
)

(princ) ;; Exit Quietly...


)

Result

CAD & Programming Forums


 TheSwamp.org
 CADTutor.net
 AUGI.com
 Autodesk Discussion Groups
ssget
The following is a detailed reference for the AutoLISP ssget function, including
information on undocumented mode strings and selection behaviour. The reference
consists of information which has been collected from various sources & compiled by
numerous contributors.
Contents
 Function Format
 Selection Mode Strings
 Filter List Operators
 Relational Operators
 Logical Operators
 System Variables
 PICKADD
 PICKAUTO
 PICKDRAG
 PICKFIRST
 PICKSTYLE
 Existing Documentation

Function Format
(ssget [mode-string] [pt1 [pt2]] [pt-list] [filter-
list])

Selection Mode Strings

Non-localised mode string prefix


_ Ensures the English version of the mode string is used in non-En
(underscore)
Not strictly necessary for all mode strings (since some mode stri
safer to include than exclude.

+. Point Selection Mode [user selection] [undocumented]


Forces ssget to remain in 'point' mode, similar to setting PICKAUT
selection mode and ":E"mode to emulate an entsel selection by
Example:
(ssget "_+.:E:S")
Will emulate an entsel selection behaviour.

This mode string must be combined with other mode strings and
its own.

All [automated] [undocumented]


Similar to the "X" mode string but excludes objects on frozen lay
Example:
A (ssget "_A" '((0 . "LINE")))

Selects all lines residing on thawed layers in the drawing.

This mode string cannot be combined with graphical selection m

Box [automated] [undocumented]

B Selects all objects inside or crossing a rectangle specified by two


left, Box is equivalent to Crossing. Otherwise, Box is equivalent t

Crossing [automated] [documented]

Selects objects residing within and/or crossing a rectangular are


should be expressed relative to the UCS, however, the crossing w
axes.
C Example:
(ssget "_C" '(0 0) '(2 1) '((0 . "CIRCLE")))
Selects all circles residing inside or crossing the rectangle with v
Caution: Only objects visible in the drawing area at the time of
Consider temporarily zooming to the selection window before pe
to restore the original screen position.

CP Crossing Polygon [automated] [documented]

Selects objects residing within and/or crossing a polygon defined


shape but cannot cross or touch itself. AutoCAD will construct th
closed at all times.

The CP mode string is not affected by the PICKADD System Variab


Example:
(ssget "_CP" '((1 1) (3 1) (5 2) (2 4)))
Selects all objects residing inside or crossing a polygon with vert
Caution: only objects visible in the drawing area at the time of s
Consider temporarily zooming to the selection area before perfor
restore the original screen position.

Allow Duplicates [user selection] [undocumented]


:D
Includes duplicate selected entities in the selection, else duplicat

Everything within Aperture [user selection] [documented]


:E Allows selection of everything within the cursor's object selection
conjunction with the "+." and ":S"mode strings to emulate ents

Fence [automated] [documented]


Selects all objects crossing a selection fence. The Fence method
AutoCAD does not close the fence, and a fence can cross itself.
Example:
(ssget "_F" '((0 0) (1 1)) '((0 . "LINE")))
F
Selects all lines crossing the fence line running from (0,0) to (1,
Fence is not affected by the PICKADD System Variable.
Caution: Only objects visible in the drawing area at the time of
Consider temporarily zooming to the selection window before pe
to restore the original screen position.

Groups [automated] [undocumented]

Selects all objects within a specified group.


G
Although a valid ssget mode string, there is no provision for pas
the ssget function and hence this option is only of use at the com

I Implied [automated] [documented]


Implied selection (objects selected while PICKFIRST is in effect).

Last [automated] [documented]

Selects the last visible object added to the drawing database.


L Caution: when using the "L" selection method in an MDI enviro
object drawn to remain visible. For example, if your application d
minimizes or cascades the AutoCAD drawing window, the line ma
the "L" option will return nil.

Exclude Locked Layers [user selection] [undocumented]


:L
Rejects selection of objects residing on locked layers.
Multiple [automated] [undocumented]

M Specifies multiple points without highlighting the objects, thus sp


objects. The Multiple method also selects two intersecting object

Nested [user selection] [documented]


Call ssnamex for additional information on container blocks and
during the ssgetoperation. This additional information is availabl
selection methods such as Window, Crossing, and point picks.
Unlike the other object selection methods, :N may return multipl
:N selection set. For example, if the user selects a subentity of a co
PolygonMesh, or old style polyline, ssget looks at the subentity t
already been selected. However, ssget actually adds the main en
selection set. The result could be multiple entries with the same
different subentity information for ssnamex to report).
This ssget mode string is known to perform erratically.

Previous [automated] [documented]

Selects the most recent selection set.


P The Previous selection set is cleared by operations that delete ob
whether each selection set was specified in model space or pape
you switch spaces.

Reject Viewports [user selection] [undocumented]

Rejects selection of Viewport objects.


:P
Equivalent to:
(ssget '((0 . "~VIEWPORT")))

Permit Long Transaction [user selection] [documented]


:R
Allows entities in a long transaction to be selected.

Single Selection [user selection] [documented]


:S The user is permitted a single attempt to make a selection of ob
When combined with either "+." or ":E", only a single object ma

:U Enable Subentity Selection - 2006+ [user selection] [documented]


Cannot be combined with the duplicate (":D") or nested (":N") s
In this mode, top-level entities are selected by default, but the u
pressing the CTRL key while making the selection. This option is s
as window, crossing, and polygon. It is not supported for all, filte

Force Subentity Selection - 2006+ [user selection] [documented]

Treats all interactive, graphic selections performed by the user a


:V
The returned selection set contains subentities only. This option
nested (":N") selection modes. This option is supported only with
crossing. It is not supported for all, filtered, or group selections.

Window [automated] [documented]

Selects all objects residing completely inside a rectangle defined

Example:
W (ssget "_W" '(3 2) '(5 4) '((0 . "TEXT")))
Selects all text objects residing entirely inside the rectangle with
Caution: only objects visible in the drawing area at the time of s
Consider temporarily zooming to the selection window before pe
to restore the original screen position.

Window Polygon [automated] [documented]


Selects objects completely inside a polygon defined by a list of p
cross or touch itself. AutoCAD will construct the last segment of
WPolygon is not affected by the PICKADD System Variable.
WP Example:
(ssget "_WP" '((0 1) (4 2) (6 4)) '((0 . "ARC") (40 . 1.0))
Selects all arcs with radius 1.0 residing entirely within a polygon
Caution: only objects visible in the drawing area at the time of s
Consider temporarily zooming to the selection area before perfor
restore the original screen position.

Extended search (Entire Drawing Database) [automated] [documented]

Iterates over the entire drawing database selection all entities m


list (if present); includes entities on layers that are off, frozen &
drawing area.
X
Example:
(ssget "_X" '((0 . "CIRCLE")))

Selects all circles in every drawing layout.


Filter List Operators
Relational Operators
Notes: http://www.lee-mac.com/ssget.html

o The following relational operators are only valid for use with groups containing
integer or real values; the bitwise operators are limited to integer values only.
Use wildcard patterns for testing strings.
o For point groups, the X, Y, and Z tests can be combined into a single string, with
each operator separated by commas (for example, ">,>,*"). If an operator is
omitted from the string (for example, "=,<>" leaves out the Z test), then the
'anything goes' operator, "*", is assumed.
o Direction vectors (DXF Group code 210) can be compared only with the
operators "*", "=", and "!=" (or one of the equivalent 'not equal' strings).

Anything goes (always true)


* Example:
(ssget '((0 . "LINE") (-4 . "=,*,=") (10 1.0 0.0 1.0)))
Select lines with start point passing through (1.0,*,1.0) i.e. with any Y-co

Equal
= Example:
(ssget '((0 . "CIRCLE") (-4 . "*,*,=") (10 0.0 0.0 4.0)))
Select circles with a center at an elevation of 4.0 units

Not Equal
!= All three listed operators are equivalent.
/=
<> Example:
(ssget '((0 . "CIRCLE") (-4 . "<>") (40 . 5.0)))
Select circles with a radius not equal to 5.0

Less Than
< Example:
(ssget '((0 . "ARC") (-4 . "<") (40 . 2.0)))
Select arcs with a radius less than 2.0
Less Than or Equal to
<= Example:
(ssget '((0 . "TEXT") (-4 . "*,<=") (11 0.0 10.0 0.0)))
Select text with alignment point with Y-coordinate less than or equal to 10.

Greater Than

> Example:
(ssget '((0 . "LINE") (-4 . ">,>") (11 3.0 3.0 0.0)))
Select lines with end point passing through a point with X & Y coordinate g
value.

Greater Than or Equal to

>= Example:
(ssget '((0 . "POINT") (-4 . "<,>=,=") (10 5.0 7.0 0.0)))
Select points with X-coordinate less than 5.0, Y-coordinate greater than or
to 0.0

Bitwise AND (integer groups only)

Equivalent to: (/= 0 (logand bit filter))


&
Example:
(ssget '((0 . "POLYLINE") (-4 . "&") (70 . 6)))
Select Polylines with either curve-fit (2) or spline-fit (4) vertices added.

Bitwise Masked Equals (integer groups only)

Equivalent to: (= filter (logand bit filter))


&= Example:
(ssget '((0 . "LWPOLYLINE") (-4 . "&=") (70 . 1)))

Select closed LWPolylines.

Logical Operators

<AND...AND>
Logical And

Matches all enclosed expressions.

Since the ssget filter list has an implied AND operator (matching
used in conjunction with other logical operators to form compo
Example:
(ssget
'(
(-4 . "<OR")
(-4 . "<AND") (0 . "ARC") (40 . 1.5) (-4 .
(-4 . "<AND") (0 . "CIRCLE") (40 . 2.0) (-4 .
(-4 . "OR>")
)
)
Selects arcs with radius 1.5 or circles with radius 2.0.

Logical Inclusive Or

Matches one or more enclosed expressions.


<OR...OR> Example:
(ssget '((0 . "TEXT") (-4 . "<OR") (40 . 1.0) (8 . "0") (6
Selects text objects with text height of 1.0 or layer "0", or with
of these properties.

Logical Exclusive Or

<XOR...XOR> Matches one of two enclosed expressions.


Example:
(ssget '((0 . "TEXT") (-4 . "<XOR") (40 . 1.0) (62 . 3) (-
Selects text with text height of 1.0 or with colour set to 3, but

Logical Not

<NOT...NOT> Rejects objects matching the single enclosed expression.


Example:
(ssget '((0 . "LINE") (-4 . "<NOT") (62 . 256) (-4 . "NOT>
Selects lines with colour not set to 256 (ByLayer).

System Variables
PICKADD
Controls whether subsequent selections replace the current selection set or add to it.

0 Turns off PICKADD.


The objects and subobjects most recently selected become the selection set.
removed from the selection set. Add more objects or subobjects to the selec

Turns on PICKADD.
1 Each object and subobject selected, either individually or by windowing, is ad
objects or subobjects from the set, press SHIFT while selecting.

Turns on PICKADD.
2
Same as PICKADD=1, but keeps objects selected after the SELECT command en

PICKAUTO
Controls automatic windowing at the Select Objects prompt.

Turns off PICKAUTO.


0
Forces 'point' selection: clicking in empty drawing space will not open a selec

Turns on PICKAUTO.
1 Draws a selection window (for either a window or a crossing selection) autom
user clicks in an empty drawing area.

PICKDRAG
Controls the method of drawing a selection window.

Draws the selection window using two points.


0
Click the pointing device at one corner, and then click to select another corn

Draws the selection window using dragging.


1
Click one corner and drag the pointing device, release the button at the oth

PICKFIRST
Controls whether you select objects before (noun-verb selection) or after you issue a
command.

0 Turns off PICKFIRST, you select objects after you issue a command

1 Turns on PICKFIRST, you select objects before you issue a command

PICKSTYLE
Controls the use of group selection and associative hatch selection.
0 No group selection or associative hatch selection

1 Group selection

2 Associative hatch selection

3 Group selection and associative hatch selection

Existing Documentation
Below you will find various links to existing documentation referencing
the ssget function.
Standard ssget Function Reference
Selecting Objects and Selection Sets
Selection Set Filter Lists
Wildcard Patterns in Filter Lists
Filtering for Extended Data
Relational Tests
Logical Grouping of Filter Tests
Selection Set Manipulation Functions Reference
ssget (AutoLISP)

Creates a selection set from the selected object

Supported Platforms: Windows and Mac OS

Signature
(ssget [sel-method] [pt1 [pt2]] [pt-list] [filter-list])

sel-method
Type: String
Object selection method.
Valid selection methods are
C -- Crossing selection.
CP -- Cpolygon selection (all objects crossing and inside of the specified
polygon).
F -- Fence selection.
I -- Implied selection (objects selected while the AutoCAD PICKFIRST system
variable is in effect).
L -- Last visible object added to the database.
P -- Last selection set created.
W -- Window selection.
WP -- WPolygon (all objects within the specified polygon).
X -- Entire database. If you specify the X selection method and do not provide
a filter-list, ssget selects all entities in the database, including entities on layers
that are off, frozen, and out of the visible screen.
:E -- Everything within the cursor's object selection pickbox.
:N -- Call ssnamex for additional information on container blocks and
transformation matrices for any entities selected during the ssget operation. This
additional information is available only for entities selected through graphical
selection methods such as Window, Crossing, and point picks.
Unlike the other object selection methods, :N may return multiple entities with the
same entity name in the selection set. For example, if the user selects a subentity
of a complex entity such as a BlockReference, PolygonMesh, or old style
polyline, ssgetlooks at the subentity that is selected when determining if it has
already been selected. However, ssget actually adds the main entity
(BlockReference, PolygonMesh, and so on) to the selection set. The result could
be multiple entries with the same entity name in the selection set (each will have
different subentity information for ssnamex to report).

:R -- Allows entities in a long transaction to be selected.


:S -- Allow single selection only.
:U -- Enables subentity selection. Cannot be combined with the duplicate (":D") or
nested (":N") selection modes. In this mode, top-level entities are selected by
default, but the user can attempt to select subentities by pressing the CTRL key
while making the selection. This option is supported only with interactive
selections, such as window, crossing, and polygon. It is not supported for all,
filtered, or group selections.

pt1
Type: List
A point relative to the selection.

pt2
Type: List
A point relative to the selection.

pt-list
Type: List
A list of points.

filter-list
Type: List
An association list that specifies object properties. Objects that match the filter-
list are added to the selection set.

Return Values
Type: ads_name or nil
The name of the created selection set if successful; otherwise nil if no objects
were selected.

Remarks
Selection sets can contain objects from both paper and model space, but when
the selection set is used in an operation, ssget filters out objects from the space
not currently in effect. Selection sets returned by ssget contain main entities only
(no attributes or polyline vertices).
If you omit all arguments, ssget prompts the user with the Select Objects
prompt, allowing interactive construction of a selection set.
If you supply a point but do not specify an object selection method, AutoCAD
assumes the user is selecting an object by picking a single point.

 When using the :N selection method, if the user selects a subentity of a complex
entity such as a BlockReference, PolygonMesh, or old style polyline, ssget looks
at the subentity that is selected when determining if it has already been selected.
However, ssget actually adds the main entity (BlockReference, PolygonMesh,
etc.) to the selection set. It is therefore possible to have multiple entries with the
same entity name in the selection set (each will have different subentity
information for ssnamex to report). Because the :N method does not guarantee
that each entry will be unique, code that relies on uniqueness should not use
selection sets created using this option.
 When using the L selection method in an MDI environment, you cannot always
count on the last object drawn to remain visible. For example, if your application
draws a line, and the user subsequently minimizes or cascades the AutoCAD
drawing window, the line may no longer be visible. If this occurs, ssget with
the "L" option will return nil.

Examples
Prompt the user to select the objects to be placed in a selection set:
(ssget)

<Selection set: 2>

Create a selection set of the object passing through (2,2):


(ssget '(2 2))

nil

Create a selection set of the most recently selected objects:


(ssget "_P")

<Selection set: 4>

Create a selection set of the objects crossing the box from (0,0) to (1,1):
(ssget "_C" '(0 0) '(1 1))

<Selection set: b>

Create a selection set of the objects inside the window from (0,0):
(ssget "_W" '(0 0) '(5 5))

<Selection set: d>

By specifying filters, you can obtain a selection set that includes all objects of a
given type, on a given layer, or of a given color. The following example returns a
selection set that consists only of blue lines that are part of the implied selection
set (those objects selected while the AutoCAD PICKFIRST system variable is in
effect):
(ssget "_I" '((0 . "LINE") (62 . 5)))

<Selection set: 4>

The following examples of ssget require that a list of points be passed to the
function. The pt_list variable cannot contain points that define zero-length
segments.
Create a list of points:
(setq pt_list '((1 1)(3 1)(5 2)(2 4)))

((1 1) (3 1) (5 2) (2 4))

Create a selection set of all objects crossing and inside the polygon defined
by pt_list:
(ssget "_CP" pt_list)

<Selection set: 13>

Create a selection set of all blue lines inside the polygon defined by pt_list:
(ssget "_WP" pt_list '((0 . "LINE") (62 . 5)))

<Selection set: 8>

The selected objects are highlighted only when ssget is used with no
arguments. Selection sets consume AutoCAD temporary file slots, so AutoLISP is
not permitted to have more than 128 open at one time. If this limit is reached,
AutoCAD cannot create any more selection sets and returns nil to
all ssget calls. To close an unnecessary selection set variable, set it to nil.

A selection set variable can be passed to AutoCAD in response to any Select


objects prompt at which selection by Last is valid. AutoCAD then selects all the
objects in the selection set variable.
The current setting of Object Snap mode is ignored by ssget unless you
specifically request it while you are in the function.

Related Concepts

 Selection Set Manipulation Functions Reference (AutoLISP)

Related Reference

 ssgetfirst (AutoLISP)
 ssadd (AutoLISP)
 ssdel (AutoLISP)

About Selecting Objects and Selection Sets (AutoLISP)

Selection sets are groups of one or more selected objects (entities).

You can interactively add objects to, remove objects from, or list objects in a selection
set. The following example code uses the ssget function to return a selection set
containing all the objects in a drawing.
(ssget "X")

<Selection set: 1>

AutoLISP provides a number of functions for handling selection sets. The following lists
some of the functions available for working with selection sets:
 ssget - Prompts the user to select objects (entities), and returns a selection set.
 ssadd - Adds an object (entity) to a selection set, or creates a new selection set.
 ssdel - Removes an object (entity) from a selection set.
 ssname - Returns the object (entity) name of the indexed element of a selection
set.
 sslength - Returns an integer containing the number of objects (entities) in a
selection set.

The ssget function provides the most general means of creating a selection set. It can
create a selection set in one of the following ways:

 Explicitly specifying the objects to select, using the Last, Previous, Window,
Implied, Window Polygon, Crossing, Crossing Polygon, or Fence options
 Specifying a single point
 Selecting all objects in the database
 Prompting the user to select objects

With any option, you can use filtering to specify a list of properties and conditions that the
selected objects must match.
Note: Selection set and entity names do not remain the same between drawing
sessions.
The first argument to ssget is a string that describes which selection option to use. The
next two arguments, pt1 and pt2, specify point values for the relevant options (they
should be left out if they do not apply). A point list, pt-list, must be provided as an
argument to the selection methods that allow selection by polygons (that is, Fence,
Crossing Polygon, and Window Polygon). The last argument, filter-list, is optional. If filter-
list is supplied, it specifies the list of entity field values used in filtering. For example, you
can obtain a selection set that includes all objects of a given type, on a given layer, or of
a given color.

The following table shows examples of calls to ssget:

SSGET Examples

Function call Effect

(setq Sets pt1, pt2, pt3, and pt4 to point values


pt1 '(0.0 0.0 0.0)
pt2 '(5.0 5.0 0.0)
pt3 '(4.0 1.0 0.0)
pt4 '(2.0 6.0 0.0)
)

(setq ss1 (ssget)) Prompts the user for a general object selection
and places those items in a selection set

(setq ss1 (ssget "P")) Creates a selection set from the most recently
created selection set

(setq ss1 (ssget "L")) Creates a selection set of the last object added
to the database that is visible on the screen
SSGET Examples

Function call Effect

(setq ss1 (ssget pt2)) Creates a selection set of an object passing


through point (5,5)

(setq ss1 (ssget "W" pt1 pt2)) Creates a selection set of the objects inside the
window from (0,0) to (5,5)

(setq ss1 (ssget "F" (list pt2 pt3 Creates a selection set of the objects crossing
pt4))) the fence and defined by the points (5,5), (4,1),
and (2,6)

(setq ss1 (ssget "WP" (list pt1 pt2 Creates a selection set of the objects inside the
pt3))) polygon defined by the points (0,0), (5,5), and
(4,1)

(setq ss1 (ssget "X")) Creates a selection set of all objects in the
database

When an application has finished using a selection set, it is important to release it from
memory. This can be done by setting it to nil:
(setq ss1 nil)

Remember: You can also release the memory used by the values stored in a variable by
defining it as a local variable in a function.
Attempting to manage a large number of selection sets simultaneously is not
recommended. An AutoLISP application cannot have more than 128 selection sets open
at once. (The limit may be lower on your system.) When the limit is reached, AutoCAD
will not create more selection sets. Keep a minimum number of sets open at a time, and
set unneeded selection sets to nil as soon as possible. If the maximum number of
selection sets is reached, you must call the gc function to free unused memory before
another ssget will work.

Related Concepts

 About Modifying Selection Sets (AutoLISP)


 About Selection Set Filter Lists (AutoLISP)
 About Logical Grouping of Selection Filter Tests (AutoLISP)
 About Relational Tests in Filter Lists for Selection Sets (AutoLISP)
 About Wild-Card Patterns in Selection Set Filter Lists (AutoLISP)
 About Filtering for Extended Data in a Selection Set (AutoLISP)
 Selection Set Manipulation Functions Reference (AutoLISP)

About Selection Set Filter Lists (AutoLISP)

An entity filter list is an association list that uses DXF group codes in the same format as
a list returned by entget.
The ssget function recognizes all group codes except entity names (group code -1),
handles (group code 5), and xdata (group codes greater than 1000). If an invalid group
code is used in a filter-list, it is ignored by ssget. Use the group code -3 to search for
objects with xdata. When a filter-list is provided as the last argument to ssget, the
function scans the selected objects and creates a selection set containing the names of
all main entities matching the specified criteria. The filter-list specifies which property (or
properties) of the entities are to be checked and which values constitute a match.
For example, you can obtain a selection set that includes all objects of a given type, on a
given layer, or of a given color.

The following examples demonstrate different methods of using a filter-list with various
object selection options.

SSGET examples using filter lists

Function call Effect

(setq ss1 Prompts for general object selection but adds only
(ssget '((0 . "TEXT"))) text objects to the selection set.
)

(setq ss1 Creates a selection set containing all line objects


(ssget "P" '((0 . "LINE"))) from the last selection set created.
)

(setq ss1 Creates a selection set of all objects inside the


(ssget "W" pt1 pt2 '((8 . "FLOOR9"))) window that are also on layer FLOOR9.
)

(setq ss1 Creates a selection set of all objects in the


(ssget "X" '((0 . "CIRCLE"))) database that are Circle objects.
)

(setq ss1 Creates a selection set of all blue Line objects that
(ssget "I" '((0 . "LINE") (62 . 5))) are part of the Implied selection set (those objects
) selected while the AutoCAD PICKFIRST system
variable is in effect).
Note that this filter picks up lines that have been
assigned color 5 (blue), but not blue lines that
have had their color applied by the ByLayer or
ByBlock properties.

If both the group code and the desired value are known, the list may be quoted as shown
previously. If either is specified by a variable, the list must be constructed using
the list and cons function. For example, the following code creates a selection set of
all objects in the database that are on layer FLOOR3:
(setq lay_name "FLOOR3")

(setq ss1

(ssget "X"

(list (cons 8 lay_name))


)

If the filter-list specifies more than one property, an entity is included in the selection set
only if it matches all specified conditions, as in the following example code:
(ssget "X" (list (cons 0 "CIRCLE")(cons 8 lay_name)(cons 62 3)))

This code selects only Circle objects on layer FLOOR3 that are colored green. This type
of test performs a Boolean “AND” operation.

The ssget function filters a selection set by scanning the selected entities and
comparing the fields of each main entity against the specified filtering list. If an entity's
properties match all specified fields in the filtering list, it is included in the returned
selection set. Otherwise, the entity is not included in the selection set.
The ssget function returns nil if none of the selected entities match the specified
filtering criteria.
Note: The meaning of certain group codes can differ from entity to entity, and not all
group codes are present in all entities. If a particular group code is specified in a filter,
entities not containing that group code are excluded from the selection set
that ssgetreturns.
When ssget filters a selection set, the selected objects it retrieves might include entities
from both paper space and model space. However, when the selection set is passed to
an AutoCAD command, only entities from the space that is currently in effect are used.
(The space to which an entity belongs is specified by the value of its 67 group code.)

Related Concepts

 About Selecting Objects and Selection Sets (AutoLISP)


 About Modifying Selection Sets (AutoLISP)
 About Logical Grouping of Selection Filter Tests (AutoLISP)
 About Relational Tests in Filter Lists for Selection Sets (AutoLISP)
 About Wild-Card Patterns in Selection Set Filter Lists (AutoLISP)
 About Filtering for Extended Data in a Selection Set (AutoLISP)
 Selection Set Manipulation Functions Reference (AutoLISP)

About Wild-Card Patterns in Selection Set Filter Lists


(AutoLISP)

Symbol names specified in filtering lists can include wild-card patterns.

The wild-card patterns recognized by ssget are the same as those recognized by
the wcmatch function. When filtering for anonymous blocks, you must precede the *
character with a reverse single quotation mark ( ` ), also known as an escape character,
because the * is read by ssget as a wild-card character.

For example, you can retrieve an anonymous block named *U2 with the following:
(ssget "X" '((2 . "`*U2")))
Related Concepts

 About Selecting Objects and Selection Sets (AutoLISP)


 About Modifying Selection Sets (AutoLISP)
 About Selection Set Filter Lists (AutoLISP)
 About Logical Grouping of Selection Filter Tests (AutoLISP)
 About Relational Tests in Filter Lists for Selection Sets (AutoLISP)
 About Filtering for Extended Data in a Selection Set (AutoLISP)
 Selection Set Manipulation Functions Reference (AutoLISP)

About Filtering for Extended Data in a Selection Set (AutoLISP)

You can select all entities containing extended data for a particular application using
the filter-list argument of ssget.

The filter-list argument must be a list that contains -3 as its first element. The following
example code selects all the objects in a drawing that include extended data for the
"APPNAME" application:
(ssget "X" '((-3 ("APPNAME"))))

You can also expand the scope of the filter to filter specific types of objects. The following
example code selects all the circles in a drawing that include extended data for the
"APPNAME" application:
(ssget "X" '((0 . "CIRCLE") (-3 ("APPNAME"))))

If more than one application name is included in the -3 group's list, an AND operation is
implied and the entity must contain extended data for all of the specified applications. So,
the following statement would select all the objects with extended data for both the
"APP1" and "APP2" applications:
(ssget "X" '((-3 ("APP1")("APP2"))))

Wild-card matching is also permitted, so either of the following statements will select all
the objects with extended data for either or both of these applications.
(ssget "X" '((-3 ("APP[12]"))))

(ssget "X" '((-3 ("APP1,APP2"))))

Related Concepts

 About Extended Data - Xdata (AutoLISP)


 About Attaching Extended Data to an Entity (AutoLISP)
 About Extended Data Group Codes (AutoLISP)
 About Retrieving Extended Data (AutoLISP)
 About Selecting Objects and Selection Sets (AutoLISP)
 About Selection Set Filter Lists (AutoLISP)
 About Registered Applications (AutoLISP)
 Extended Data-Handling Functions Reference (AutoLISP)
About Relational Tests in Filter Lists for Selection Sets
(AutoLISP)

Unless otherwise specified, an equivalency is implied for each item in the filter-list.

For numeric group codes (integers, reals, points, and vectors), you can specify other
relations by including a special -4 group code that specifies a relational operator. The
value of a -4 group code is a string indicating the test operator to be applied to the next
group in the filter-list.
The following selects all circles with a radius (group code 40) greater than or equal to
2.0:
(ssget "X" '((0 . "CIRCLE") (-4 . ">=") (40 . 2.0)))

The possible relational operators are shown in the following table:

Relational operators for selection set filter lists

Operator Description

"*" Anything goes (always true)

"=" Equals

"!=" Not equal to

"/=" Not equal to

"<>" Not equal to

"<" Less than

"<=" Less than or equal to

">" Greater than

">=" Greater than or equal to

"&" Bitwise AND (integer groups only)

"&=" Bitwise masked equals (integer groups only)

The use of relational operators depends on the kind of group code value you are testing:

 All relational operators except for the bitwise operators ("&" and "&=") are valid
for both real- and integer-valued groups.
 The bitwise operators "&" and "&=" are valid only for integer-valued groups. The
bitwise AND, "&", is true if ((integer_group & filter) /= 0)—that is, if any of
the bits set in the mask are also set in the integer group code. The bitwise masked
equals, "&=", is true if ((integer_group & filter) = filter)—that is, if all bits
set in the mask are also set in the integer_group(other bits might be set in
the integer_group but are not checked).
 For point group codes, the X, Y, and Z tests can be combined into a single string,
with each operator separated by commas (for example, ">,>,*"). If an operator is
omitted from the string (for example, "=,<>" leaves out the Z test), then the “anything
goes” operator, "*", is assumed.
 Direction vectors (group code 210) can be compared only with the
operators "*", "=", and "!=" (or one of the equivalent “not equal” strings).
 You cannot use the relational operators with string group codes; use wild-card
tests instead.

Related Concepts

 About Selection Set Filter Lists (AutoLISP)


 About Selecting Objects and Selection Sets (AutoLISP)
 About Modifying Selection Sets (AutoLISP)
 About Logical Grouping of Selection Filter Tests (AutoLISP)
 About Wild-Card Patterns in Selection Set Filter Lists (AutoLISP)
 About Filtering for Extended Data in a Selection Set (AutoLISP)
 Selection Set Manipulation Functions Reference (AutoLISP)

About Logical Grouping of Selection Filter Tests (AutoLISP)

You can define test groups with nested Boolean expressions to filter objects from a
selection set created with ssget.

The following table lists the grouping operators that you can use to filter selection sets:

Grouping operators for selection set filter lists

Starting operator Encloses Ending operator

"<AND" One or more operands "AND>"

"<OR" One or more operands "OR>"

"<XOR" Two operands "XOR>"

"<NOT" One operand "NOT>"

The grouping operators are specified by -4 dxf group codes, like the relational operators.
They are paired and must be balanced correctly in the filter list or the ssget call will fail.
(ssget "X"

'(

(-4 . "<OR")

(-4 . "<AND")

(0 . "CIRCLE")

(40 . 1.0)

(-4 . "AND>")
(-4 . "<AND")

(0 . "LINE")

(8 . "ABC")

(-4 . "AND>")

(-4 . "OR>")

This filter list allows the selection of all circles with a radius of 1.0 plus all lines on layer
"ABC". The grouping operators are not case-sensitive; for example, you can
specify "and>", "<or", instead of "AND>", "<OR". Grouping operators are not allowed
within the -3 dxf group code. Multiple application names specified in a -3 dxf group code
use an implied AND operator. If you want to test for extended data using other grouping
operators, specify separate -3 dxf group codes and group them as desired.
The following example code demonstrates how to select all circles having extended data
for either application "APP1" or "APP2" but not both:
(ssget "X"

'((0 . "CIRCLE")

(-4 . "<XOR")

(-3 ("APP1"))

(-3 ("APP2"))

(-4 . "XOR>")

You can simplify the coding of frequently used grouping operators by setting them equal
to a symbol. The previous example could be rewritten as follows (notice that in this
example you must explicitly quote each list):
(setq <xor '(-4 . "<XOR")

xor> '(-4 . "XOR>"))

(ssget "X"

(list

'(0 . "CIRCLE")

<xor

'(-3 ("APP1"))
'(-3 ("APP2"))

xor>

Related Concepts

 About Selecting Objects and Selection Sets (AutoLISP)


 About Selection Set Filter Lists (AutoLISP)
 About Modifying Selection Sets (AutoLISP)
 About Relational Tests in Filter Lists for Selection Sets (AutoLISP)
 About Filtering for Extended Data in a Selection Set (AutoLISP)
 Selection Set Manipulation Functions Reference (AutoLISP)

Selection Set Manipulation Functions Reference (AutoLISP)

The following table provides summary descriptions of the AutoLISP selection set
manipulation functions.

Selection set manipulation functions

Function Description

(ssadd [ename [ss]]) Adds an object (entity) to a selection set, or creates a new
selection set

(ssdel ename ss) Deletes an object (entity) from a selection set

(ssget [mode] [pt1 [pt2]] [pt-list] [filter-list]) Prompts the user to select objects (entities), and returns a
selection set

(ssgetfirst) Determines which objects are selected and gripped

(sslength ss) Returns an integer containing the number of objects (entities)


in a selection set

(ssmemb ename ss) Tests whether an object (entity) is a member of a selection set

(ssname ss index) Returns the object (entity) name of the indexed element of a
selection set

(ssnamex ss index) Retrieves information about how a selection set was created

(sssetfirst gripset [pickset]) Sets which objects are selected and gripped

Related Reference

 ssadd (AutoLISP)
 ssdel (AutoLISP)
 ssget (AutoLISP)
 ssgetfirst (AutoLISP)
 sslength (AutoLISP)
 ssmemb (AutoLISP)
 ssname (AutoLISP)
 ssnamex (AutoLISP)
 sssetfirst (AutoLISP)
 AutoLISP Functions By Name and Feature Reference (AutoLISP)

About the DXF Format (DXF)

The DXF™ format is a tagged data representation of all the information contained in an
AutoCAD ® drawing file.  Tagged data means that each data element in the file is preceded by an
integer number that is called a group code. A group code's value indicates what type of data
element follows. This value also indicates the meaning of a data element for a given object (or
record) type. Virtually all user-specified information in a drawing file can be represented in DXF
format.

Related Concepts

 About DXF Formatting Conventions


 About Object and Entity Codes (DXF)
 Group Code Value Types Reference (DXF)
 DXF Group Codes in Numerical Order Reference

Related Reference

 About the DXF HEADER Section


 About the DXF CLASSES Section
 About the DXF TABLES Section (DXF)
 About the DXF BLOCKS Section
 About the DXF ENTITIES Section
 About the DXF OBJECTS Section
 About the DXF THUMBNAILIMAGE Section

Functions Reference (AutoLISP)

Listing of AutoLISP functions by alphabetic name and feature.

Alphabetic List
ABCDEFGHIJKLMNOPQRSTUVWXYZ

Non-alphabetic

External

Feature List
Basic
Core functions that are used to perform mathematical calculations, manipulate list and
strings, provide error handling for programs, and much more.

Application-Handling
Arithmetic

Equality and Conditionals

Error-Handling

Function-Handling

List Manipulation

String-Handling

Symbol-Handling

Utility
Functions that are used to convert between data types, work with standard AutoCAD
commands, get input from the user at the command prompt, and much more.

Data Conversion

Device Access

Display Control

File-Handling

Geometric

Query and Command

User Input

Memory Management

Windows Registry and Property List Files

Selection Set, Object, and Symbol Table


Functions used to work with extended data (Xdata), manipulate and select objects, and
work with symbol tables and dictionaries.

Extended Data-Handling

Object-Handling

Selection Set Manipulation

Symbol Table and Dictionary-Handling

Programmable Dialog Boxes - DCL (Windows only)


Functions used to display and implement actions for dialog boxes defined in DCL files.

Dialog Box Opening and Closing

Tile- and Attribute-Handling

List Box and Pop-Up List-Handling

Image Tile-Handling

Application-Specific Data-Handling

Tile Attributes Reference


Tiles Reference

Visual LISP Extensions for AutoLISP (Windows only)


Functions used to utilize the AutoCAD and other third-party ActiveX/COM APIs with
AutoLISP.

ActiveX Collection Manipulation

ActiveX Data Conversion

ActiveX Method Invocation

ActiveX Object-Handling

ActiveX Property-Handling

Curve Measurement

Dictionary

Handling Drawing Objects

Reactors

VLX Namespace

Namespace Communication

Topics in this section

 Non-alphabetic Functions Reference (AutoLISP)


These AutoLISP functions all start non-alphabetic or numeric characters.
 A Functions Reference (AutoLISP)
These AutoLISP functions all start with 'A'.
 B Functions Reference (AutoLISP)
These AutoLISP functions all start with 'B'.
 C Functions Reference (AutoLISP)
These AutoLISP functions all start with 'C'.
 D Functions Reference (AutoLISP)
These AutoLISP functions all start with 'D'.
 E Functions Reference (AutoLISP)
These AutoLISP functions all start with 'E'.
 F Functions Reference (AutoLISP)
These AutoLISP functions all start with 'F'.
 G Functions Reference (AutoLISP)
These AutoLISP functions all start with 'G'.
 H Functions Reference (AutoLISP)
These AutoLISP functions all start with 'H'.
 I Functions Reference (AutoLISP)
These AutoLISP functions all start with 'I'.
 L Functions Reference (AutoLISP)
These AutoLISP functions all start with 'L'.
 M Functions Reference (AutoLISP)
These AutoLISP functions all start with 'M'.
 N Functions Reference (AutoLISP)
These AutoLISP functions all start with 'N'.
 O Functions Reference (AutoLISP)
These AutoLISP functions all start with 'O'.
 P Functions Reference (AutoLISP)
These AutoLISP functions all start with 'P'.
 Q Functions Reference (AutoLISP)
These AutoLISP functions all start with 'Q'.
 R Functions Reference (AutoLISP)
These AutoLISP functions all start with 'R'.
 S Functions Reference (AutoLISP)
These AutoLISP functions all start with 'S'.
 T Functions Reference (AutoLISP)
These AutoLISP functions all start with 'T'.
 U Functions Reference (AutoLISP)
These AutoLISP functions all start with 'U'.
 V Functions Reference (AutoLISP)
These AutoLISP functions all start with 'V'.
 W Functions Reference (AutoLISP)
These AutoLISP functions all start with 'W'.
 X Functions Reference (AutoLISP)
These AutoLISP functions all start with 'X'.
 Z Functions Reference (AutoLISP)
These AutoLISP functions all start with 'Z'.

Related Concepts

 About Function Syntax (AutoLISP)


 AutoLISP and Visual LISP (AutoLISP)

Related Reference

 New and Changed AutoLISP Functions Reference (AutoLISP)


 AutoLISP Developer's Guide (AutoLISP)
DIESEL Functions Reference

Status retrieval, computation, and display are performed by DIESEL functions.

All functions have a limit of 10 parameters, including the function name itself.

Function Description/Example

Returns the sum of the numbers val1 , val2 , …, val9 .


+ (addition)
$(+, val1 [, val2, …, val9])

If the current thickness is set to 5, the following DIESEL string returns 15.

$(+, $(getvar, thickness), 10)

- (subtraction) Returns the result of subtracting the numbers val2 through val9 from val1

$(-, val1 [, val2 , …, val9])

* (multiplication) Returns the result of multiplying the numbers val1 , val2 , …, val9 .

$(*, val1 [, val2, …, val9])

/ (division) Returns the result of dividing the number val1 by val2 , …, val9 .

$(/, val1 [, val2, …, val9])

= (equal to) If the numbers val1 and val2 are equal, the string returns 1; otherwise, it retu

$(=, val1, val2)

< (less Than) If the number val1 is less than val2 , the string returns 1; otherwise, it return

$(<, val1, val2)

The following expression gets the current value of HPANG; if the value is less th
variable USERR1, it returns 1. If the value 10.0 is stored in USERR1 and the cur
Function Description/Example

following string returns 0.

$(<, $(getvar, hpang), $(getvar, userr1))

> (greater Than) If the number val1 is greater than val2 , the string returns 1; otherwise, it ret

$(>, val1, val2)

!= (not Equal to) If the numbers val1 and val2 are not equal, the string returns 1; otherwise, it

$(!=, val1, val2)

<= (less Than or Equal to) If the number val1 is less than or equal to val2 , the string returns 1; otherwi

$(<=, val1, val2)

>= (greater Than or Equal to) If the number val1 is greater than or equal to val2 , the string returns 1; othe

$(>=, val1, val2)

and Returns the bitwise logical AND of the integers val1 through val9 .

$(and, val1 [, val2,…, val9])

angtos Returns the angular value in the format and precision specified.

$(angtos, value [, mode, precision])

Edits the given value as an angle in the format specified by the mode and pr
analogous AutoLISP function. If mode and precision are omitted, it uses th
UNITS command.
Note: AutoLISP is not available in AutoCAD LT.
The following mode values can be applied:

0, for Degrees
1, for Degrees/Minutes/Seconds
Function Description/Example

2, for Grads
3, for Radians

4, for Surveyor's Units

Edtime Returns a formatted date and time based on a given picture.

$(edtime, time, picture)

Edits the Julian date given by time (obtained, for example, from $(getvar,d
given picture ). The picture consists of format phrases replaced by specif
time. Characters not interpretable as format phrases are copied literally into the re
phrases are defined as shown in the following table.
For example, assume that the date and time are Saturday, 5 September 1998 4:53
phrases and output examples for edtime are as follows:

D-5
DD - 05
DDD - Sat
DDDD - Saturday
M-9
MO - 09
MON - Sep
MONTH - September
YY - 98
YYYY - 1998
H-4
HH - 04
MM - 53
SS - 17
MSEC - 506
AM/PM - AM
am/pm - am
A/P - A
a/p - a

Enter the entire AM/PM phrase as shown in the preceding table; if AM is used alon
the M will return the current month.
If any AM/PM phrases appear in the picture, the H and HH phrases edit the time ac
(12:00-12:59 1:00-11:59) instead of the 24-hour clock (00:00-23:59).
The following example uses the date and time from the preceding table. Notice th
quotation marks because it is read as an argument separator.

$(edtime, $(getvar,date), DDD"," DD MON YYYY - H:MMam/pm)

It returns the following:


Sat, 5 Sep 1998 - 4:53am
Function Description/Example

If time is 0, the time and date at the moment that the outermost macro was exec
and time-consuming multiple calls on $(getvar,date) and guarantees that s
(edtime) macros all use the same time.

eq If the strings val1 and val2 are identical, the string returns 1; otherwise, it re

$(eq, val1, val2)

The following expression gets the name of the current layer; if the name matches
USERS1 (USERS1-5) system variable, it returns 1. Assume the string "PART12
current layer is the same.
Note: The USERS1-5 system variables are not available in AutoCAD LT.

$(eq, $(getvar, users1), $(getvar, clayer))

It returns the following:


1

Eval Passes the string str to the DIESEL evaluator and returns the result of evaluatin

$(eval, str)

fix Truncates the real number value to an integer by discarding any fractional part

$(fix, value)

Getenv Returns the value of the environment variable varname .

$(getenv, varname)

If no variable with that name is defined, it returns the null string.

Getvar Returns the value of the system variable with the given varname .

$(getvar, varname)

if Conditionally evaluates expressions.


Function Description/Example

$(if, expr, dotrue [, dofalse])

If expr is nonzero, it evaluates and returns dotrue . Otherwise, it evaluates


the branch not chosen by expr is not evaluated.

Index Returns the specified member of a comma-delimited string.

$(index, which, string)

Assumes that the string argument contains one or more values delimited by th
character, the comma. The which argument selects one of these values to be ex
numbered 0. This function is most frequently used to extract X, Y, or Z coordinate
returned by $(getvar).
Applications can use this function to retrieve values stored as comma-delimited s
variables.
Note: The USERS1-5 system variables are not available in AutoCAD LT.

nth Evaluates and returns the argument selected by which .

$(nth, which, arg0 [, arg1,…, arg7])

If which is 0, nth returns arg0 , and so on. Note the difference between $(n
(nth) returns one of a series of arguments to the function, while $(index)
delimited string passed as a single argument. Arguments not selected by whicha

or Returns the bitwise logical OR of the integers val1 through val9 .

$(or, val1 [, val2,…, val9])

Rtos Returns the real value in the format and precision specified.

$(rtos, value [, mode, precision])

Edits the given value as a real number in the format specified


by mode and precision. If modeand precision are omitted, it uses the
UNITS command.

Strlen Returns the length of string in characters.

$(strlen, string)
Function Description/Example

Substr Returns the substring of string , starting at character start and extending f

$(substr, string, start [, length])

Characters in the string are numbered from 1. If length is omitted, it returns th


string.

Upper Returns the string converted to uppercase according to the rules of the curren

$(upper, string)

xor Returns the bitwise logical XOR of the integers val1 through val9 .

$(xor, val1 [, val2,…, val9])

Related Concepts

 About MODEMACRO Values


 About Responding to AutoLISP with DIESEL Expressions in Macros
 About DIESEL Expressions in Macros

Related Reference

 DIESEL Error Message Reference

You might also like