<?xml version="1.0"?>
<rss version="2.0"><channel><title><![CDATA[AutoLISP, Visual LISP &amp; DCL Latest Topics]]></title><link>https://www.cadtutor.net/forum/forum/15-autolisp-visual-lisp-amp-dcl/</link><description><![CDATA[AutoLISP, Visual LISP &amp; DCL Latest Topics]]></description><language>en</language><item><title>about grread deselect objects</title><link>https://www.cadtutor.net/forum/topic/99162-about-grread-deselect-objects/</link><description><![CDATA[<p>
	Is it possible to use the grread function to deselect objects by holding down the SHIFT key+left click?
</p>
]]></description><guid isPermaLink="false">99162</guid><pubDate>Sun, 14 Jun 2026 16:31:29 +0000</pubDate></item><item><title>Insert a copy of the block at the specified point. CopyRenameBlockV1-5.lsp /Lee Mac/</title><link>https://www.cadtutor.net/forum/topic/99155-insert-a-copy-of-the-block-at-the-specified-point-copyrenameblockv1-5lsp-lee-mac/</link><description><![CDATA[<p>
	Hi, everybody.<br />
	In this code, a copy of the block is superimposed on the original, <br />
	how to change the code to insert a copy of the block at the specified point.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted"><span class="pln">;;-----------------=={ Copy/Rename Block Reference }==------------------;;
;;----------------------------------------------------------------------;;
;;  Author:  Lee Mac, Copyright   2013  -  www.lee-mac.com              ;;
;;----------------------------------------------------------------------;;
;;  Version 1.5    -    05-07-2013                                      ;;
;;----------------------------------------------------------------------;;

(defun c:cb nil (LM:RenameBlockReference   t))
(defun c:rb nil (LM:RenameBlockReference nil))

(defun LM:RenameBlockReference ( cpy / *error* abc app dbc dbx def doc dxf new old prp src tmp vrs )

    (defun *error* ( msg )
        (if (and (= 'vla-object (type dbx)) (not (vlax-object-released-p dbx)))
            (vlax-release-object dbx)
        )
        (if (not (wcmatch (strcase msg t) "*break,*cancel*,*exit*"))
            (princ (strcat "\nError: " msg))
        )
        (princ)
    )
    
    (while
        (progn
            (setvar 'errno 0)
            (setq src (car (entsel (strcat "\nSelect block reference to " (if cpy "copy &amp; " "") "rename: "))))
            (cond
                (   (= 7 (getvar 'errno))
                    (princ "\nMissed, try again.")
                )
                (   (= 'ename (type src))
                    (setq dxf (entget src))
                    (cond
                        (   (/= "INSERT" (cdr (assoc 0 dxf)))
                            (princ "\nPlease select a block reference.")
                        )
                        (   (= 4 (logand 4 (cdr (assoc 70 (tblsearch "layer" (cdr (assoc 8 dxf)))))))
                            (princ "\nSelected block is on a locked layer.")
                        )
                    )
                )
            )
        )
    )
    (if (= 'ename (type src))
        (progn
            (setq app (vlax-get-acad-object)
                  doc (vla-get-activedocument app)
                  src (vlax-ename-&gt;vla-object src)
                  old (vlax-get-property src (if (vlax-property-available-p src 'effectivename) 'effectivename 'name))
                  tmp 0
            )
            (while (tblsearch "block" (setq def (strcat (vl-string-left-trim "*" old) "_" (itoa (setq tmp (1+ tmp)))))))
            (while
                (and (/= "" (setq new (getstring t (strcat "\nSpecify new block name &lt;" def "&gt;: "))))
                    (or (not (snvalid new))
                        (tblsearch "block" new)
                    )
                )
                (princ "\nBlock name invalid or already exists.")
            )
            (if (= "" new)
                (setq new def)
            )
            (setq dbx
                (vl-catch-all-apply 'vla-getinterfaceobject
                    (list app
                        (if (&lt; (setq vrs (atoi (getvar 'acadver))) 16)
                            "objectdbx.axdbdocument"
                            (strcat "objectdbx.axdbdocument." (itoa vrs))
                        )
                    )
                )
            )
            (if (or (null dbx) (vl-catch-all-error-p dbx))
                (princ "\nUnable to interface with ObjectDBX.")
                (progn
                    (setq abc (vla-get-blocks doc)
                          dbc (vla-get-blocks dbx)
                    )
                    (vlax-invoke doc 'copyobjects (list (vla-item abc old)) dbc)
                    (if (wcmatch old "`**")
                        (vla-put-name (vla-item dbc (1- (vla-get-count dbc))) new)
                        (vla-put-name (vla-item dbc old) new)
                    )
                    (vlax-invoke dbx 'copyobjects (list (vla-item dbc new)) abc)
                    (vlax-release-object dbx)
                    (if cpy (setq src (vla-copy src)))
                    (if
                        (and
                            (vlax-property-available-p src 'isdynamicblock)
                            (= :vlax-true (vla-get-isdynamicblock src))
                        )
                        (progn
                            (setq prp (mapcar 'vla-get-value (vlax-invoke src 'getdynamicblockproperties)))
                            (vla-put-name src new)
                            (mapcar
                               '(lambda ( a b )
                                    (if (/= "ORIGIN" (strcase (vla-get-propertyname a)))
                                        (vla-put-value a b)
                                    )
                                )
                                (vlax-invoke src 'getdynamicblockproperties) prp
                            )
                        )
                        (vla-put-name src new)
                    )
                    (if (= :vlax-true (vla-get-isxref (setq def (vla-item (vla-get-blocks doc) new))))
                        (vla-reload def)
                    )
                    (if cpy (sssetfirst nil (ssadd (vlax-vla-object-&gt;ename src))))
                )
            )
        )
    )
    (princ)
)

;;----------------------------------------------------------------------;;

(vl-load-com)
(princ
    (strcat
        "\n:: CopyRenameBlock.lsp | Version 1.5 | \\U+00A9 Lee Mac "
        (menucmd "m=$(edtime,$(getvar,date),YYYY)")
        " www.lee-mac.com ::"
        "\n:: Available Commands:"
        "\n::    \"CB\"  -  Copy &amp; Rename Block Reference."
        "\n::    \"RB\"  -  Rename Block Reference."
    )
)
(princ)

;;----------------------------------------------------------------------;;
;;                             End of File                              ;;
;;----------------------------------------------------------------------;;</span></pre>

<p>
	 
</p>
]]></description><guid isPermaLink="false">99155</guid><pubDate>Tue, 09 Jun 2026 14:39:26 +0000</pubDate></item><item><title>Help to Modify Existing Line Annotation LISP</title><link>https://www.cadtutor.net/forum/topic/99157-help-to-modify-existing-line-annotation-lisp/</link><description><![CDATA[<p>
	I have this Lisp (Edited by me) that works really well.
</p>

<p>
	However I would really appreciated being able to incorporate three things beyond my skill level:
</p>

<p>
	- Arc Lengths with the prefix "A"
</p>

<p>
	- Mtext output rather than standard Text<span style="font-size:9px;"><em> </em></span><span style="font-size:11px;"><em>(I tried simply changing TEXT to MTEXT and a few other tweaks without success)</em></span>
</p>

<p>
	- Remove trailing 00" <span style="font-size:11px;"><em>(I already have a work around for this but it would be great to have incorporated into the existing lisp)</em></span>
</p>

<p>
	 
</p>

<p>
	Any help is greatly appreciated.
</p>

<p>
	 
</p>

<pre class="ipsCode">;;Bearing and Distance 4 © 2020 Ronald Harman (dlanorh)
;;Released under MIT Licence https://opensource.org/licenses/MIT

(vl-load-com)

(defun rh:R2D (r) (* 180.0 (/ r pi)))

(defun gc:round (num prec) (if (zerop (setq prec (abs prec))) num (* prec (fix ((if (minusp num) - +) (/ num prec) 0.5)))))

(defun rh:midpoint ( pt1 pt2 / pt3 ) (setq pt3 (mapcar '(lambda (x y) (/ (+ x y) 2)) pt1 pt2)))

(defun rh:2azimuth ( a_brg / d a_azi)
  (setq d (fix a_brg))
  (cond ((and (&gt;= d 0) (&lt; d 90)) (setq a_azi (- 90 a_brg)))
        ((and (&gt;= d 90) (&lt; d 180)) (setq a_azi (- 360 (- a_brg 90))))
        ((and (&gt;= d 180) (&lt; d 270)) (setq a_azi (- 270 (- a_brg 180))))
        ((and (&gt;= d 270) (&lt; d 360)) (setq a_azi (- 90 (- a_brg 360))))
  )
  (setq d a_azi)
);_end_defun

; converts radian brg to dms text
(defun rh:2dms ( r_brg rnd / d_brg d m s b_str)
  (setq d_brg (rh:2azimuth (rh:R2D r_brg))
        d (fix d_brg)
        m (fix (* (rem d_brg 1.0) 60))
        s (gc:round (* (rem (* (rem d_brg 1.0) 60) 1.0) 60) rnd)
  );_end_setq
  (if (&gt;= s 59.5) (setq m (1+ m) s 0.0))
  (if (= m 60) (setq d (1+ d) m 0))
  (if (&gt;= d 360) (setq d (- d 360)))
  (setq s (rtos s 2 0) m (itoa m) d (itoa d))
  (if (&lt; (atoi s) 10) (setq s (strcat "0" s)))
  (if (&lt; (atoi m) 10) (setq m (strcat "0" m)))
  ;(while (&lt; (strlen d) 3) (setq d (strcat "0" d)))
  (setq b_str (strcat d "\260" m "'" s "\""))
);_end_defun

(defun rh:em_txt ( pt txt lyr ang tht d72 d73)
  (entmakex (list '(0 . "TEXT") '(100 . "AcDbEntity") '(100 . "AcDbText")
                 (cons 8 lyr) (cons 50 ang) (cons 7 (getvar 'textstyle)) (cons 1 txt)
                 (cons 10 pt) (cons 40 tht) (cons 72 d72) (cons 11 pt) (cons 73  d73)
            )
  )
);end_defun

;;BEGIN MAIN ROUTINE
(defun C:BAD ( / *error* sv_lst sv_vals tht b_lyr_lst d_lyr_lst lyr_idx d_rnd a_rnd lans pik lyr_e l_lst lt dv txt b_lyr d_lyr l_obj l_ang a_txt l_txt m_pt i_ang d_pt)
(setvar "DIMZIN" 8)
  (defun *error* ( msg )
    (mapcar 'setvar sv_lst sv_vals)
    (if (not (wcmatch (strcase msg) "*BREAK*,*CANCEL*,*EXIT*")) (princ (strcat "\nOops an Error : " msg " occurred.")))
    (princ)
  );_end_*error*_defun

  (setq sv_lst (list 'cmdecho 'osmode 'dynmode 'dynprompt 'textsize)
        sv_vals (mapcar 'getvar sv_lst)
  );end_setq

  (mapcar 'setvar sv_lst '(0 0 3 1))

;; User Variables
  (setq b_lyr_lst (list "Text_3.5 Bearing" "Text_2.8 Bearing Connection") ;; Bearing Layer list (first item is always default)
        d_lyr_lst (list "Text_3.5 Distance" "Text_2.8 Distance Connection") ;; Distance Layer list (first item is always default)
        lyr_idx 0                               ;; Index for the above lists PLEASE DON'T CHANGE
        d_rnd 3                                 ;; Rounding for distance (Integer, number of decimal places)
        a_rnd 5.0                              ;; Rounding for angles (Real Seconds of Arc)
  );end_setq

  (initget "Boundaries Connections")
  (setq lans (cond ( (getkword (strcat "\nUse Boundaries (" (nth lyr_idx b_lyr_lst)" &amp; " (nth lyr_idx d_lyr_lst) ") or Connections Layers : ? [Boundaries/Connections] &lt;Boundaries&gt;"))) ("Boundaries")))
  (if (= lans "Connections") (setq lyr_idx 1 pik "Boundaries") (setq pik "Connections"))

  (setq b_lyr (nth lyr_idx b_lyr_lst) d_lyr (nth lyr_idx d_lyr_lst))

  (foreach lyr (list b_lyr d_lyr) (if (not (tblsearch "layer" lyr)) (setq lyr_e T l_lst (cons lyr l_lst))))

  (cond (lyr_e
          (if (= (length l_lst) 2)  (setq lt "layers" dv " , ") (setq lt "layer" dv ""))
          (setq txt (strcat "MISSING LAYERS\n\nOption " lans " " lt " : "))
          (mapcar '(lambda (x) (setq txt (strcat txt x dv))) l_lst)
          (setq txt (vl-string-right-trim " ," txt))
          (alert (strcat txt "\n\nPlease rectify missing " lt " or re-run\nand select " pik " option"))
        )
  );end_cond (missing layers)

  (initget 6)
  (setq tht (cond ( (getreal (strcat "\nEnter Text Size : &lt;" (rtos (getvar 'textsize) 2 3) "&gt;"))) ( (getvar 'textsize))))

  (cond ( (not lyr_e)
          (princ "\nSelect Lines : ")
          (setq ss (ssget '((0 . "LINE"))))
          (cond (ss
                  (repeat (setq cnt (sslength ss))
                    (setq l_obj (vlax-ename-&gt;vla-object (setq ent (ssname ss (setq cnt (1- cnt)))))
                          elst (entget ent)
                          l_ang (angle '(0.0 0.0 0.0) (vlax-curve-getfirstderiv ent 0))
                          a_txt (rh:2dms l_ang a_rnd)
                          l_txt (rtos (vlax-curve-getdistatparam ent (vlax-curve-getendparam ent)) 2 d_rnd)
                          m_pt (rh:midpoint (vlax-get l_obj 'startpoint) (vlax-get l_obj 'endpoint))
                    );_end_setq
                    (setq i_ang l_ang)
                    (if (and (&gt;= l_ang (* pi 0.5)) (&lt; l_ang (* pi 1.5)))
                      (setq i_ang (- l_ang pi) d_pt (polar m_pt (- i_ang (* pi 0.5)) (* tht 0.3)))
                      (setq d_pt (polar m_pt (- i_ang (* pi 0.5)) (* tht 0.3)))
                    );end_if
                    (rh:em_txt m_pt a_txt b_lyr i_ang tht 1 1)
                    (rh:em_txt d_pt l_txt d_lyr i_ang tht 1 3)
                  );end_repeat
                )
          );end_cond
        )
  );end_cond
  (mapcar 'setvar sv_lst sv_vals)
  (princ)
);_end_defun
(princ)</pre>

<p>
	 
</p>
]]></description><guid isPermaLink="false">99157</guid><pubDate>Thu, 11 Jun 2026 00:19:44 +0000</pubDate></item><item><title>Retro Error Backtrace</title><link>https://www.cadtutor.net/forum/topic/99154-retro-error-backtrace/</link><description><![CDATA[<p>
	Back in the day (Autocad 14 or so) the autolisp interpreter would spit out the variable names in the line of code that bombed instead of the values (example below), making it much easier find the problem. This may be a newbie question from an old-timer. I never took the pains to learn the VLIDE. Is there something there that solves the problem?
</p>

<p>
	 
</p>

<p>
	Error: bad argument type: numberp: nil<br />
	Backtrace:<br />
	[0.57] (VL-BT)<br />
	[1.53] (#&lt;SUBR @0000018680e21a98 -lambda-&gt; "bad argument type: numberp: nil")<br />
	[2.49] (ill-fun-hk "bad argument type: numberp: nil")<br />
	[3.44] (((MSG) (IF (NOT (MEMBER MSG (QUOTE ("console break" "Function cancelled" "quit / exit abort" "")))) (PROGN (PRINC (STRCAT "\nError: " MSG)) (IF *DEBUG* (VL-BT))))) "bad argument type: numberp: nil")<br />
	[4.39] (_call-err-hook ((MSG) (IF (NOT (MEMBER MSG (QUOTE ("console break" "Function cancelled" "quit / exit abort" "")))) (PROGN (PRINC (STRCAT "\nError: " MSG)) (IF *DEBUG* (VL-BT))))) "bad argument type: numberp: nil")<br />
	[5.33] (sys-error "bad argument type: numberp: nil")<br />
	:ERROR-BREAK.28 nil<br />
	<span style="background-color:#f1c40f;">[6.25] (- nil 8.48089)</span><br />
	[7.19] (C:GT)<br />
	[8.15] (#&lt;SUBR @0000018680872c50 -rts_top-&gt;)<br />
	[9.12] (#&lt;SUBR @00000186807c8700 veval-str-body&gt; "(C:GT)" T #&lt;FILE internal&gt;)<br />
	:CALLBACK-ENTRY.6 (:CALLBACK-ENTRY)<br />
	:ARQ-SUBR-CALLBACK.3 (nil 0)<br />
	 
</p>
]]></description><guid isPermaLink="false">99154</guid><pubDate>Mon, 08 Jun 2026 15:09:41 +0000</pubDate></item><item><title>Incremental Numbering Suite</title><link>https://www.cadtutor.net/forum/topic/9470-incremental-numbering-suite/</link><description><![CDATA[<p>
	Hi Guys,
</p>

<p>
	 
</p>

<p>
	Wasn't that busy, so I thought I'd put together a little Incremental Numbering Suite for you all to sample.
</p>

<p>
	 
</p>

<p>
	I've come to realise that this kind of LISP seems to be quite a popular one in many trades, and this was my main inspiration for its creation.
</p>

<p>
	 
</p>

<p>
	As with all my programs - your comments and/or criticism is welcome, as this only helps to improve the program itself.
</p>

<p>
	 
</p>

<p>
	Thanks &amp; Enjoy!
</p>

<p>
	 
</p>

<p>
	Cheers
</p>

<p>
	 
</p>

<p>
	Lee
</p>

<p>
	 
</p>

<p>
	 
</p>

<p>
	<a href="http://lee-mac.com/numinc.html" rel="external nofollow"><span style="font-family:Georgia;"><span style="font-size:18px;">Incremental Numbering Suite</span></span></a>
</p>

<p>
	 
</p>

<p>
	<span style="font-size:12px;"><span style="font-family:Georgia;">Main Dialog Preview:</span></span>
</p>

<p>
	<img alt="spacer.png" class="ipsImage" data-ratio="83.40" height="623" style="height:auto;" width="747" data-src="https://lee-mac.com/lisp/gifs/NumIncV4-0.png" src="https://www.cadtutor.net/forum/applications/core/interface/js/spacer.png" />
</p>

<p>
	 
</p>

<p>
	Content Builder Preview:
</p>

<p>
	<img alt="NumIncV4-2_Build.png" class="ipsImage" data-ratio="79.81" height="514" style="height:auto;" width="644" data-src="https://lee-mac.com/lisp/gifs/NumIncV4-2_Build.png" src="https://www.cadtutor.net/forum/applications/core/interface/js/spacer.png" />
</p>

<p>
	 
</p>

<p>
	<span style="font-size:12px;"><span style="font-family:Georgia;">About Dialog Preview:</span></span>
</p>

<p>
	<img alt="spacer.png" class="ipsImage" data-ratio="191.10" height="644" style="height:auto;" width="337" data-src="https://lee-mac.com/lisp/gifs/NumIncV4-0_About.png" src="https://www.cadtutor.net/forum/applications/core/interface/js/spacer.png" />
</p>

<p>
	 
</p>

<p>
	<img alt="spacer.png" class="ipsImage" data-ratio="24.62" height="160" style="height:auto;" width="650" data-src="https://lee-mac.com/lisp/gifs/NumInc0.gif" src="https://www.cadtutor.net/forum/applications/core/interface/js/spacer.png" />
</p>

<p>
	 
</p>

<p>
	<img alt="spacer.png" class="ipsImage" data-ratio="24.69" height="160" style="height:auto;" width="648" data-src="https://lee-mac.com/lisp/gifs/NumInc1.gif" src="https://www.cadtutor.net/forum/applications/core/interface/js/spacer.png" />
</p>

<p>
	 
</p>

<p>
	<img alt="spacer.png" class="ipsImage" data-ratio="24.54" height="160" style="height:auto;" width="652" data-src="https://lee-mac.com/lisp/gifs/NumInc2.gif" src="https://www.cadtutor.net/forum/applications/core/interface/js/spacer.png" /><img alt="NumIncA2.gif" style="height:auto;" data-src="https://www.cadtutor.net/forum/applications/core/interface/js/spacer.png" src="https://www.cadtutor.net/forum/applications/core/interface/js/spacer.png" />
</p>

<p>
	 
</p>

<p>
	<img alt="spacer.png" class="ipsImage" data-ratio="24.54" height="160" style="height:auto;" width="652" data-src="https://lee-mac.com/lisp/gifs/NumInc3.gif" src="https://www.cadtutor.net/forum/applications/core/interface/js/spacer.png" />
</p>

<p>
	 
</p>

<p>
	<img alt="spacer.png" class="ipsImage" data-ratio="24.54" height="160" style="height:auto;" width="652" data-src="https://lee-mac.com/lisp/gifs/NumInc4.gif" src="https://www.cadtutor.net/forum/applications/core/interface/js/spacer.png" /><span style="font-family:Georgia;"><span style="font-size:12px;"> </span></span>
</p>

<p>
	 
</p>

<p>
	<img alt="spacer.png" class="ipsImage" data-ratio="24.54" height="160" style="height:auto;" width="652" data-src="https://lee-mac.com/lisp/gifs/NumInc5.gif" src="https://www.cadtutor.net/forum/applications/core/interface/js/spacer.png" />
</p>

<p>
	 
</p>

<p>
	<img alt="spacer.png" class="ipsImage" data-ratio="24.62" height="160" style="height:auto;" width="650" data-src="https://lee-mac.com/lisp/gifs/NumInc6.gif" src="https://www.cadtutor.net/forum/applications/core/interface/js/spacer.png" />
</p>

<p>
	 
</p>

<p>
	<span style="font-family:Georgia;"><span style="font-size:12px;">A full description of the program and the latest version can be found </span></span><a href="http://lee-mac.com/numinc.html" rel="external nofollow"><span style="font-family:Georgia;"><span style="font-size:12px;">here</span></span></a><span style="font-family:Georgia;"><span style="font-size:12px;">.</span></span>
</p>

<p>
	 
</p>
]]></description><guid isPermaLink="false">9470</guid><pubDate>Sun, 12 Apr 2009 19:07:52 +0000</pubDate></item><item><title>Boundary command</title><link>https://www.cadtutor.net/forum/topic/99146-boundary-command/</link><description><![CDATA[<p>
	Hi<br />
	I’ve run into this problem several times, but I was never able to understand why — until today.<br />
	Sometimes I need to use the "boundary" command to obtain the perimeter of complex enclosed areas, but occasionally the area of the region returned by the command does not match the expected value.<br />
	Today, I finally discovered why.
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" href="https://www.cadtutor.net/forum/uploads/monthly_2026_05/Img1-2.png.b023165a8968d81cbf03d491a1679f6a.png" data-fileid="70372" data-fileext="png" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="70372" data-ratio="73.50" width="800" alt="Img1-2.thumb.png.b994785efc1d96ff870e78188ebdeeb6.png" data-src="https://www.cadtutor.net/forum/uploads/monthly_2026_05/Img1-2.thumb.png.b994785efc1d96ff870e78188ebdeeb6.png" src="https://www.cadtutor.net/forum/applications/core/interface/js/spacer.png" /></a><br />
	In the image, I show an example of this. The thick yellow line is part of the original geometry, while the thinner dark-colored line is the one returned by "boundary".<br />
	I repeated the command several times, but it always makes the same mistake.<br />
	Does anyone understand why this happens?<br />
	Is it possible to solve it somehow?
</p>

<p>
	<br />
	Thanks in advance.
</p>
]]></description><guid isPermaLink="false">99146</guid><pubDate>Sat, 30 May 2026 00:08:42 +0000</pubDate></item><item><title>Automatically placing borehole tables with leaders without overlap</title><link>https://www.cadtutor.net/forum/topic/99141-automatically-placing-borehole-tables-with-leaders-without-overlap/</link><description><![CDATA[<p>
	Hi everyone,
</p>

<p>
	I’m working on a complex borehole location drawing in AutoCAD with many boreholes and corresponding data tables. When a new borehole is added, I would like to have an AutoLISP routine that can automatically place a new table and leader for that borehole without overlapping the existing tables.
</p>

<p>
	The layout concept is roughly like the attached image:
</p>

<p>
	Each borehole is a point/block near the center of the drawing.
</p>

<p>
	Each borehole has a data table placed outside the central cluster.
</p>

<p>
	A leader (polyline or multileader) connects the borehole to its table, using straight segments and preferably angles that are multiples of 60 degrees (or similar fixed angles).
</p>

<p>
	When space on one side is not available, the routine should try other directions until it finds a free spot between the existing tables.
</p>

<p>
	What I would like the routine to do is:
</p>

<p>
	Take the new borehole (block or point) as input.
</p>

<p>
	Use a standard table block (or AutoCAD table) with a known size and insertion point.
</p>

<p>
	Search along several radial directions (0°, 60°, 120°, 180°, 240°, 300° or similar) at a given distance to find a position where the table’s bounding box does not overlap existing tables or a central “no‑go” area.
</p>

<p>
	Insert the new table at the first (or best) free position and draw the leader from the borehole to the table with clean, orthogonal/60° segments.
</p>

<p>
	I have some AutoLISP experience and I’m thinking about using:
</p>

<p>
	Block/table bounding boxes (vla-getBoundingBox) for collision checks.
</p>

<p>
	Simple rectangle overlap tests to avoid collisions.
</p>

<p>
	Polar coordinates for candidate positions at fixed angles and distances.
</p>

<p>
	Before I start building this “placement engine” from scratch, I’d really like your feedback:
</p>

<p>
	Has anyone already written something similar (automatic table/label placement around a central cluster, avoiding overlaps)?
</p>

<p>
	From your experience, is this approach (block + attributes + leader + bounding‑box collision tests) reasonable, or is there a better pattern?
</p>

<p>
	Any tips on robust overlap detection or examples of similar LISP routines you recommend looking at?
</p>

<p>
	Would you implement this with standard tables, block attributes, or something else for the borehole information ?
</p>

<p>
	Any ideas, sample code, or links to existing routines would be greatly appreciated. Thanks in advance for your time and suggestions!
</p>

<p>
	 
</p>

<p>
	** Find attached plz
</p>
<p>
<a class="ipsAttachLink" href="https://www.cadtutor.net/forum/applications/core/interface/file/attachment.php?id=70350&amp;key=9729556193b2d670a3ec7338ddddd114" data-fileExt='pdf' data-fileid='70350' data-filekey='9729556193b2d670a3ec7338ddddd114'>11.pdf</a></p>]]></description><guid isPermaLink="false">99141</guid><pubDate>Mon, 25 May 2026 16:19:54 +0000</pubDate></item><item><title>A CODE FOR DIVIDING OBJECTS WITH POINTS AS IN MEASURE AND DIVIDE COMMAND IN AUTOCAD BUT WAY MORE ADVANCED</title><link>https://www.cadtutor.net/forum/topic/99149-a-code-for-dividing-objects-with-points-as-in-measure-and-divide-command-in-autocad-but-way-more-advanced/</link><description><![CDATA[<p>
	<a class="ipsAttachLink" data-fileext="LSP" data-fileid="70384" href="https://www.cadtutor.net/forum/applications/core/interface/file/attachment.php?id=70384&amp;key=4aa1a4f3e4a95eb67ac6dbb2996ca42f" rel="">DIVCURVES-INSERTING POINTS AS SPECIFIC DISTANCE.LSP</a><br />
	<br />
	<strong>I am so sorry for not giving more details about the code.<br />
	Please read the following for more details:</strong><br />
	 
</p>

<p>
	 When executed, the utility launches an interactive keyword configuration:  
</p>

<p>
	 Menu: [1-Polylines/2-Lines/3-Arcs/4-Circles/5-Splines/6-FeatureLines/7-All] 
</p>

<p>
	                                                                            
</p>

<p>
	 --- OPTION 1: Polylines ---                                                
</p>

<p>
	  - Target: Native 2D LWPolylines and 3D Heavy Polylines (*POLYLINE).       
</p>

<p>
	  - Sub-Prompts: Asks for both "Curve distance" and "Line distance".         
</p>

<p>
	  - Workflow Logic: Polylines frequently alternate between straight tangents 
</p>

<p>
	    and arced bulges. The engine runs through each sub-segment parameter,   
</p>

<p>
	    applying the Curve interval on loops returning a non-zero bulge and the 
</p>

<p>
	    Line interval on zero-bulge vectors. Critical for tracking centerlines. 
</p>

<p>
	                                                                            
</p>

<p>
	 --- OPTION 2: Lines ---                                                    
</p>

<p>
	  - Target: Standalone native LINE entities (completely ignores curves).    
</p>

<p>
	  - Sub-Prompts: Triggers only "Line distance [Middle/Vertices]".           
</p>

<p>
	  - Workflow Logic:                                                         
</p>

<p>
	    * Absolute Number: Measures out fixed structural intervals from start.  
</p>

<p>
	    * "Middle": Drops a single layout node at exactly Total Length / 2.      
</p>

<p>
	    * "Vertices": Flags only the absolute start and endpoints, bypassing    
</p>

<p>
	       any segment division calculations. Perfect for boundary box indexing. 
</p>

<p>
	                                                                            
</p>

<p>
	 --- OPTION 3: Arcs ---                                                     
</p>

<p>
	  - Target: Standalone open circular ARC elements.                          
</p>

<p>
	  - Sub-Prompts: Triggers only "Curve distance [Middle]".                  
</p>

<p>
	  - Workflow Logic: Uses true structural arc-length path calculations (not  
</p>

<p>
	    straight-line chord spacing). Entering "Middle" isolates the exact apex 
</p>

<p>
	    mid-curve station node. Excellent for curb returns or radius layout.    
</p>

<p>
	                                                                            
</p>

<p>
	 --- OPTION 4: Circles ---                                                  
</p>

<p>
	  - Target: Full, closed 360-degree CIRCLE elements.                        
</p>

<p>
	  - Sub-Prompts: 1. Circle Mode [Distance/Pieces]                           
</p>

<p>
	                 2. Curve Distance (if Distance Mode)                       
</p>

<p>
	                 3. Number of Slices (if Pieces Mode)                       
</p>

<p>
	  - Workflow Logic:                                                         
</p>

<p>
	    * Pieces Mode: Divides the 360° rim into perfectly equal pie sections.  
</p>

<p>
	      Ideal for setting layout coordinates for manholes or foundation piles. 
</p>

<p>
	    * Distance Mode: Steps linearly around the outer circumference.         
</p>

<p>
	                                                                            
</p>

<p>
	 --- OPTION 5: Splines ---                                                 
</p>

<p>
	  - Target: Non-uniform smooth organic SPLINE curve strings.                
</p>

<p>
	  - Sub-Prompts: Triggers "Curve distance" and "Line distance".             
</p>

<p>
	  - Workflow Logic: Utilizes Visual LISP curve projection vectors to step   
</p>

<p>
	    smoothly through changing multi-radius landscape or contour paths,      
</p>

<p>
	    automatically trapping and marking the true start/end index boundaries. 
</p>

<p>
	                                                                            
</p>

<p>
	 --- OPTION 6: FeatureLines ---                                            
</p>

<p>
	  - Target: Native Autodesk Civil 3D Feature Lines (AECC_FEATURE_LINE).     
</p>

<p>
	  - Sub-Prompts: Triggers "Curve distance" and "Line distance".             
</p>

<p>
	  - Workflow Logic: Tailored for civil infrastructure models. The engine    
</p>

<p>
	    interrogates the 3D string, locks all critical grade breaks and site    
</p>

<p>
	    vertices, and overlays intermediate interval layout points that retain  
</p>

<p>
	    design model accuracy.                                                  
</p>

<p>
	                                                                            
</p>

<p>
	 --- OPTION 7: All ---                                                      
</p>

<p>
	  - Target: Simultaneous mixed selection set of all supported geometries.  
</p>

<p>
	  - Sub-Prompts: Sequential configuration parameters for all curves/lines.  
</p>

<p>
	  - Workflow Logic: Scans the entire cross-window selection. For every object
</p>

<p>
	    trapped, it reads its DXF Group 0 type, dynamically assigns your preset 
</p>

<p>
	    rules, avoids duplicate coordinate overlaps, and populates the entire   
</p>

<p>
	    site plan layer in a single execution click.        
</p>

<p>
	 SHORT SEGMENT OVERRIDE LOGIC:                                              
</p>

<p>
	 If an entity length or sub-segment is shorter than the interval distance   
</p>

<p>
	 specified, the script halts and prompts: [Middle/All/SkipAll]              
</p>

<p>
	                                                                            
</p>

<p>
	  - "Middle": Drops a layout node exactly at the center of that specific    
</p>

<p>
	    short segment.                                                          
</p>

<p>
	  - "All": Converts the current short vector and all subsequent short vectors
</p>

<p>
	    discovered during the current command run into midpoints automatically. 
</p>

<p>
	  - "SkipAll": Ignores short segments entirely for the rest of the execution,
</p>

<p>
	    leaving them clean and checking only major length spans.   <br />
	 
</p>

<p>
	 <u>SHORT SEGMENT OVERRIDE LOGIC:</u>                                             
</p>

<p>
	 If an entity length or sub-segment is shorter than the interval distance  
</p>

<p>
	 specified, the script halts and prompts: [Middle/All/SkipAll]             
</p>

<p>
	                                                                           
</p>

<p>
	  - "Middle": Drops a layout node exactly at the center of that specific   
</p>

<p>
	    short segment.                                                         
</p>

<p>
	  - "All": Converts the current short vector and all subsequent short vectors
</p>

<p>
	    discovered during the current command run into midpoints automatically.
</p>

<p>
	  - "SkipAll": Ignores short segments entirely for the rest of the execution,
</p>

<p>
	    leaving them clean and checking only major length spans.               
</p>

<p>
	             
</p>

<p>
	                    
</p>
]]></description><guid isPermaLink="false">99149</guid><pubDate>Tue, 02 Jun 2026 06:37:26 +0000</pubDate></item><item><title>Explode nested blocks only</title><link>https://www.cadtutor.net/forum/topic/41164-explode-nested-blocks-only/</link><description><![CDATA[
<p>Hi all,</p>
<p> </p>
<p>Is there a way to explode nested blocks within a block without exploding the original block that is shown in my drawing?</p>
<p> </p>
<p>Any help would be greatly appreciated.</p>
]]></description><guid isPermaLink="false">41164</guid><pubDate>Tue, 04 Sep 2012 06:14:51 +0000</pubDate></item><item><title>Notepad++ run time exension</title><link>https://www.cadtutor.net/forum/topic/74904-notepad-run-time-exension/</link><description><![CDATA[<p>
	Hi I have been using the Notepad++ run lisp extension for ages and its stopped working after installing an upgrade, I tried going to the web site link
</p>

<p>
	<a href="https://sourceforge.net/projects/nppactivexplugin/" rel="external nofollow">https://sourceforge.net/projects/nppactivexplugin/</a>
</p>

<p>
	and have just gone around in circles trying to join so could send a message re problem, is anyone else having problems ? Do you have a sourceforge account and could send a message would be appreciated.
</p>

<p>
	 
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted"><span class="pln">; This routine runs the code in the active editor of NotePad++ from AutoCAD:
(defun C:n++ nil (C:RunFromNotePadPP)) ; Quick Run
(defun C:RunFromNotePadPP ( / scr *error* err np++ npeditor npSS npMS r )
  ; NOTE: Requires ActiveX plugin(by David Gausmann) installed on the NP++ 
  ; https://sourceforge.net/projects/nppactivexplugin/
 
  (defun *error* (m)
    (foreach x (reverse (list np++ npeditor npSS npMS))
      (vl-catch-all-apply (function vlax-release-object) (list x))
    )
    (gc) (gc)
    (and msg (or (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*") (princ (strcat "\nError: " msg)))) (princ)
  ); defun *error*
 
  (setq err
    (vl-catch-all-apply
      (function 
        (lambda nil ; THIS WORKS - IT GETS THE ACTIVE DOCUMENT CODE IN NOTEPAD !!!
          (setq np++ (vlax-get-or-create-object "NotepadPlusPlus.Application"))
          (setq npeditor (vlax-get np++ 'ActiveEditor))
          (vlax-invoke-method npeditor 'selectAll)
          (setq npSS (vlax-get npeditor 'selections))
          (setq npMS (vlax-get npSS 'mainSelection))
          (setq r (vlax-get-property npMS 'text))
          (vlax-invoke npSS 'setRange 0 0 0 0)
        ); lambda 
      ); function
    ); vl-catch-all-apply
  ); setq err 
 
  (*error* nil)(princ)
  (if (and r (not (vl-catch-all-error-p err)))
    (eval (read (strcat "(list\n" r "\n)")))
  )
); defun
</span></pre>

<p>
	 
</p>

<p>
	 
</p>
]]></description><guid isPermaLink="false">74904</guid><pubDate>Fri, 15 Apr 2022 01:59:58 +0000</pubDate></item><item><title>Unexpected behaviour handling multiline attribute when inserting block with Lisp</title><link>https://www.cadtutor.net/forum/topic/99147-unexpected-behaviour-handling-multiline-attribute-when-inserting-block-with-lisp/</link><description><![CDATA[<p>
	I'm writing a lisp routine to automation drawing revision in lisp. to replace a diesel version. I have come across a problem when inserting the block using lisp, in diesel it works perfectly. The block has four attributes, with the last being a multiline attribute. The routine stumbles at this point and misinterprets the pause for user input as \ and returns the error 'unknown command'.
</p>

<p>
	 
</p>

<p>
	The diesel code that works is below.
</p>

<p>
	 
</p>

<p>
	attdia;0;-I;REVNOTE;\;1;;P01;""$m=$(edtime,$(getvar,date),DD.MO.YYYY)"";SMS;First issue;;attdia;1;rea;
</p>

<p>
	 
</p>

<p>
	The same in lisp below
</p>

<p>
	 
</p>

<p>
	(command "attdia" "0")<br />
	(command "_Insert" "REVNOTE" pause 1 1 0 "P01" Date Initials pause)<br />
	(command "attdia" "1")<br />
	(command "REA")
</p>

<p>
	 
</p>

<p>
	Any ideas on why this is happening as i'm stumped, unless its a bug in AutoCAD. 
</p>

<p>
	 
</p>

<p>
	many thanks
</p>

<p>
	 
</p>

<p>
	 
</p>
<p>
<a class="ipsAttachLink" href="https://www.cadtutor.net/forum/applications/core/interface/file/attachment.php?id=70382&amp;key=19506d24a2307a064fdab00e5007a7c4" data-fileExt='dwg' data-fileid='70382' data-filekey='19506d24a2307a064fdab00e5007a7c4'>REVNOTE.dwg</a></p>]]></description><guid isPermaLink="false">99147</guid><pubDate>Mon, 01 Jun 2026 16:44:23 +0000</pubDate></item><item><title>Quick String Search</title><link>https://www.cadtutor.net/forum/topic/99135-quick-string-search/</link><description><![CDATA[<pre class="ipsCode">;;; QSS - Quick String Search Rlx June'26
;;; Just a basic string search engine, first meant for text based files like lsp &amp; txt files + dwg files (dbx)
;;; Some files are read as stream so maybe it also works for other file types ... bucketlist material.
;;; App can skip (error-catch) files its unable to open because they were saved with higher version.
;;; Sometimes files can be corrupt and AutoCad crashes and you would loose all search results fo far.
;;; Thats why I created shadow mode and recovery mode.
;;; Shadow mode writes a file (QSS-Shadow-List.txt) on your desktop in 'QuickStringSearch' folder where the name of each file is saved.
;;; Each line begins with &lt;num&gt; | status | filename. You can save this file as csv and split on pipesymbol |.
;;; Status can be 0 - corrupt , 1 - unable to open , 2 - no hit , 3 - hit (search string was found)
;;; I created this because I was searching little over one hundred thousand drawings and just before it was finished
;;; it crashed AutoCad because of a corrupt drawing. With shadow mode you can now see how far it came.
;;; To be able to get past this , I also created recovery mode.
;;; First all filenames are saved to file (QSS-Recovery-List.txt) , then this list is compared to the shadow list.
;;; With this info , app can tell which file caused the crash , sent it to my naughty list , and resume with the rest.
;;; Normal operation , no corrupt files is simple click and go. You can allways leave on Shadow mode.
;;; When however AutoCad crashed because of corrupt file , switch on recovery mode and app will be able to
;;; skip corrupt file and resume with the rest.
;;; 
;;; Last update		: 2026-05-18 - added eror catch for read excel values
;;;			: 2026-05-30 - added Shadow Mode, save results do desktop (QSS-Shadow-Mode.txt)
;;;			: 2026-06-01 - added Recovery Mode, resume search after crash &amp; find everything

(defun C:QSS
       ( /
        ;;; globals
        OldErr regkey regvar sysvar-names sysvar-old-values total-file-list hit-list open-at-the-end fn no-show
        
        ;;; debug / crash &amp; recovery
        QSS-Program-Folder
        QSS-Shadow-List-fn  QSS-Shadow-List-fp  shadow-list
        QSS-Recovery-List-fn QSS-Recovery-List-fp recovery-list
        QSS-Naughty-List-fn QSS-Naughty-List-fp naughty-list
        
        ;;; object dbx / RegExp
        actApp actDoc actDocs actLay dbxObj AllOpen RegExp
        
        ;;; Excel
        xlApp xlWorkbooks xlWorkbook xlSheets
        
        ;;; registry
        QSS-Search-Folder					;;; String - Folder where lisp files are placed
        QSS-Include-Subfolders					;;; Toggle - "0" scan only search folder, "1" also scan subfolders
        QSS-Filename-Extension-Filter				;;; String - delimited by , like "lsp,txt"
        QSS-Search-String-Filter				;;; String - delimited by | like "Rlx|Dragon"
        QSS-Get-Everything					;;; Toggle - Get every string form every drawwing
        QSS-Case-Sensitive					;;; Toggle - "0" don't care, "1" case sensitive search
        QSS-Whole-Words-Only					;;; Toggle - "0" find every part, "1" only find whole words
        QSS-Shadow-Mode						;;; Toggle - save all search hits directly to desktop
        QSS-Recovery-Mode					;;; Toggle - Resume after crash and put guilty file on naughty lisy

        ;;; dialog
        QSS-Main-Dialog-fn QSS-Main-Dialog-fp QSS-Main-Dialog-id
	MainDialog-tl MainDialog-rd
	
       )
  (QSS_init)
  (QSS_exit)
  (QSS_end_it)
)

;--- Init ------------------------------------------------- Begin Init Section --------------------------------------------------- Init ---

(defun QSS_Init ()
  ; initialize error handling
  (setq OldErr *error* *error* QSS_Err)
  ; backup &amp; set system variables (not realy used here, just added for template purposes)
  (setq sysvar-names (list (cons 'cmdecho 0))
        sysvar-old-values (mapcar '(lambda (x)(getvar (car x))) sysvar-names))
  (mapcar '(lambda (x)(setvar (car x) (cdr x))) sysvar-names)
  ;;; init registry variables
  (InitDefaultRegistrySettings)(ReadSettingsFromRegistry)
  ;;; for direct saving results to desktop
  (QSS_Init_Shadow_and_Recovery_Mode)
  ;;; lets go girls
  (QSS_Main_Dialog_Start)
)

(defun QSS_Err ($s) (princ $s)(QSS_Exit)(setq *error* OldErr)(princ))

;;; save search results also to desktop in case computer crashes during search
(defun QSS_Init_Shadow_and_Recovery_Mode ()
  (setq QSS-Program-Folder (mk_desktop_dir "QuickStringSearch"))
  (setq QSS-Shadow-List-fn (strcat QSS-Program-Folder "\\QSS-Shadow-List.txt"))
  (setq QSS-Recovery-List-fn (strcat QSS-Program-Folder "\\QSS-Recovery-List.txt"))
  (setq QSS-Naughty-List-fn  (strcat QSS-Program-Folder "\\QSS-Naughty-List.txt"))
  ;;; if recovery mode is activated preload recovery-list
  (QSS_Check_For_Recovery_Mode)
)

(defun QSS_Exit ()
  ; cleanup dialog(s) (I use list for future use in case of more dialogs)
  (mapcar '(lambda (x) (if (not (null x)) (unload_dialog x)))
	   (list QSS-Main-Dialog-fn))
  (mapcar '(lambda (x) (if (not (null x)) (close x)))
	   (list QSS-Main-Dialog-fp QSS-Shadow-List-fp shadow-fp-2 QSS-Recovery-List-fp QSS-Naughty-List-fp))
  (mapcar '(lambda (x) (if (and (not (null x)) (findfile x)) (vl-file-delete x)))
	   (list QSS-Main-Dialog-fn))
                 
  ; reset system variables (not realy used here just for future / template purposes)
  (mapcar '(lambda (x y)(setvar (car x) y)) sysvar-names sysvar-old-values)
  (term_dialog) (gc) (princ "\nDone") (terpri) (princ)
  ; release dbxObj &amp; RegExp
  (foreach obj (list dbxObj RegExp) (vl-catch-all-apply 'vlax-release-object (list obj)))
  ;;; release Excel
  (Exit_Excel)
)

;;; check for unfinished business...
(defun QSS_End_it ( / fn )
  ;;; in shadow mode , each search hit (filename) is saved to desktop (QSS-Shadow-List.txt)
  (if (and (null no-show) (= QSS-Shadow-Mode "1") (setq fn (findfile QSS-Shadow-List-fn))) (startapp "notepad" fn))
  ;;; user clicked on open drawing from result list, aint gonna happen until dialog was terminated first
  (if (and open-at-the-end (setq fn (findfile open-at-the-end)))(_ShellOpen fn))
)

;;; file and mode are verified in QSS_Init
(defun QSS_Check_For_Recovery_Mode ( / inp l) (if (and (= QSS-Recovery-Mode "1") (findfile QSS-Recovery-List-fn)
  (setq QSS-Recovery-List-fp (open QSS-Recovery-List-fn "r"))) (progn (while (setq inp (read-line QSS-Recovery-List-fp))
     (setq l (cons inp l)))(close QSS-Recovery-List-fp) (setq recovery-list (reverse l)))))

;;; ------------------------------------------------------ End of Init Section ------------------------------------------------------------



;;; --- Registry Settings ------------------------------- Begin Registry Settings ------------------------------- Registry Settings --- ;;;

(defun InitDefaultRegistrySettings ()
  (setq regkey "HKEY_CURRENT_USER\\SOFTWARE\\QSS\\")
  ;;; regkeys must be strings ("variable name" "default value")
  (setq regvar
     (list
       '("QSS-Search-Folder" "")				;;; String - Folder where lisp files are placed
       '("QSS-Include-Subfolders" "0")				;;; Toggle - "0" scan only search folder, "1" also scan subfolders
       '("QSS-Filename-Extension-Filter" "lsp,txt,dwg")		;;; String - delimited by , (comma) like "lsp,dwg"
       '("QSS-Search-String-Filter" "")				;;; String - delimited by | (Pipe) like "Rlx|Dragon"
       '("QSS-Get-Everything" "0")				;;; Toggle - Get every string form every drawwing
       '("QSS-Case-Sensitive" "0")				;;; Toggle - "0" don't care, "1" case sensitive search
       '("QSS-Whole-Words-Only" "0")				;;; Toggle - "0" nope , "1" jip 
       '("QSS-Shadow-Mode" "0")					;;; Toggle - if on save all results to desktop 
       '("QSS-Recovery-Mode" "0")				;;; Toggle - resume after crash (corrupt file or something)
    )
  )
  (mapcar '(lambda (x)(set (read (car x)) (cadr x))) regVar)
)

(defun ReadSettingsFromRegistry ()
  (mapcar '(lambda (x / n v)
    (if (setq v (vl-registry-read regkey (setq n (car x)))) (set (read n) v) (vl-registry-write regkey n (cadr x)))) regvar))

(defun WriteSettingsToRegistry ()
  (mapcar '(lambda (x) (vl-registry-write regkey (car x) (eval (read (car x))))) regvar))

;;; --- Registry Settings -------------------------------- End Registry Settings -------------------------------- Registry Settings --- ;;;



;;; --- dialog section ----------------------------------- begin dialog section ------------------------------------ dialog section --- ;;;

; SaveDialogData evaluates all vars from %tl and returns them as a list, reset does the opposite
(defun Save_Dialog_Data      (%tl) (mapcar '(lambda (x) (eval (car x))) %tl))
(defun Reset_Dialog_Data (%tl %rd) (mapcar '(lambda (x y) (set (car x) y)) %tl %rd))
(defun Set_Dialog_Tiles      (%tl) (mapcar '(lambda (x / v) (if (eq 'str (type (setq v (eval (car x))))) (set_tile (cadr x) v))) %tl))
(defun Main_Dialog_Cancel       () (Reset_Dialog_Data MainDialog-tl MainDialog-rd) (WriteSettingsToRegistry))

(defun QSS_Main_Dialog_Create ()
  (if (and (setq main-dialog-fn (vl-filename-mktemp "Main.dcl")) (setq main-dialog-fp (open main-dialog-fn "w")))
    (mapcar
      '(lambda (x)(write-line x main-dialog-fp))
       (list "QSS : dialog {label=\"QSS - Quick String Search (RLX June 2026)\";"
             ":boxed_column {label=\"Search Folder :\";"
             "  :row {:edit_box {key=\"eb_search_folder\";}"
             "        :button {fixed_width=true;width=12;key=\"bt_select_search_folder\";label=\"Select\";}}"
             "  :toggle {label=\"Include Subfolders\";key=\"tg_include_subfolders\";}}"

             ":boxed_column {label=\"Filename Extension Filter [ , ]\";"
             "  :row {:edit_box {key=\"eb_filename_extension_filter\";}"
             "        :button {fixed_width=true;width=12;key=\"bt_filename_extension_filter\";label=\"Select\";}}}"
	     
	     ":boxed_column {label=\"Search String Filter [ | ]\";"
             "  :concatenation {:edit_box {edit_width=80;key=\"eb_search_string_filter\";}"
             "                  :toggle {key=\"tg_everything\";label=\"Everything\";}}"
             "  :row {:toggle {label=\"Case Sensitive\";key=\"tg_case_sensitive\";}"
             "        :toggle {label=\"Whole Words Only\";key=\"tg_whole_words_only\";}"
             "        :toggle {label=\"Shadow Mode\";key=\"tg_shadow_mode\";}"
             "        :toggle {label=\"Recovery Mode\";key=\"tg_recovery_mode\";}}}"
             
             "spacer;:row {gap;:image {key=\"im_mode\";height=0.2;}gap;}spacer;"
             
             ":concatenation {gap; :image {height=1.5;width=91;key=\"the_bar\";color=dialog_background;}gap;}"
             
             ":column {:concatenation {alignment=centered;"
             "  :bt_16 {key=\"bt_clear_lists\";label=\"Clear Lists\";} spacer;spacer; ok_cancel;}}"
             "spacer;spacer;"
             
             "}"
             "gap:image {fixed_width=true;width=0.001;color=dialog_background;}"
             "bt_16 :button {width=18;fixed_width=true;}"
       )
    )
  )
  (if main-dialog-fp (close main-dialog-fp))(gc)
)

(defun QSS_Main_Dialog_Start ( / drv )
  (if (null main-dialog-fn)(QSS_Main_Dialog_Create))
  (if (and (setq main-dialog-dcl (load_dialog main-dialog-fn)) (new_dialog "QSS" main-dialog-dcl))
    (progn
      (QSS_Main_Dialog_Update)
      (QSS_Main_Dialog_Action)
      (setq drv (start_dialog))
      
      (cond
	((= drv  0)(Main_Dialog_Cancel)(setq no-show T)); no-show to prevent showing shawdow-list after cancel
        ;;; disabled accept (ok / done dialog 1) to be able to show progress bar
        ;;; ok action replaced by : ("accept" "(WriteSettingsToRegistry)(QSS_Pre_Scan)")
	((= drv  1)(WriteSettingsToRegistry))
        ((= drv  2)(WriteSettingsToRegistry)(Show_Hit_List))
      )
    )
  )
  (if main-dialog-fn (vl-file-delete main-dialog-fn))
  (setq main-dialog-fn nil)
)

(defun QSS_Main_Dialog_Update ()
  (setq MainDialog-tl
	 '((QSS-Search-Folder "eb_search_folder")
           (QSS-Include-Subfolders "tg_include_subfolders")
           (QSS-Filename-Extension-Filter "eb_filename_extension_filter")
           (QSS-Search-String-Filter "eb_search_string_filter")
           (QSS-Get-Everything  "tg_everything")
           (QSS-Case-Sensitive "tg_case_sensitive")
           (QSS-Whole-Words-Only "tg_whole_words_only")
           (QSS-Shadow-Mode "tg_shadow_mode")
           (QSS-Recovery-Mode "tg_recovery_mode")
          )
  )
  ;;; rd = reset data (val1 val2 ...) , in case of a cancel store original values before start of dialog
  (if (null MainDialog-rd) (setq MainDialog-rd (Save_Dialog_Data MainDialog-tl)))
  ;;; set edit boxes and toggle values
  (Set_Dialog_Tiles MainDialog-tl)
  ;;; show mode in color
  (show_program_mode)
)

(defun QSS_Main_Dialog_Action ()
  (mapcar '(lambda (x)(action_tile (car x) (cadr x)))
    '(("cancel" "(done_dialog 0)")
      ;;; stay in dialog for progress bar
      ;;; ("accept" "(done_dialog 1)")
      ("accept" "(WriteSettingsToRegistry)(if (eq QSS-Get-Everything \"1\")(QSS_Get_Everything)(QSS_Pre_Scan))")
      
      ("eb_search_folder" "(setq QSS-Search-Folder $value)")
      ("bt_select_search_folder" "(QSS_select_search_folder)")
      ("tg_include_subfolders" "(setq QSS-Include-Subfolders $value)")
      ("eb_filename_extension_filter" "(setq QSS-Filename-Extension-Filter $value)")
      ("bt_filename_extension_filter" "(QSS_Select_Filename_Extension_Filter)")
      ("eb_search_string_filter" "(setq QSS-Search-String-Filter $value)")
      ("tg_everything" "(setq QSS-Get-Everything $value)")
      ("tg_case_sensitive" "(setq QSS-Case-Sensitive $value)")
      ("tg_whole_words_only" "(setq QSS-Whole-Words-Only $value)")
      ("tg_shadow_mode" "(setq QSS-Shadow-Mode $value)(show_program_mode)")
      ("tg_recovery_mode" "(setq QSS-Recovery-Mode $value)(show_program_mode)")
      ("bt_clear_lists" "(QSS_Clear_Lists)")
    )
  )
)

(defun show_program_mode ( / col )
  (setq col (cond ((= QSS-Recovery-Mode "1") 1) ((= QSS-Shadow-Mode  "1") 3)(t 7)))
  (start_image "im_mode") (fill_image 0 0 (dimx_tile "im_mode") (dimy_tile "im_mode") col)(end_image)
)

(defun QSS_select_search_folder ( / f)
  (if (setq f (GetShellFolder "Select search folder"))(set_tile "eb_search_folder" (setq QSS-Search-Folder f))))

(defun QSS_Clear_Lists ( / l)
  (if (and (folder-p QSS-Program-Folder) (vl-consp (setq l (vl-directory-files QSS-Program-Folder "*.*" 1)))
    (yesno "Realy want to clear all lists in QuickStringSearch folder?"))
      (foreach f l (vl-file-delete (strcat QSS-Program-Folder "\\" f)))))

;;; QSS-Filename-Extension-Filter / eb_filename_extension_filter
(defun QSS_Select_Filename_Extension_Filter ( / tl dl rtn)
  ;;; total list with (future) supported extensions (doc &amp; pdf untested / too slow at this moment)
  ;;; (setq tl '("doc" "docx" "dwg" "dxf" "lsp" "pdf" "txt" "xls" "xlsx"))
  (setq tl '("dwg" "dxf" "lsp" "txt" "xls" "xlsx"))
  ;;; get current list from edit box and use as default for multiple select routine
  ;;; also make sure all extentions are in lowercase
  (setq dl (SplitStr (strcase (get_tile "eb_filename_extension_filter") t) ","))
  (if (setq rtn (mfl tl dl))
    (progn
      (set_tile "eb_filename_extension_filter" (setq QSS-Filename-Extension-Filter (strcase (commatize rtn) t)))
      (WriteSettingsToRegistry)
    )
  )
)

;;; first handle the file &amp; folder stuf side of things
(defun QSS_Pre_Scan ( / subfolder-flag case-flag filename-extension-filter-list search-string-filter-list folder-list tmp-l)
  ;;; make sure include subfolders and case-sensitive flags are either T or nil
  (if (not (eq QSS-Include-Subfolders "1")) (setq subfolder-flag nil) (setq subfolder-flag T))
  (if (not (eq QSS-Case-Sensitive "1")) (setq case-flag nil) (setq case-flag T))
  ;;; check all parameters
  (cond
    ;;; verify search folder
    ((not (folder-p QSS-Search-Folder))
     (alert (strcat "Invalid search folder : " (vl-princ-to-string QSS-Search-Folder))))
    ;;; verify filename filter (like "lsp,dwg") -&gt; pimpext -&gt; ("*.lsp" "*.dwg")
    ((or (void QSS-Filename-Extension-Filter)
         (not (vl-consp (setq tmp-l (SplitStr QSS-Filename-Extension-Filter ","))))
         (not (vl-every '(lambda (s) (wcmatch s "*`.*")) (setq filename-extension-filter-list (pimpex tmp-l)))))
     (alert (strcat "Bad filename filter : " (vl-princ-to-string QSS-Filename-Extension-Filter))))
    ;;; verify search string filter
    ((or (void QSS-Search-String-Filter)
         (not (vl-consp (setq search-string-filter-list (SplitStr QSS-Search-String-Filter "|")))))
     (alert (strcat "Invalid search string : " (vl-princ-to-string QSS-Search-String-Filter))))
    ;;; maybe do file list check here
    (t
     ;;; fire-up proress bar
     (clear_bar)(set_tile "the_bar" " working...")
     
     ;;; if recovery mode is active no need to scan again for subfolders and files
     (if (and (= QSS-Recovery-Mode "1") (vl-consp recovery-list))
       (setq total-file-list recovery-list)
       ;;; at this moment either recovery mode is not activated or (pre-loaded) recovery-list is empty
       ;;; so we have to perform a full (sub)folder / file scan
       (progn
         (if (eq QSS-Include-Subfolders "1")
         (setq folder-list (QSS_FindSubfolders QSS-Search-Folder)) (setq folder-list (list QSS-Search-Folder)))
         ;;; just a little delay to enjoy the view, exterminate when it gets anoying
         (wait 1.5)
         (setq total-file-list (QSS_FindFiles folder-list filename-extension-filter-list)) ;;; [QSS_FindFiles line 747]
         ;;; recovery mode may be active but recovery-list is empty
         (if (and (= QSS-Recovery-Mode "1") (not (vl-consp recovery-list)))
           (QSS_Save_Recovery_List (setq recovery-list total-file-list)))
       )
     )
    )
  );;; end cond

  ;;; determine whether to process recovery or total-file-list
  (if (and (= QSS-Recovery-Mode "1") (vl-consp recovery-list) (findfile QSS-Shadow-List-fn)) (QSS_Start_Recovery))
  ;;; ready to proceed with total-file list
  (clear_bar)
  (if (not (vl-consp total-file-list))
    (alert "No (more) files to process")
    (QSS_Process_Total_File_List)
  )
);;; end defun

     
;;; little explanation : Recovery list contains all filenames from original search operation (in my case 105.000)
;;; With shadow mode enabled every result is saved to a file (QSS-Shadow-Mode-fn)
;;; If AutoCad crashed because of a corrupt file , count the number of lines in shadow file, say 5000.
;;; This means that file 5001 in the Recovery list gets a seat on my naughty list and app should resume from 5002.
;;; In order to keep lists in sync file 5001 has to be added to shadow list and tagged as corrupt / unable to read
;;; (setq l1 '(0 1 2 3 4 5) l2 '(0 1 2)) -&gt; 3 = err -&gt; resume search from 4 
(defun QSS_Start_Recovery ( / fn shadow-count )
  (cond
    ((not (vl-consp recovery-list)) (alert "Recovery unavailable : recovery-list empty"))
    ((not (and (setq fn (findfile (vl-princ-to-string QSS-Shadow-List-fn)))
       (setq QSS-Shadow-List-fp (open fn "r")))) (alert "Recovery unavailable : recovery-list empty"))
    (t
     (setq shadow-count 0)
     (while (setq inp (read-line QSS-Shadow-List-fp))(setq shadow-count (1+ shadow-count)))(close QSS-Shadow-List-fp)
     ;;; (sublst (reverse '(10 9 8 7 6 5 4 3 2 1)) (1+ (length '(1 2 3))) nil) -&gt; (4 5 6 7 8 9 10)
     (setq total-file-list (sublst (reverse recovery-list) (1+ shadow-count) nil))
     ;;; first item in total list is the naughty one so bag &amp; tag
     (QSS_Save_To_Naughty_List (car total-file-list))
     ;;; put item also on hit-list with remark that app was unable to open it
     (QSS_Save_To_Shadow_List (strcat "0|error|" (vl-princ-to-string (car total-file-list))))
     ;;; now process rest of total-list
     (setq total-file-list (cdr total-file-list))
    )
  )
)

;;; clear previous status
(defun clear_bar () (start_image "the_bar")(fill_image 0 0 (dimx_tile "the_bar") (dimy_tile "the_bar") 141)(end_image))

(defun Show_Hit_List () (if (vl-consp hit-list)
  (dplm+ hit-list (strcat "Number of files found : " (itoa (length hit-list)))) (alert "Sorry search returned no results")))

(defun QSS_Process_Total_File_List ( / stream pattern file-count n l hit shadow-fn-1 shadow-fp-1 shadow-fn-2 shadow-fp-2)
  (set_tile "the_bar" (strcat "Number of files to search : " (setq n (itoa (length total-file-list)))))
  (setq file-count 0 pattern QSS-Search-String-Filter)
  (if (eq QSS-Case-Sensitive "1")(setq ignoreCase nil)(setq ignoreCase T))
  
  ;;; save all results to file on desktop for later valuation
  ;;; the reason I wrote this was I had to scan 104.987 files and around no. 86.000 AutoCad crashed and all results poof
  ;;; after I created Shadow Mode it happened again so now I first save every filename to a dat file and
  ;;; in the loop I do the same with prefix [Y], (string was found) or [N], (string was not found)
  ;;; Now if AutoCad crashes again at least I can see which file I have to kick of this planet
  (if (and (= QSS-Shadow-Mode "1") (not (= QSS-Recovery-Mode "1")))
    (progn
      ;;; clear old shadow file first because inside next loop this shadow file is appended (\\Desktop\\QSS-Shadow-Mode.txt)
      (if (setq shadow-fn-1 (findfile QSS-Shadow-List-fn))(vl-file-delete shadow-fn-1))
      ;;; write all filenames to dat file
      (if (and (setq shadow-fn-2 (strcat (getenv "USERPROFILE") "\\Desktop\\QSS-Shadow-Mode.dat"))
               (vl-consp total-file-list)(setq shadow-fp-2 (open shadow-fn-2 "w")))
        (progn (foreach x total-file-list (write-line x shadow-fp-2))(close shadow-fp-2)(gc)(gc)))
    )
  )
               
  ;;; now do the actual scanning
  (foreach fn total-file-list
    (setq hit nil)
    ;;; split here for different types of extensions
    ;;; lisp &amp; text files can be read by stream , dwg by odbx
    ;;; (strcase (last (fnsplitl "c:\\temp\lisp\acad.dwg")) t) -&gt; ".dwg"
    (if (setq ext (vl-filename-extension fn)) (setq ext (strcase ext t)) (setq ext ""))
    
    ;(setq ext (strcase (last (fnsplitl fn)) t))

    ;;; for now only *.lsp, *.txt &amp; *.dwg,
    ;;; bucketlist xls/xlsx &amp; pdf but they may need different approach or 3rd party software, so low priority
    (cond
      ;;; on this moment untested / too slow
      ((wcmatch ext "*`.doc,*`.docx,*`.rtf")
       (if (SearchInWord fn pattern) (setq hit fn hit-list (cons hit hit-list))))
      ;;; on this moment untested / too slow
      ((wcmatch ext "*`.pdf")
       (if (SearchInPDF fn pattern) (setq hit fn hit-list (cons hit hit-list))))
      ((wcmatch ext "*`.lsp,*`.txt")
       (if (and (setq stream (_ReadStream fn 0))
                (setq rtn (= (vlax-invoke (InitRegExp pattern ignoreCase nil) 'Test stream) -1))
                (not (member fn hit-list))) (setq hit fn hit-list (cons hit hit-list))))
      ;;; regex_string_search last parameter is for return as list
      ;;; if T -&gt; return all strings in doc as list, if nil -&gt; return nil or filename if pattern is found
      ((wcmatch ext "*`.dwg")
       (setq dbx-doc (vl-catch-all-apply 'odbx_open (list fn)))
       (if (or (= dbx-doc nil) (vl-catch-all-error-p dbx-doc))
         ;;; one reasonthis can happen is when trying to open drawing with higher AutoCad version
         (setq hit nil fn (strcat "1|unable to open|" fn))
         (if (setq hit (regex_string_search dbx-doc pattern nil)) (setq hit fn hit-list (cons hit hit-list))))
       ;(odbx_close dbx-doc)
      )
      
      ;;; excel : Scan_Excel returns T or nil if regex pattern is found
      ((wcmatch ext "*`.xls,*`.xlsx")
       (if (and (Scan_Excel fn) (not (member fn hit-list))) (setq hit fn hit-list (cons hit hit-list))))
    )
    ;;; Shadow Mode (save search hits directly to file on desktop
    ;(if (and hit (= QSS-Shadow-Mode "1")) (QSS-Execute-Shadow-Protocol hit))
    (if (= QSS-Shadow-Mode "1")
      (if hit
        (QSS_Save_To_Shadow_List (strcat "3|found|" hit))
        (QSS_Save_To_Shadow_List (strcat "2|none|" fn))
      )
    )
    ;;; length of hit-list
    (setq l (itoa (length hit-list)))
    ;;; clear previous status
    (clear_bar)
    ;;; update status message
    (set_tile "the_bar" (strcat "   ( " (setq *spin* (Spinbar *spin*)) " ) Scanning files [" (itoa file-count) " of " n "] - found " l))
    ;;; increase file counter
    (setq file-count (1+ file-count))
  )
  (done_dialog 2)
)


(defun QSS_Save_To_Shadow_List (s)
  (if (setq QSS-Shadow-List-fp (open QSS-Shadow-List-fn "a"))
    (progn (write-line s QSS-Shadow-List-fp)(close QSS-Shadow-List-fp)(gc))
    (princ (strcat "Unable to save to Shadow-List : " (vl-princ-to-string s)))
  )
)

(defun QSS_Save_To_Naughty_List (s)
  (if (setq QSS-Naughty-List-fp (open QSS-Naughty-List-fn "a"))
    (progn (write-line s QSS-Naughty-List-fp)(close QSS-Naughty-List-fp)(gc))
    (princ (strcat "Unable to save to Naughty-List : " (vl-princ-to-string s)))
  )
)

(defun QSS_Save_Recovery_List (lst)
  (if (setq QSS-Recovery-List-fp (open QSS-Recovery-List-fn "w"))
    (progn (foreach x lst (write-line x QSS-Recovery-List-fp)) (close QSS-Recovery-List-fp) (gc))
    (alert "Unable to save recovery list")
  )
)

;;; --- dialog section ------------------------------------ end dialog section ------------------------------------- dialog section --- ;;;



;--- + + + --------------------------------------------- Begin of tiny lisp section --------------------------------------------- + + + ---

(defun void (x) (or (not x) (= "" x) (and (eq 'STR (type x)) (not (vl-remove 32 (vl-string-&gt;list x))))))

(defun wait (sec / stop)(setq stop (+ (getvar "DATE") (/ sec 86400.0)))(while (&gt; stop (getvar "DATE"))))

(defun string-p (s) (if (= (type s) 'str) t nil))

(defun folder-p (f) (if (and (= (type f) 'str) (vl-file-directory-p f)) t nil))

;;; (mk_desktop_dir "QuickStringSearch")
(defun mk_desktop_dir ( $d / d ) (setq $d (vl-princ-to-string $d))
  (setq d (strcat (getenv "USERPROFILE") "\\Desktop\\" $d)) (if (vl-file-directory-p d) d (progn (vl-mkdir d) d)))

; test : (commatize '("a" "b" "c"))
(defun commatize (l) (apply 'strcat (cdr (apply 'append (mapcar (function (lambda (x) (list "," x))) l)))))

; make sure itoa has fixed length , i.e. (fixitoa 1 3) -&gt; "001"
(defun fixitoa ( #i #n / s ) (setq s (itoa #i))(while (&gt; #n (strlen s))(setq s (strcat "0" s))) s)

;;; (sublst '(1 2 3 4 5 6 7 8 9 10) 5 2) -&gt; (5 6) / (sublst '(1 2 3 4 5 6 7 8 9 10) 8 8) -&gt; (8 9 10)
;;; (sublst '(1 2 3 4 5 6 7 8 9 10) 3 nil) -&gt; (3 4 5 6 7 8 9 10)
(defun sublst (lst i l / r) (if (not (&lt;= 1 l (- (length l) i)))
  (setq l (- (length lst) (1- i))))(repeat l (setq r (cons (nth (1- i) lst) r) i (1+ i))) (reverse r))


;;; (Dos_Path (strcat (getvar "dwgprefix") (getvar "dwgname"))) -&gt; "C:\\USERS\\ROB\\DOCUMENTS\\ACAD\\QUICKSTRINGSEARCH.DWG\\"
(defun Dos_Path ($p)
  (if (= (type $p) 'STR) (strcase (strcat (vl-string-right-trim "\\" (vl-string-translate "/" "\\" $p)) "\\")) ""))

;;; (vl_path (strcat (getvar "dwgprefix") (getvar "dwgname"))) -&gt; "c:/users/rob/documents/acad/quickstringsearch.dwg/"
(defun vl_path ($p)(if (= (type $p) 'str)
   (strcat (vl-string-right-trim "\\/" (strcase (vl-string-translate "\\" "/" $p) t)) "/") ""))

(defun IsFileReadable (fn / fp inp) (if (setq fileHandle (open fn "r")) (progn (setq inp (read-line fp))
  ;|like AC1032|; (close fp) (and inp (= (substr inp 1 2) "AC")) ;|T if valid header|; ) nil ;|corrupt or locked|; ))

; generic getfolder routine with possibility to create a new subfolder (GetShellFolder "select path")
(defun GetShellFolder ( m / f s) (if (and (setq s (vlax-create-object "Shell.Application"))
  (setq f (vlax-invoke s 'browseforfolder 0 m 0 "")))(setq f (vlax-get-property (vlax-get-property f 'self) 'path))
     (setq f nil))(vl-catch-all-apply 'vlax-release-object (list s))
  (if f (strcat (vl-string-right-trim "\\" (vl-string-translate "/" "\\" f)) "\\")))

; returns T if no errors occurred during program execution
(defun _ShellOpen ( $f / it sh )
  (if (and (not (void $f)) (setq $f (findfile $f)) (setq sh (vla-getInterfaceObject (vlax-get-acad-object) "Shell.Application")))
    (progn (setq it (vl-catch-all-apply 'vlax-invoke (list sh 'open $f)))(vlax-release-object sh)(not (vl-catch-all-error-p it)))
      (progn (prompt "\nShell application was unable to open file")(setq it nil))))

;;; d = directory , e = extension like "*.dwg" , f = flag include subfolders (any value or nil)
;;; test : (length (alf "d:/temp/lisp" "*.dwg" t))  (length (alf "d:/temp/lisp" "*.dwg" nil))
;;; (setq l (alf "c:/temp/lisp" "*.xlsx" t)) (setq l (alf "c:\\temp\\lisp\\" "*.txt" t))
(defun alf (d e f) (setq d (vl-string-right-trim "/" (vl-string-translate "\\" "/" d)))
  (if f (apply 'append (cons (if (vl-directory-files d e)(mapcar '(lambda (x) (strcat d "/" x)) (vl-directory-files d e)))
    (mapcar '(lambda (x) (alf (strcat d "/" x) e f))(vl-remove ".." (vl-remove "." (vl-directory-files d nil -1))))))
      (mapcar '(lambda (x) (strcat d "/" x))(vl-directory-files d e 1))))

;;; (SplitStr "a,b,c" ",") -&gt; ("a" "b" "c")
(defun SplitStr (s d / p)
  (if (setq p (vl-string-search d s))(cons (substr s 1 p)(SplitStr (substr s (+ p 1 (strlen d))) d))(list s)))

;;; (lst-&gt;csv '("a" "b" "c") "|") -&gt; "a|b|c"
(defun lst-&gt;csv (%l $s)
  (apply 'strcat (cdr (apply 'append (mapcar (function (lambda (x) (list $s x))) %l)))))

;;; (sandwich '("a" "b" "c") "*") -&gt; '("*a*" "*b*" "*c*")
;;; for whole word search each string in regex string has to begin and end with \\b
(defun sandwich (%l %c) (mapcar '(lambda (s)(strcat %c s %c)) %l))

;;; make sure each extension begin with *. (pimpex (splitstr "lsp,dwg" ",")) -&gt; ("*.lsp" "*.dwg")
(defun pimpex (%l) (mapcar '(lambda (s)(strcat "*." (vl-string-trim "*." s))) %l))

;;; (yesno "Are you a dragon?")
(defun yesno ( m / n p i r ) (and (= (type m) 'STR) (setq n (vl-filename-mktemp "yesno.dcl")) (setq p (open n "w"))
  (princ (strcat"yesno :dialog{label=\"" m "?\";ok_cancel;}") p)(progn (close p)(gc) t) (setq i (load_dialog n))
    (new_dialog "yesno" i) (progn(action_tile "accept" "(done_dialog 1)")(action_tile "cancel" "(done_dialog 0)")
           (setq r (start_dialog))(unload_dialog i)(vl-file-delete n) t)(if (= r 1) t nil)))

; choose from list (cfl '("1" "2" "3"))
(defun cfl (l / f p d r) (and (setq p (open (setq f (vl-filename-mktemp ".dcl")) "w"))
 (princ "cfl:dialog{label=\"Choose\";:list_box{key=\"lb\";width=40;}ok_cancel;}" p)
  (not (setq p (close p)))(&lt; 0 (setq d (load_dialog f)))(new_dialog "cfl" d)
   (progn (start_list "lb")(mapcar 'add_list l)(end_list)(action_tile "lb" "(setq r (nth (atoi $value) l))(done_dialog 1)")
    (action_tile "accept" "(setq r (get_tile \"lb\"))(done_dialog 1)")(action_tile "cancel" "(setq r nil)(done_dialog 0)")
     (start_dialog)(unload_dialog d)(vl-file-delete f))) (cond ((= r "") nil)(r r)(t nil)))

;;; multiple from list (setq inp (mfl '("bak" "dwg" "pdf" "tif") '("dwg")))
(defun mfl (%l %df / toggle set_all l f p d r)
  (setq l (mapcar '(lambda (x)(if (member x %df)(strcat "[X] " x)(strcat "[O] " x))) %l))
  (defun toggle (v / s r)(if (eq (substr (setq r (nth (atoi v) l)) 2 1) "X")(setq s "[O] ")(setq s "[X] "))
    (setq l (subst (strcat s (substr r 5)) r l))(start_list "lb")(mapcar 'add_list l)(end_list))
  (defun set_all (i)(setq l (mapcar '(lambda (x)(if (eq i "1") (strcat "[X] " x) (strcat "[O] " x))) %l))
    (start_list "lb")(mapcar 'add_list l)(end_list))
  (and (setq p (open (setq f (vl-filename-mktemp ".dcl")) "w"))
       (princ (strcat "cfl:dialog{label=\"Choose\";:list_box {height=12;key=\"lb\";}"
         ":button{label=\"All\";key=\"bt_all\";}:button{label=\"None\";key=\"bt_none\";}ok_cancel;}") p)
       (not (setq p (close p)))(&lt; 0 (setq d (load_dialog f)))(new_dialog "cfl" d)
       (progn (start_list "lb")(mapcar 'add_list l)(end_list) (action_tile "lb" "(toggle $value)")
         (action_tile "accept" "(setq r (get_tile \"lb\"))(done_dialog 1)")
         (action_tile "cancel" "(setq r nil)(done_dialog 0)")
         (action_tile "bt_all" "(set_all \"1\")")(action_tile "bt_none" "(set_all \"0\")")
         (start_dialog)(unload_dialog d)(vl-file-delete f)))
  (if r (mapcar '(lambda (y)(substr y 5)) (vl-remove-if '(lambda (x)(eq (substr x 2 1) "O")) l)))
)

;;; display list (plus message)
(defun dplm (l m / f p d w) (and (vl-consp l) (setq l (mapcar 'vl-princ-to-string l)) (setq w (+ 5 (apply 'max (mapcar 'strlen l))))
  (setq p (open (setq f (vl-filename-mktemp ".dcl")) "w")) (princ (strcat "cfl:dialog{label=\"" m "\";:list_box {key=\"lb\";"
   "width="(itoa w)";}ok_only;}") p)(not (setq p (close p)))(&lt; 0 (setq d (load_dialog f)))(new_dialog "cfl" d)(progn (start_list "lb")
     (mapcar 'add_list l)(end_list)(action_tile "accept" "(done_dialog)")(start_dialog)(unload_dialog d)(vl-file-delete f))))

;;; possibility to load / save the list and ShellOpen selection
(defun dplm+ (l m / load_list save_list open_item f p d w pick)
  ;;; results are saved in user\desktop\quickstringsearch\QSS-Shadow-List.txt (QSS-Shadow-List-fn)
  ;;; each line begins with 0|error| , 1|unable to open| , 2|no hit| or 3|hit|
  (defun load_list ( / result-list)
    (if (and (findfile QSS-Shadow-List-fn)(setq QSS-Shadow-List-fp (open QSS-Shadow-List-fn "r")))
      (progn
        (while (setq inp (read-line QSS-Shadow-List-fp))
          (if (= (car (setq inp (SplitStr inp "|"))) "3") (setq result-list (cons (last inp) result-list))))
        (if (vl-consp result-list)(setq l (reverse result-list)) (setq l '("No results")))
        (start_list "lb")(mapcar 'add_list l)(end_list)
      )
      (alert "Unable to load list")
    )
  )
  
  ;;; very basic file save routine
  (defun save_list ( / f p)
    (if (and (vl-consp l) (setq f (vl-filename-mktemp "QuickStringSearch.txt")) (setq p (open f "w")))
      (progn (mapcar '(lambda (x)(write-line x p)) l) (close p) (gc) (startapp "notepad" f))))
  
  (defun open_item ( / i f)(if (and (vl-consp l)(not (null pick))(setq i (atoi pick))(setq f (nth i l))(setq f (findfile f)))
    (cond ((wcmatch (strcase (last (fnsplitl f)) t) "*.dwg")(setq open-at-the-end f)(done_dialog))(t (_ShellOpen f)))))

  (defun list_box_action ($r $v) (cond ((= $r 1) (setq pick $v)) ((= $r 4) ;|double click|; (setq pick $v)(open_item))))

  (if (not (vl-consp l)) (setq l (list "No results")) (setq l (mapcar 'vl-princ-to-string l)))
  ;;; make width dialog based on longest string in list
  (setq w (+ 5 (apply 'max (mapcar 'strlen l))))
  (setq p (open (setq f (vl-filename-mktemp ".dcl")) "w"))
  (write-line (strcat "cfl:dialog{label=\"" m "\";") p)
  (write-line (strcat ":list_box {key=\"lb\";width=" (itoa w) ";height=25;}") p)
  (write-line (strcat ":column {:row {fixed_width=true;alignment=centered; :button {key=\"bt_load\";label=\"Load\";}"
                          ":button {key=\"bt_save\";label=\"Save\";} :button {key=\"bt_open\";label=\"Open\";}}}") p)
  (write-line "ok_only;}" p)
  
  (if p (close p))
  (if (and (&lt; 0 (setq d (load_dialog f))) (new_dialog "cfl" d))
    (progn
      (start_list "lb")(mapcar 'add_list l)(end_list)
      (action_tile "accept" "(done_dialog)") (action_tile "lb" "(list_box_action $reason $value)")
      (action_tile "bt_load" "(load_list)") (action_tile "bt_save" "(save_list)")  (action_tile "bt_open" "(open_item)")
      (start_dialog) (unload_dialog d) (vl-file-delete f)
    )
  )
)



;--- + + + ---------------------------------------------- End of tiny lisp section ---------------------------------------------- + + + ---


;;; --- Odbx ---------------------------------------------- Begin Odbx Section ----------------------------------------------- Odbx --- ;;;

(defun GetAllOpenDocs ()
  (or actApp (setq actApp (vlax-get-acad-object))) (or actDoc (setq actDoc (vla-get-ActiveDocument actApp)))
    (or actDocs (setq actDocs (vla-get-documents actApp)))
  (vlax-for doc actDocs (if (= 1 (vlax-variant-value (vla-getvariable doc "DWGTITLED"))); no nameless drawings
    (setq AllOpen (cons (cons (strcase (vla-get-fullname doc)) doc) AllOpen))))
)
       
(defun _ReleaseAll ()
  (mapcar '(lambda(x) (if (and (= 'vla-object (type x)) (not (vlax-object-released-p x)))
    (vlax-release-object x))(set (quote x) nil)) (list actLay actDoc actDocs actApp dbxObj))(gc))

(defun _ReleaseAll ()
  (mapcar '(lambda(x) (if (and (= 'vla-object (type x)) (not (vlax-object-released-p x)))
    (vlax-release-object x))(set x nil)) (list 'doc 'actLay 'actDoc 'actDocs 'actApp 'dbxObj))(gc))

(defun _InitObjectDBX ()(or actApp (setq actApp (vlax-get-acad-object)))
  (or actDoc (setq actDoc (vla-get-ActiveDocument actApp)))(or AllOpen (setq AllOpen (GetAllOpenDocs)))
  (setq dbxObj (vl-catch-all-apply 'vla-getinterfaceobject (list actApp (dbx_ver))))
  (if (or (null dbxObj)(vl-catch-all-error-p dbxObj))(progn (princ "\nObjectDbx not available")(setq dbxObj nil)))
  dbxObj
)


(defun odbx_open ( $dwg / _pimp doc) (or AllOpen (GetAllOpenDocs))
  (or dbxObj (_InitObjectDBX))
  (defun _pimp (s) (strcase (vl-string-trim " ;\\" (vl-string-translate "/" "\\" s))))
  (cond ((or (void $dwg) (not (findfile $dwg)))(princ "\nInvalid drawing")(setq doc nil))
	((not (or dbxObj (_InitObjectDBX)))(princ "\nObjectDbx not available")(setq doc nil))
        ((setq doc (cdr (assoc (_pimp $dwg) AllOpen))))
	((vl-catch-all-error-p (vl-catch-all-apply 'vla-Open (list dbxObj (findfile $dwg))))
	 (princ "\nUnable to open drawing.")(setq doc nil))
	(t (setq doc dbxObj)))
  doc
)

(defun odbx_close ( %doc ) (if (and (= 'vla-object (type %doc))
  (not (vlax-object-released-p %doc)))(progn (vlax-release-object %doc))(setq %doc nil)))

(defun dbx_ver ( / v)
  (strcat "objectdbx.axdbdocument" (if (&lt; (setq v (atoi (getvar 'acadver))) 16) "" (strcat "." (itoa v)))))

;;; function to find all strings (txt/att etc) in all drawings in a folder
;;; QSS-Search-Folder	QSS-Include-Subfolders	QSS-Filename-Extension-Filter	QSS-Search-String-Filter
;;; QSS-Get-Everything	QSS-Case-Sensitive	QSS-Whole-Words-Only

;;; alf : d = directory , e = extension like "*.dwg" , f = flag include subfolders (any value or nil)
;;; test : (length (alf "d:/temp/lisp" "*.dwg" t)) 
(defun QSS_Get_Everything ( / actDoc actDocs actApp dbxObj RegExp dbx-doc write_result show_result 
                              search-folder dwg-list rtn result-list search-pattern result-list-fn
                              folder-list file-count l
                           )
  
  ;;; init vl functions, odbx &amp; regexp
  (vl-load-com) (_InitObjectDBX) (or RegExp (setq RegExp (vlax-create-object "VBScript.RegExp")))
  
  (defun write_result (lst fn / fp)
    (cond
      ((not (vl-consp lst))
       (alert "Computer says no : empty result list, nothing to write"))
      ((or (not (= (type fn) 'STR)) (not (setq fp (open fn "w"))))
       (alert (strcat "unable to write to : " (vl-princ-to-string fn))))
      ;;; format lst : ( ("dwgname1" . ("str1" "str2" ...)) ...)
      (t
       (write-line (strcat "Scanned " (itoa (length lst)) " drawings\n") fp)
       (foreach item lst
         (write-line (car item) fp)
         (foreach str (cdr item) (write-line (vl-princ-to-string str) fp))
         (write-line "\n--\n" fp)
       )
      )
    )
    (if fp (progn (close fp)(gc)(gc))) 
    (princ)
  )
  
  (defun show_result (fn)
    (if (and fn (setq fn (findfile fn)))
      (startapp "notepad" fn)
      (alert (strcat "Computer says no : unable to read from : " (vl-princ-to-string fn)))
    )
    (princ)
  )

  ;; (setq d (vl-string-right-trim "\\/" d))
  (setq search-pattern "*" result-list-fn (strcat (vl-string-right-trim "\\/" QSS-Search-Folder) "\\QuickStringSearchResult.txt"))

  ;;; fire-up process bar
  (clear_bar)(set_tile "the_bar" " working...")
  (cond
    ((not (vl-file-directory-p QSS-Search-Folder))
     (alert (strcat "Folder " QSS-Search-Folder " does not exist - change folder")))
    ;((not (vl-consp (setq dwg-list (alf QSS-Search-Folder "*.dwg" (if (eq QSS-Include-Subfolders "1") T nil)))))
    ; (alert (strcat "No dwg files in " QSS-Search-Folder)))
    (t
     ;;; if return-as-list is T regex_string_search returns all strings else T or nil if pattern is found
     (setq return-as-list T file-count 1)
     ;;; first scan for subfolder
     (if (eq QSS-Include-Subfolders "1")
         (setq folder-list (QSS_FindSubfolders QSS-Search-Folder)) (setq folder-list (list QSS-Search-Folder)))
     ;;; just a little delay to enjoy the view, exterminate when it gets anoying
     (wait 1.5)
     (setq dwg-list (QSS_FindFiles folder-list (list "*.dwg")))
     (clear_bar)
     (set_tile "the_bar" (strcat "Number of files to search : " (setq n (itoa (length dwg-list)))))
     (foreach dwg dwg-list
       (if (setq dbx-doc (odbx_open dwg))
         (progn
           (if (vl-consp (setq rtn (regex_string_search dbx-doc search-pattern return-as-list)))
             (setq result-list (cons (cons dwg rtn) result-list)))
           ;;; release doc to prevent dbx memory leak
           ;(odbx_close dbx-doc)
         )
         (princ (strcat "\nUnable to open " dwg))
       )
       ;;; clear previous status
       (clear_bar)
       ;;; update status message
       (set_tile "the_bar" (strcat "   ( " (setq *spin* (Spinbar *spin*)) " ) Scanning files [" (itoa file-count) " of " n))
       ;;; increase file counter
       (setq file-count (1+ file-count))
     )
     (_ReleaseAll)
    )
  )
  ;;; (vlax-release-object dbxObj)

  ;;; release RegExp
  (if (= 'vla-object (type RegExp))(vlax-release-object RegExp))
  
  (if (vl-consp result-list)
    (progn (write_result result-list result-list-fn) (show_result result-list-fn))
    (princ (strcat "\nNo text was found in dwg files in " (vl-princ-to-string search-folder)))
  )
  (princ)
)



;;; doc = duh , pat = duh , ral = return as list , if T return all strings , if nil test for pattern and return nil or T
(defun regex_string_search (doc pat ral / pat-p pattern ingnoreCase global
                            blocks objName textStr atts result s tableRow tableCol)
  ;;; not realy needed because als called in test function
  (or RegExp (setq RegExp (vlax-create-object "VBScript.RegExp")))

  ;;; *** still to do create regex version, not sure pat-p is working as intended
  ;;; test if pattern is found in list of strings (RegExp needs to be initialized)
  (defun pat-p (p l) (vl-some (function (lambda (s)(= (vlax-invoke-method RegExp 'Test s) :vlax-true))) l))

  ;;; *** still to do : apply ignore case / whole words only to pattern
  ;;; alternative : (lwcmatch "M-16427" '("As built K-16886.pdf" "As built M-16427.pdf" "As built N-16260.pdf"))
  (defun lwcmatch ( p l / r ) (foreach x l (if (vl-string-search p x)(setq r (cons x r)))) r)

  ;;; (re)init regex pattern (QSS-Search-String-Filter) is something like "Fikkie|Rlx"
  (setq pattern QSS-Search-String-Filter global T)
  (if (eq QSS-Case-Sensitive "1")(setq ignoreCase nil)(setq ignoreCase T))
  ;;; **** test 2026-06-01 on request Percy ****
  (if (eq QSS-Get-Everything "1") (setq pattern "*"))
  (InitRegExp pattern ignoreCase global)

  ;;; go through all document objects and retrieve textstring, return as list or test with regex (pat-p)
  (setq blocks (vla-get-blocks doc))
  (if (/= pat "")
    (progn
      (vlax-for block blocks
        (vlax-for obj block
          (setq objName (vlax-get-property obj 'ObjectName))
          (setq textStr nil)
          ;;; Filter objects &amp; get textString
          (cond
            ;; Text en MText
            ((vl-position objName '("AcDbText" "AcDbMText"))
             (setq textStr (vlax-get-property obj 'TextString)))
            ;; Old Leaders &amp; Dimensions
            ((vl-position objName '("AcDbLeader" "AcDbDimension" "AcDbRotatedDimension" "AcDbAlignedDimension"))
             (if (vlax-property-available-p obj 'TextOverride)
               (setq textStr (vlax-get-property obj 'TextOverride))))
            ;; Modern MultiLeaders (MLeader)
            ((= objName "AcDbMLeader")
             (if (= (vlax-get-property obj 'ContentType) 2) ; 2 = acMTextContent
               (setq textStr (vlax-get-property obj 'TextString))))
            ;; Block Reference with Attributes
            ((= objName "AcDbBlockReference")
             (if (= (vlax-get-property obj 'HasAttributes) :vlax-true)
               (progn
                 (setq atts (vlax-invoke obj 'GetAttributes))
                 (foreach attObj atts
                   (setq s (vlax-get-property attObj 'TextString))
                   (if (and s (/= s "")) ;(= (vlax-invoke-method RegExp 'Test pat) :vlax-true))
                     (progn (setq textStr (cons  (strcat "Block " (vlax-get-property obj 'Name)
                         ", Tag : " (vlax-get-property attObj 'TagString) ", Text : " s) textStr))))
                 )
               )
             )
            )
            ;; Tabellen (Scant elke cel afzonderlijk)
            ((= objName "AcDbTable")
             (setq tableRow 0)
             (while (&lt; tableRow (vlax-get-property obj 'Rows))
               (setq tableCol 0)
               (while (&lt; tableCol (vlax-get-property obj 'Columns))
                 (setq s (vlax-invoke obj 'GetText tableRow tableCol))
                 (if (and s (/= s "")); (= (vlax-invoke-method regex 'Test textStr) :vlax-true))
                   (setq textStr (cons  (strcat "Table [Row " (itoa tableRow) ", Col " (itoa tableCol) "]: " s) textStr)))
                 (setq tableCol (1+ tableCol))
               )
               (setq tableRow (1+ tableRow))
             )
            )
          ) ;;; end cond
          
          ;;; put result in list
          (cond
            ((null textStr))
            ((vl-consp textStr) (foreach x textStr (setq result (cons x result))))
            (t (setq result (cons textStr result)))
          )
        ) ;;; vlax-for block
      ) ;;; vlax-for blocks
    ) ;;; end progn
  ) ;;; end if (/= pat "")

  ;;; if ral = T return all strings as list else only return T if pattern is found in result list
  ;;; *** still to do replace lwcmatch with regex version (pat-p)
  ;(if ral result (lwcmatch pat result))
  (if ral result (pat-p pattern result))
)


;;; --- Odbx ---------------------------------------------- End Odbx Section ------------------------------------------------- Odbx --- ;;;




;;; --- RegExp -------------------------------------------------- RegExp --------------------------------------------------- RegExp --- ;;;


;;; Separate multiple patterns by pipe-operator |
;;; (vlax-put-property regexp "Pattern" "Rlx|CadTutor|Visual Lisp")
;;; Whole words only (not "Rlxie" when searching for "Rlx"):
;;; (vlax-put-property regexp "Pattern" "\\bRlx\\b|\\bCadTutor\\b|\\bVisual Lisp\\b")

;;; pattern	: Pattern to search.
;;; ignoreCase	: If non nil, the search is done ignoring the case.
;;; global	: If non nil, search all occurences of the pattern, if nil, only searches the first occurence.
(defun InitRegExp (pattern ignoreCase global)
  (or RegExp (setq RegExp (vlax-create-object "VBScript.RegExp")))
  (vlax-put RegExp 'Pattern pattern)
  (if ignoreCase (vlax-put RegExp 'IgnoreCase acTrue)(vlax-put RegExp 'IgnoreCase acFalse))
  (if global (vlax-put RegExp 'Global acTrue)(vlax-put RegExp 'Global acFalse))
  RegExp
)

;;; len :  Number of bytes to read. If non numeric, &lt; 1 or greater than the number of bytes in file everything is returned.
;;; iomode : 1 = read, 2 = write, 8 = append , format : 0 = ascii, -1 = unicode, -2 = system default
(defun _ReadStream ( path len / fso file stream result )
  (vl-catch-all-apply
    '(lambda ( / iomode format size )
       (setq iomode 1 format 0 fso (vlax-create-object "Scripting.FileSystemObject") file (vlax-invoke fso 'GetFile path)
	     stream (vlax-invoke fso 'OpenTextFile path iomode format) size (vlax-get file 'Size)
	     len (if (and (numberp len) (&lt; 0 len size)) (fix len) size) result (vlax-invoke stream 'read len))
       (vlax-invoke stream 'Close)
     )
  )
  (if stream (vlax-release-object stream))(if file (vlax-release-object file))(if fso (vlax-release-object fso))
  result
)

(defun _ReadStream-n ( path len n / fso file stream result lst)
  (vl-catch-all-apply
    '(lambda ( / iomode format size )
       (setq iomode 1 format 0 fso (vlax-create-object "Scripting.FileSystemObject") file (vlax-invoke fso 'GetFile path)
	     stream (vlax-invoke fso 'OpenTextFile path iomode format) size (vlax-get file 'Size)
	     len (if (and (numberp len) (&lt; 0 len size)) (fix len) size))
       (repeat n
	 (setq result (vlax-invoke stream 'read len))
	 (setq lst (cons result lst))
       )
       (vlax-invoke stream 'Close)
     )
  )
  (if stream (vlax-release-object stream))(if file (vlax-release-object file))(if fso (vlax-release-object fso))
  lst
)


;;; T if pattern is found else nil
(defun c:test2 ( / fn pattern stream ignoreCase rtn)
  (setq fn "C:\\Temp\\Lisp\\RlxBatch.lsp")
  (setq ignoreCase T)
  (setq pattern "-publish")
  ;(setq pattern "dragon")
  (and
    (= (type fn) 'STR)
    (setq fn (findfile fn))
    (setq stream (_ReadStream fn 0))
    (setq rtn (= (vlax-invoke (InitRegExp pattern ignoreCase nil) 'Test stream) -1))
  )
  rtn
)

;;; --- RegExp -------------------------------------------------- RegExp --------------------------------------------------- RegExp --- ;;;



;;; --- Excel ---------------------------------------------------- Excel ---------------------------------------------------- Excel --- ;;;

(defun Init_Excel ()
  (or xlApp (setq xlApp (vlax-get-or-create-object "Excel.Application"))) (vla-put-visible xlApp :vlax-false))

(defun Exit_Excel ()
  (if xlApp (progn (vl-catch-all-apply 'vlax-invoke-method (list xlWorkbook 'Close :vlax-false))
    (vlax-release-object xlSheets) (vlax-release-object xlWorkbook) (vlax-release-object xlApp))))

;;; retrieve all values from Excel workbook
(defun Scan_Excel (fn / f xlUsedRange rows xlValue _safearray tmp-lst result excel-range excel-used-range excel-max-row excel-max-column
                        excel-max-range excel-variant excel-value excel-to-list l2 l3 pattern ignoreCase global)
  ;;; just to make sure regex is up and running
  (or RegExp (setq RegExp (vlax-create-object "VBScript.RegExp")))
  ;;; test if pattern is found in list of strings (RegExp needs to be initialized)
  (defun pat-p (p l) (vl-some (function (lambda (s)(= (vlax-invoke-method RegExp 'Test s) :vlax-true))) l))
  ;;; (re)init regex pattern (QSS-Search-String-Filter) is something like "Fikkie|Rlx"
  (setq pattern QSS-Search-String-Filter global T)
  (if (eq QSS-Case-Sensitive "1")(setq ignoreCase nil)(setq ignoreCase T))
  (InitRegExp pattern ignoreCase global)
  
  (if (and fn (string-p fn) (setq f (findfile fn)))
    (progn
      (Init_Excel)
      (setq xlWorkbooks (vlax-get-property xlApp 'Workbooks))
      (setq xlWorkbook (vlax-invoke-method xlWorkbooks 'Open f))
      (setq xlSheets (vlax-get-property xlWorkbook 'Sheets))
      (vlax-for xlSheet xlSheets
        (setq xlUsedRange (vlax-get-property xlSheet 'UsedRange))
        ;;; Set limits on number of rows, not sure what size would be to much for AutoCad to handle
        (setq rows (vlax-get-property (vlax-get-property xlUsedRange 'Rows) 'Count))
        (if (&lt; rows 500000) 
          (progn
	    (and
              (setq excel-variant (vlax-get-property xlUsedRange 'Value))
	      (setq excel-value (vlax-variant-value excel-variant))
              (setq excel-to-list (vlax-safearray-&gt;list excel-value))
	      (setq tmp-lst (vl-remove nil (mapcar '(lambda (x) (vl-remove nil (mapcar '(lambda (y / val)
                (setq val (vl-catch-all-apply 'vlax-variant-value (list y)))
                  (if (vl-catch-all-error-p val) nil val)) x))) excel-to-list)))
              (setq result (append result tmp-lst))
            )
          )
          (princ
            (strcat
              "\nSkipped " (vl-filename-base fn) " Tab '"
                         (vlax-get-property xlSheet 'Name) "' : to many rows (" (itoa rows) ")."))
        )
        (vlax-release-object xlUsedRange)
        (vlax-release-object xlSheet)
      )
      (vlax-invoke-method xlWorkbook 'Close :vlax-false)
    )
  )
  ;;; test if pattern is found in result list , returns T or nil
  (if (vl-consp result) (pat-p pattern (mapcar 'vl-princ-to-string (apply 'append result))))
)
 
;;; --- Excel -------------------------------------------- End of Excel Section --------------------------------------------- Excel --- ;;;


;;; --- Word --------------------------------------------- Begin of Word Section --------------------------------------------- Word --- ;;;

(defun SearchInWord (filePath openText / wordApp docCollection wordDoc wordSelect found)
  (vl-load-com)
  (setq found nil)
  
  ;; 1. Start Word in de achtergrond (onzichtbaar)
  (if (setq wordApp (vlax-get-or-create-object "Word.Application"))
    (progn
      (vla-put-visible wordApp :vlax-false) ; Zorg dat Word onzichtbaar blijft
      (setq docCollection (vla-get-documents wordApp))
      
      ;; 2. Open het document (Alleen-lezen = :vlax-true, Onzichtbaar)
      (setq wordDoc (vlax-invoke-method docCollection 'Open filePath :vlax-false :vlax-true))
      
      (if wordDoc
        (progn
          ;; 3. Gebruik de Find-methode van de documentinhoud
          (setq wordSelect (vlax-get-property wordDoc 'Content))
          (setq wordFind (vlax-get-property wordSelect 'Find))
          
          ;; Voer de zoekopdracht uit (parameters: tekst, matchCase, matchWholeWord, etc.)
          (setq found (vlax-invoke-method wordFind 'Execute openText :vlax-false :vlax-false))
          
          ;; 4. Sluit het document zonder wijzigingen op te slaan
          (vlax-invoke-method wordDoc 'Close :vlax-false)
        )
      )
      ;; 5. Sluit de Word-applicatie af en reinig het geheugen
      (vlax-invoke-method wordApp 'Quit)
      (vlax-release-object wordFind)
      (vlax-release-object wordSelect)
      (vlax-release-object wordDoc)
      (vlax-release-object docCollection)
      (vlax-release-object wordApp)
    )
  )
  ;; Geeft :vlax-true terug als de tekst is gevonden, anders :vlax-false of nil
  found
)

;;; ------------------------------------------------------- End of Word Section ------------------------------------------------------- ;;;



;;; powershell

;;;powershell -Command "$w=New-Object -ComObject Word.Application; $w.Visible=$false; $d=$w.Documents.Open('C:\Pad\Naam.pdf',+
;;;                    $false, $true); if($d.Content.Find.Execute('ZOEKTERM')) { 'GEVONDEN' | Out-File 'C:\Users\Naam\Desktop\result.txt' };+
;;;                    $d.Close($false); $w.Quit()"
;;; (SearchInPDF "c:\\temp\\test.pdf" "Rlx")
(defun SearchInPDF (pdfPath openText / shApp txtResult resFile found)
  (vl-load-com)
  (setq resFile (strcat (getenv "USERPROFILE") "\\Desktop\\pdf_result.txt"))
  
  ;; 1. Verwijder een eventueel oud resultaatbestand op de desktop
  (if (findfile resFile) (vl-file-delete resFile))

  ;; 2. Bouw het PowerShell-commando op (alles op 1 regel)
  ;; Dit opent de PDF via de Word-engine op de achtergrond en zoekt naar de tekst.
  (setq psCmd (strcat
    "powershell -WindowStyle Hidden -Command "
    "\"$w=New-Object -ComObject Word.Application; $w.Visible=$false; "
    "$d=$w.Documents.Open('" pdfPath "', $false, $true); "
    "if($d.Content.Find.Execute('" openText "')) { 'JA' | Out-File '" resFile "' }; "
    "$d.Close($false); $w.Quit();\""
  ))

  ;; 3. Voer het commando onzichtbaar uit via de Windows Shell
  (setq shApp (vlax-get-or-create-object "WScript.Shell"))
  (vlax-invoke-method shApp 'Run psCmd 0 :vlax-true) ; 0 = onzichtbaar venster, :vlax-true = wacht tot klaar
  (vlax-release-object shApp)

  ;; 4. Controleer of het tekstbestand is aangemaakt (tekst is gevonden!)
  (if (findfile resFile)
    (progn
      (setq found t)
      (vl-file-delete resFile) ; Netjes opruimen
    )
    (setq found nil)
  )
  
  found ; Geeft T terug als de tekst in de PDF staat, anders nil
)

;;; powershell



;;; -------------------------------------------------- Begin of Progress Bar Section -------------------------------------------------- ;;;

; (setq lst (acad_strlsort (QSS_FindSubfolders "c:/temp/lisp")))
(defun QSS_FindSubfolders ( d / l r s msg ) (setq d (vl-string-right-trim "\\/" d))  (setq l (list d)) trim
  (while l (setq s nil)(foreach d l (setq s (append s (mapcar (function (lambda ( x ) (strcat d "/" x)))
    (vl-remove-if (function (lambda (x)(member x '("." ".."))))(vl-directory-files d nil -1))))))(setq r (append s r) l s)
      (start_image "the_bar")(fill_image 0 0 (dimx_tile "the_bar") (dimy_tile "the_bar") 131)(end_image)
      (setq msg (strcat "   ( " (setq *spin* (Spinbar *spin*))" ) Scanning for subfolders : " (itoa (length r))))
      (set_tile "the_bar" msg)
  )
  ;;; make sure sourcefolder is part of result
  (cons d r)
)

;;; called from QSS_Pre_Scan line 201
;;; (setq rtn (QSS_FindFiles '("c:/temp/lisp") '("*.lsp" "*.txt")))
(defun QSS_FindFiles (folder-list extension-list / folder result result-list status)
  ;;; folder-list is list of all (sub)folders to scan , make sure all folders end with "/"
  (setq folder-list (acad_strlsort (mapcar 'vl_path folder-list)))
  (foreach folder folder-list
    (foreach ext extension-list
      (if (vl-consp (setq result (mapcar '(lambda (x) (strcat folder x)) (vl-directory-files folder ext 1))))
        (setq result-list (append result-list result))
      )
    )
    ;;; clear previous status
    (start_image "the_bar")(fill_image 0 0 (dimx_tile "the_bar") (dimy_tile "the_bar") 141)(end_image)
    ;;; update status message
    (setq status (strcat "   ( " (setq *spin* (Spinbar *spin*)) " ) Scanning for files : " (itoa (length result-list))))
    (set_tile "the_bar" status)
  )
  result-list
)

; funny little indicator found in StripMtext.lsp
;(princ (strcat "\r (" (setq s (Spinbar s)) ") Files : " (itoa (setq i (1+ i))) "\t\t"))
(defun SpinBar (spin) (cond ((= spin "\\") "|") ((= spin "|") "/") ((= spin "/") "-") (t "\\")))

;;; ---------------------------------------------------- End of Progress Bar Section -------------------------------------------------- ;;;

(princ "\nQuick String Search - Rlx Jun'26 - Type QSS")

;(c:qss)</pre>

<p>
	Most info included in lisp file. Just a quick string search for lsp, txt &amp; dwg files.
</p>

<p>
	 
	</p><p>
		Start with QSS , select folder , extension like lsp,dwg and search string like Rlx
	</p>


<p>
	Type in extensions like lsp,txt (with comma) and for text use pipe symbol like Rlx|Dragon
</p>

<p>
	for now only lsp,txt and dwg are supported , haven't been able to make it work on pdf
</p>

<p>
	 
</p>

<p>
	I have added a couple of toggles , Shadow mode , Recovery &amp; Everything.
</p>

<p>
	Shadow mode writes a log file for every file that is searched. Next to it is Recovery.
</p>

<p>
	When searching oh lets say 100.000+ files and one of the files is corrupt AutoCad crashes and all previous results are poof...
</p>

<p>
	When this happens start AutoCad again , select Recovery , and app will continue the search by comparing the complete file-list
</p>

<p>
	with the shadow list and can work out from where to continue and put corrupt drawing on the naughty list.
</p>

<p>
	These files are saved on desktop in QuickSearchFolder.
</p>

<p>
	 
</p>

<p>
	If a drawing was saved with a higher version I can error-catch that but when a file is corrupt lisp can't handle that so hence the recovery option.
</p>

<p>
	When multiple drawings are corrupt you have to repeat this process as many times until app reaches the finish line.
</p>

<p>
	 
</p>

<p>
	When the list pops up you only see the matches found from the last successful run, click on the load button and shadow list is read again et voila.
</p>

<p>
	 
</p>

<p>
	When 'Everything' is selected all text from all files (drawings) are saved to a text file.
</p>

<p>
	 
</p>

<p>
	Button Clear Lists in main dialog deletes all files from desktop folder so you can start as fresh as a baby's butt (after a bath of course)
</p>

<p>
	 
</p>

<p>
	Also corrected a little bug in the get-subfolders routine. Within the code I was working on doc/docx &amp; pdf support but they are so slow I removed them from extension filter , but if you want to try uncomment line 285 and comment line 286
</p>

<p>
	 
</p>

<p>
	<img src="https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f409.png" class="ipsEmoji" alt="🐉">
</p>

<p>
	 
</p>

<p>
	 
</p>

<p>
	 
</p>

<p>
	 
</p>

<p><a href="https://www.cadtutor.net/forum/uploads/monthly_2026_06/qss1.jpg.202460bccc99799417a63c9ab78c5cab.jpg" class="ipsAttachLink ipsAttachLink_image" ><img data-fileid="70378" src="https://www.cadtutor.net/forum/applications/core/interface/js/spacer.png" data-src="https://www.cadtutor.net/forum/uploads/monthly_2026_06/qss1.thumb.jpg.4c98c5eeea7ce2068c721eab518edf8a.jpg" data-ratio="45.75" width="800" class="ipsImage ipsImage_thumbnailed" alt="qss1.jpg"></a></p>
<p><a href="https://www.cadtutor.net/forum/uploads/monthly_2026_06/qss2.jpg.20233d8484f07e22b0ba5b47658ce890.jpg" class="ipsAttachLink ipsAttachLink_image" ><img data-fileid="70380" src="https://www.cadtutor.net/forum/applications/core/interface/js/spacer.png" data-src="https://www.cadtutor.net/forum/uploads/monthly_2026_06/qss2.jpg.20233d8484f07e22b0ba5b47658ce890.jpg" data-ratio="84.17" width="575" class="ipsImage ipsImage_thumbnailed" alt="qss2.jpg"></a></p>
<p><a href="https://www.cadtutor.net/forum/uploads/monthly_2026_06/qss3.jpg.98ec3dbb4e0d1a5c5477af0758b1f112.jpg" class="ipsAttachLink ipsAttachLink_image" ><img data-fileid="70381" src="https://www.cadtutor.net/forum/applications/core/interface/js/spacer.png" data-src="https://www.cadtutor.net/forum/uploads/monthly_2026_06/qss3.jpg.98ec3dbb4e0d1a5c5477af0758b1f112.jpg" data-ratio="83.62" width="574" class="ipsImage ipsImage_thumbnailed" alt="qss3.jpg"></a></p>]]></description><guid isPermaLink="false">99135</guid><pubDate>Sun, 17 May 2026 16:12:02 +0000</pubDate></item><item><title>RlxSplit - Split up large files</title><link>https://www.cadtutor.net/forum/topic/99145-rlxsplit-split-up-large-files/</link><description><![CDATA[<p>
	As usual this was born out of necessity. Had a 46Mb pdf , no tools on work laptop to convert it because also no adobe (reader only). PdF was all images so AutoCad pdf attach / import won't work either. Have a (legal) tool on my own computer but pdf wouldn't fit through the mail because of IT limitations. We used to have something like One-drive / Sharepoint but also blocked now , so I wrote this app. It chops up pdf in to 10MB pieces (or any size you want) , it can also email them at the same time and at the other end of the line you can put the pieces back again with the same app. So if your IT department tries to make your life a living hell , hell , maybe this app can give you some relief.
</p>

<p>
	 
</p>

<p>
	<img src="https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f409.png" class="ipsEmoji" alt="🐉">
</p>

<p><a href="https://www.cadtutor.net/forum/uploads/monthly_2026_05/RlxSplitEmail.jpg.5e11ac22d25a928f707d77e1fa9716e5.jpg" class="ipsAttachLink ipsAttachLink_image" ><img data-fileid="70366" src="https://www.cadtutor.net/forum/applications/core/interface/js/spacer.png" data-src="https://www.cadtutor.net/forum/uploads/monthly_2026_05/RlxSplitEmail.jpg.5e11ac22d25a928f707d77e1fa9716e5.jpg" data-ratio="70.18" width="436" class="ipsImage ipsImage_thumbnailed" alt="RlxSplitEmail.jpg"></a></p>
<p><a href="https://www.cadtutor.net/forum/uploads/monthly_2026_05/RlxSplitMain.jpg.b2ec0c3d4a61802c4fcd61539451187d.jpg" class="ipsAttachLink ipsAttachLink_image" ><img data-fileid="70367" src="https://www.cadtutor.net/forum/applications/core/interface/js/spacer.png" data-src="https://www.cadtutor.net/forum/uploads/monthly_2026_05/RlxSplitMain.jpg.b2ec0c3d4a61802c4fcd61539451187d.jpg" data-ratio="46.74" width="537" class="ipsImage ipsImage_thumbnailed" alt="RlxSplitMain.jpg"></a></p><p>
<a class="ipsAttachLink" href="https://www.cadtutor.net/forum/applications/core/interface/file/attachment.php?id=70365&amp;key=e48b0d9e657557a55e9c48d52b2dba9d" data-fileExt='lsp' data-fileid='70365' data-filekey='e48b0d9e657557a55e9c48d52b2dba9d'>RlxSplit.lsp</a></p>]]></description><guid isPermaLink="false">99145</guid><pubDate>Thu, 28 May 2026 07:26:35 +0000</pubDate></item><item><title>Set Pline Z value by selecting text</title><link>https://www.cadtutor.net/forum/topic/99139-set-pline-z-value-by-selecting-text/</link><description><![CDATA[<p>
	Hi,
</p>

<p>
	I have been racking my brains to amend this lisp to do what i want and have failed.... so i ask you the gods of lisp for some help.
</p>

<p>
	I have acquired a lisp file via google AI that will set the elevation (z axis) of a poly line, easier to just select the pline and type in the elevation i hear you cry....
</p>

<p>
	But my cunning plan was to amend the elevation of said pline by selecting the pline then select the text/mtext next to it.....
</p>

<p>
	I thought i could add some command to do this by looking at another lisp i have that does a similar thing, but i am a numpty and have given up....
</p>

<p>
	I know there are many wise men out there that could just type some lines with their eyes shut and solve my problem...
</p>

<p>
	Obviously i would be greatly indebted to such persons and wish boundless fortune upon them granting wishes galore if i could...
</p>

<p>
	Also I just want an easy life as i approach retirement and thinking for gets in the way of thinking for myself.....
</p>

<p>
	Begging you nicely..
</p>

<p>
	 
</p>

<p>
	Paul
</p>
<p>
<a class="ipsAttachLink" href="https://www.cadtutor.net/forum/applications/core/interface/file/attachment.php?id=70341&amp;key=8023f367f3da54535023f76e5e7a2941" data-fileExt='lsp' data-fileid='70341' data-filekey='8023f367f3da54535023f76e5e7a2941'>SetPlineZ.lsp</a></p>]]></description><guid isPermaLink="false">99139</guid><pubDate>Fri, 22 May 2026 14:38:08 +0000</pubDate></item><item><title>LISP CODE INSERTING ELEVATION FROM CIVIL 3D SURFACE TO 3DPOLYLINES</title><link>https://www.cadtutor.net/forum/topic/99140-lisp-code-inserting-elevation-from-civil-3d-surface-to-3dpolylines/</link><description><![CDATA[<p>
<a class="ipsAttachLink" href="https://www.cadtutor.net/forum/applications/core/interface/file/attachment.php?id=70349&amp;key=125b1dc1b343234b39ea6eac4bc1d28f" data-fileExt='LSP' data-fileid='70349' data-filekey='125b1dc1b343234b39ea6eac4bc1d28f'>3PS.LSP</a></p>]]></description><guid isPermaLink="false">99140</guid><pubDate>Mon, 25 May 2026 13:25:27 +0000</pubDate></item><item><title>A routine automates the creation of 3D Polylines, level labels, and  slope percentages for infrastructure projects (SUPPORTS FEATURE LINES TOO)</title><link>https://www.cadtutor.net/forum/topic/99121-a-routine-automates-the-creation-of-3d-polylines-level-labels-and-slope-percentages-for-infrastructure-projects-supports-feature-lines-too/</link><description><![CDATA[<p>
	Good day,
</p>

<p>
	The lisp routine here supports automatic  projection between lines, custom perpendicular line generation, and  manual adjustment of slopes.<br />
	The explanation for its functions within the routine.<br />
	Regards.
</p>
<p>
<a class="ipsAttachLink" href="https://www.cadtutor.net/forum/applications/core/interface/file/attachment.php?id=70306&amp;key=d29bd3272e925956b7c39b45d8ef3e03" data-fileExt='LSP' data-fileid='70306' data-filekey='d29bd3272e925956b7c39b45d8ef3e03'>3DSLOPE-automates the creation of 3D Polylines, level labels, and  slope percentages.LSP</a></p>]]></description><guid isPermaLink="false">99121</guid><pubDate>Wed, 13 May 2026 06:58:36 +0000</pubDate></item><item><title>MultiPLine (MPL) &#x2014; polyline-based MLINE replacement with per-line layers, presets, and auto-sync [Free + Pro]</title><link>https://www.cadtutor.net/forum/topic/99133-multipline-mpl-%E2%80%94-polyline-based-mline-replacement-with-per-line-layers-presets-and-auto-sync-free-pro/</link><description><![CDATA[<p>
	Hi all,
</p>

<p>
	 
</p>

<p>
	I've been a lurker on CADTutor for years and learned 
</p>

<p>
	a lot from this community, so I wanted to share 
</p>

<p>
	something I built and get feedback from people who 
</p>

<p>
	actually know LISP.
</p>

<p>
	 
</p>

<p>
	Background: I'm a civil CAD drafter working on US 
</p>

<p>
	land development projects — grading, drainage, 
</p>

<p>
	easements, corridors. MLINE has always been the 
</p>

<p>
	tool I wanted to use for drawing parallel offset 
</p>

<p>
	lines but couldn't, mainly because the objects are 
</p>

<p>
	locked, there's no lineweight control per component, 
</p>

<p>
	and the .mln style management across a team is a 
</p>

<p>
	nightmare. So I wrote a replacement.
</p>

<p>
	 
</p>

<p>
	──────────────────────────────────
</p>

<p>
	WHAT IT DOES
</p>

<p>
	──────────────────────────────────
</p>

<p>
	 
</p>

<p>
	Command MPL works like PLINE — you draw a centerline 
</p>

<p>
	and it generates a set of configurable parallel 
</p>

<p>
	LWPOLYLINEs around it. Every satellite line is a 
</p>

<p>
	real polyline: fully grip-editable, trimmable, 
</p>

<p>
	offsettable, joinable. No locked geometry, no 
</p>

<p>
	exploding required.
</p>

<p>
	 
</p>

<p>
	Each satellite line carries its own:
</p>

<p>
	- Offset distance (positive = left, negative = right)
</p>

<p>
	- Layer (Pro version)
</p>

<p>
	- Color, linetype, lineweight, linetype scale
</p>

<p>
	 
</p>

<p>
	Configuration is handled through a DCL dialog 
</p>

<p>
	(MPLEDIT). Settings save as user defaults and, 
</p>

<p>
	in the Pro version, as named presets stored in 
</p>

<p>
	%APPDATA%\MplineAuto\presets.dat.
</p>

<p>
	 
</p>

<p>
	──────────────────────────────────
</p>

<p>
	TWO VERSIONS
</p>

<p>
	──────────────────────────────────
</p>

<p>
	 
</p>

<p>
	Lite (free .lsp):
</p>

<p>
	- MPL, MPLEDIT, MPLSYNC
</p>

<p>
	- Manual sync after edits — run MPLSYNC, 
</p>

<p>
	  window-select the group, done
</p>

<p>
	- Groups are tracked via XDATA (app tag: MPLINE_PIPE)
</p>

<p>
	 
</p>

<p>
	Pro (compiled .vlx, $29.49):
</p>

<p>
	- Everything in Lite plus:
</p>

<p>
	- Command reactor for auto-sync — watches masters 
</p>

<p>
	  before/after every command, diffs vertex lists, 
</p>

<p>
	  rebuilds only what changed
</p>

<p>
	- Named preset library with Save/Update/Delete 
</p>

<p>
	  from the dialog
</p>

<p>
	- Per-satellite layer assignment
</p>

<p>
	- MPLADD — promote existing LWPOLYLINEs or LINEs 
</p>

<p>
	  into MPL groups
</p>

<p>
	- MPLON / MPLOFF — toggle reactor at runtime
</p>

<p>
	- XDATA app tag: MPLINE_AUTO
</p>

<p>
	 
</p>

<p>
	──────────────────────────────────
</p>

<p>
	IMPLEMENTATION NOTES
</p>

<p>
	──────────────────────────────────
</p>

<p>
	 
</p>

<p>
	The interesting part was the Pro reactor. I went 
</p>

<p>
	through a few approaches before landing on a global 
</p>

<p>
	command reactor that snapshots the master cache 
</p>

<p>
	before a command fires and diffs it after. This 
</p>

<p>
	avoids object reactors entirely (which caused IDispatch 
</p>

<p>
	arity issues in testing) and means the reactor 
</p>

<p>
	doesn't interfere with Express Tools or COPY/MIRROR 
</p>

<p>
	operations on non-MPL geometry.
</p>

<p>
	 
</p>

<p>
	Groups copied with COPY or MIRROR produce new masters 
</p>

<p>
	on the next MPLSYNC call — the reactor doesn't 
</p>

<p>
	auto-register copies, which is intentional to avoid 
</p>

<p>
	unexpected geometry multiplication.
</p>

<p>
	 
</p>

<p>
	Happy to discuss the approach if anyone has thoughts 
</p>

<p>
	or has solved similar problems differently.
</p>

<p>
	 
</p>

<p>
	──────────────────────────────────
</p>

<p>
	LINKS
</p>

<p>
	──────────────────────────────────
</p>

<p>
	 
</p>

<p>
	Video walkthrough: <a href="https://youtu.be/DXpyy1JWtXs" rel="external nofollow">https://youtu.be/DXpyy1JWtXs</a>
</p>

<p>
	 
</p>

<p>
	Free Lite download: 
</p>

<p>
	<a href="https://skillamplifier.gumroad.com/l/hgpujs" rel="external nofollow">https://skillamplifier.gumroad.com/l/hgpujs</a>
</p>

<p>
	 
</p>

<p>
	Pro listing: 
</p>

<p>
	<a href="https://skillamplifier.gumroad.com/l/nsidsv" rel="external nofollow">https://skillamplifier.gumroad.com/l/nsidsv</a>
</p>

<p>
	 
</p>

<p>
	Blog post with full documentation and use cases:
</p>

<p>
	<a href="https://skillamplifier.wordpress.com/2026/05/16/multipline/" rel="external nofollow">https://skillamplifier.wordpress.com/2026/05/16/multipline/</a>
</p>

<p>
	 
</p>

<p>
	Full disclosure: I'm the developer. Posting here 
</p>

<p>
	because I'd genuinely value feedback from experienced 
</p>

<p>
	LISP users, and the Lite version is free so there's 
</p>

<p>
	no risk trying it.
</p>

<p>
	 
</p>

<p>
	Thanks for any thoughts.
</p>

<p>
	 
</p>

<p>
	Zlatislav
</p>
]]></description><guid isPermaLink="false">99133</guid><pubDate>Sat, 16 May 2026 19:01:06 +0000</pubDate></item><item><title>A toolkit is designed to streamline the conversion of raw survey texts ,and markers into professional MLeaders</title><link>https://www.cadtutor.net/forum/topic/99127-a-toolkit-is-designed-to-streamline-the-conversion-of-raw-survey-texts-and-markers-into-professional-mleaders/</link><description><![CDATA[<p>
	This code is so helpful to convert texts or mtexts to mleader.<br />
	In the attachments the lisp file and cad file that has the problem I tied to solve.<br />
	The cad file contains a huge amounts of elevations as texts and leaders that are exploded for landscape work , therefore this lisp can help with case like this <br />
	<br />
	Regards
</p>
<p>
<a class="ipsAttachLink" href="https://www.cadtutor.net/forum/applications/core/interface/file/attachment.php?id=70308&amp;key=2223addfd5a4f4fe83db8c4079ccbd99" data-fileExt='lsp' data-fileid='70308' data-filekey='2223addfd5a4f4fe83db8c4079ccbd99'>TBC- JOIN TEXT AND POLYLINES AND CONVERT THEM TO MLEADER OR MAKE IT MANUALLY.lsp</a> 
<a class="ipsAttachLink" href="https://www.cadtutor.net/forum/applications/core/interface/file/attachment.php?id=70309&amp;key=21df4a25b37b592154b0f3bfec37d1a4" data-fileExt='dwg' data-fileid='70309' data-filekey='21df4a25b37b592154b0f3bfec37d1a4'>BR FIN LVLS-1.dwg</a></p>]]></description><guid isPermaLink="false">99127</guid><pubDate>Thu, 14 May 2026 05:06:45 +0000</pubDate></item><item><title>ARES Commander LISP not Working</title><link>https://www.cadtutor.net/forum/topic/99137-ares-commander-lisp-not-working/</link><description><![CDATA[<p>
	can anyone help me with this, this lisp work in autocad perfectly but i want to use this to ares but it doesn't work <br />
	<br />
	 
</p>

<pre class="ipsCode">(defun c:KKK ( / TBName TBTemp s flag ctr SheetSize chk PrjName LaynName i n e x 1p 2p o1p o2p y1p y2p s1 i1 n1 e1 x1 s2 i2 n2 e2 x2 Psize Size file tempViewName DwgTitle )
  
  (setvar "CMDECHO" 0)

  (setq TBName "Title Block_R2.R")
  (setq TBTemp "FT NEW TEMPLATE 2.0")
  (setq s nil)
  (setq flag 1)
  (setq ctr 1)
  (setq SheetSize nil)
  (setq chk nil)
  (setq LaynName (car (layoutlist)))
  (setq DwgTitle "Title_info")
  (setq tempViewName "_TEMP_ORIGINAL_VIEW")
  
  (if (setq s (ssget (list '(0 . "INSERT") )))
        (progn
            (command "-VIEW" "S" tempViewName)
            (setq chk T)
            (setq i 0
                  n (sslength s)
            )
            (while (&lt; i n)
                (setq e (ssname s i)
                      x (cdr (assoc 2 (entget e)))
                      i (1+ i)
                )
              ;(print x)
                (if (= (LM:name-&gt;effectivename x) TBName )
                  (progn
                    (command "_zoom" "_object" (cdr(car(entget e))) "")
                    (setq 1P (car(LM:boundingbox (vlax-ename-&gt;vla-object (cdr(car(entget e)))))))
                    (setq 2P (nth 2 (LM:boundingbox (vlax-ename-&gt;vla-object (cdr(car(entget e)))))))
                    (setq o1P 1P)
                    (setq o2P 2P)
                    (setq y1p (strcat (rtos (car 1P) 2 0) "," (rtos (car (cdr 2P)) 2 0)))
                    (setq y2p y1p)
                    
                    (setq s1 (ssget "W" 1P 2P (list '(0 . "INSERT") )))
                    
                                (setq i1 0
                                      n1 (sslength s1)
                                )
                                (while (&lt; i1 n1)
                                  (setq e1 (ssname s1 i1)
                                      x1 (cdr (assoc 2 (entget e1)))
                                      i1 (1+ i1)
                                  )
                                  
                                  (if (= (cdr (assoc 0 (entget e1))) "INSERT")
                                    (cond 
                                      ((= (LM:getvisibilitystate (vlax-ename-&gt;vla-object (cdr (car (entget e1))))) "NESTED")
                                        (setq SheetSize (LM:assoc++ (setq Size (strcat (LM:getattributevalue (cdr (car(entget e1))) "SHEET_WIDTH") "X" (LM:getattributevalue (cdr (car(entget e1))) "SHEET_HEIGHT"))) SheetSize))
                                        (setq PSize (assoc Size SheetSize))
                                        (setq Psize (strcat (car Psize)"-" (fixitoa (cdr Psize) 2)))
                                        
                                      )
                                      ((= (LM:getvisibilitystate (vlax-ename-&gt;vla-object (cdr (car (entget e1))))) "SINGLE PANEL")
                                        (setq s2 (ssget "W" (subst (- (car 1p) 450) (car 1p) 1p) 2P (list '(0 . "INSERT") )))
                                        (setq i2 0
                                                    n2 (sslength s2)
                                              )
                                              (while (&lt; i2 n2)
                                                  (setq e2 (ssname s2 i2)
                                                        x2 (cdr (assoc 0 (entget e2)))
                                                        i2 (1+ i2)
                                                  )
                                                (if (= (LM:name-&gt;effectivename (cdr (assoc 2 (entget e2)))) "NestedPanelTitle")
                                                  (setq Psize (LM:getattributevalue (cdr (car(entget e2))) "PANELNAME"))
                                                )
                                                (if (= (LM:name-&gt;effectivename (cdr (assoc 2 (entget e2)))) "AWC")
                                                  (LM:setattributevalue e2 "RUN_PROGRAM" "-")
                                                )
                                              ) 
                                            
                                      )
                                      ((= (LM:getvisibilitystate (vlax-ename-&gt;vla-object (cdr (car (entget e1))))) "NESTED (OFFCUT)")
                                        (setq SheetSize (LM:assoc++ "OFFCUT" SheetSize))
                                        (setq PSize (assoc "OFFCUT" SheetSize))
                                        (setq Psize (strcat (car Psize)"-" (fixitoa (cdr Psize) 2)))
                                        
                                      )
                                       ((= x1 DwgTitle)
                                       (setq PrjName (vl-string-trim "Model" (LM:getattributevalue e1 "PROGRAM_NAME:")))

                                      ) 
                                    );cond
                                  );if
                                );while
                  );progn
                );if
            )
          (if (= PSIZE nil)
            (setq flag 0)
            (progn
              
              (CreateScript)
            )
          )
        )
    (progn
    (setq flag 0)
    (setq ctr 0)
    )
    );if
    (princ)
  
  
(while (= flag 1)
  (while (= ctr 1)
    (setq 1P (list (car 1P)(- (car(cdr 1P)) 4127 )))
    (setq 2P (list (car 2P)(- (car(cdr 2P)) 4127 )))
    (setq y1p (strcat (rtos (car 1P) 2 0) "," (rtos (car (cdr 2P)) 2 0)))
    
    (command "._zoom" "non" 1P "non" 2P)
    
    (if (setq s (ssget "_W" 1P 2P)) 
        (progn
            (setq i 0
                  n (sslength s)
            )
            (while (&lt; i n)
                (setq e (ssname s i)
                      x (cdr (assoc 0 (entget e)))
                      i (1+ i)
                )
              (if (= x "INSERT")
                (cond 
                  ((= (LM:getvisibilitystate (vlax-ename-&gt;vla-object (cdr (car (entget e))))) "NESTED")
                    (setq SheetSize (LM:assoc++ (setq Size (strcat (LM:getattributevalue (cdr (car(entget e))) "SHEET_WIDTH") "X" (LM:getattributevalue (cdr (car(entget e))) "SHEET_HEIGHT"))) SheetSize))
                    (setq PSize (assoc Size SheetSize))
                    (setq Psize (strcat (car Psize)"-" (fixitoa (cdr Psize) 2)))
                    (WriteScript)
                    (setq ctr 1)
                  )
                  ((= (LM:getvisibilitystate (vlax-ename-&gt;vla-object (cdr (car (entget e))))) "SINGLE PANEL")
                    (setq s2 (ssget "W" (subst (- (car 1p) 450) (car 1p) 1p) 2P (list '(0 . "INSERT") )))
                    (setq i2 0
                                n2 (sslength s2)
                          )
                          (while (&lt; i2 n2)
                              (setq e2 (ssname s2 i2)
                                    x2 (cdr (assoc 0 (entget e2)))
                                    i2 (1+ i2)
                              )
                            (if (= (LM:name-&gt;effectivename (cdr (assoc 2 (entget e2)))) "NestedPanelTitle")
                              (setq Psize (LM:getattributevalue (cdr (car(entget e2))) "PANELNAME"))
                            )
                            (if (= (LM:name-&gt;effectivename (cdr (assoc 2 (entget e2)))) "AWC")
                              (LM:setattributevalue e2 "RUN_PROGRAM" "-")
                            )
                          ) 
                    (WriteScript)
                    (setq ctr 1)
                  )
                  ((= (LM:getvisibilitystate (vlax-ename-&gt;vla-object (cdr (car (entget e))))) "NESTED (OFFCUT)")
                    (setq SheetSize (LM:assoc++ "OFFCUT" SheetSize))
                    (setq PSize (assoc "OFFCUT" SheetSize))
                    (setq Psize (strcat (car Psize)"-" (fixitoa (cdr Psize) 2)))
                    (WriteScript)
                    (setq ctr 1)
                  )
                );cond
                
              )
            );WHILE
        );PROGN
    );IF
    (if (= s nil) (setq ctr 0))
    (princ)
  );while
    (setq 1P (list (+ (car o1P) 6830 )(car(cdr o1P))))
    (setq 2P (list (+ (car o2P) 6830 )(car(cdr o2P))))
    (setq y1p (strcat (rtos (car 1P) 2 0) "," (rtos (car (cdr 2P)) 2 0)))
    (setq o1P 1P)
    (setq o2P 2P)
    (command "_zoom" 1P 2P)
  
    (if (setq s (ssget "_W" 1P 2P))
        (progn
            (setq i 0
                  n (sslength s)
            )
            (while (&lt; i n)
                (setq e (ssname s i)
                      x (cdr (assoc 0 (entget e)))
                      i (1+ i)
                )
              
              (if (= x "INSERT")
                (cond 
                  ((= (LM:getvisibilitystate (vlax-ename-&gt;vla-object (cdr (car (entget e))))) "NESTED")
                    (setq SheetSize (LM:assoc++ (setq Size (strcat (LM:getattributevalue (cdr (car(entget e))) "SHEET_WIDTH") "X" (LM:getattributevalue (cdr (car(entget e))) "SHEET_HEIGHT"))) SheetSize))
                    (setq PSize (assoc Size SheetSize))
                    (setq Psize (strcat (car Psize)"-" (fixitoa (cdr Psize) 2)))
                    (WriteNextScript)
                    (setq ctr 1)
                    
                  )
                  ((= (LM:getvisibilitystate (vlax-ename-&gt;vla-object (cdr (car (entget e))))) "SINGLE PANEL")
                    (setq s2 (ssget "W" (subst (- (car 1p) 450) (car 1p) 1p) 2P (list '(0 . "INSERT") )))
                    (setq i2 0
                                n2 (sslength s2)
                          )
                          (while (&lt; i2 n2)
                              (setq e2 (ssname s2 i2)
                                    x2 (cdr (assoc 0 (entget e2)))
                                    i2 (1+ i2)
                              )
                            (if (= (LM:name-&gt;effectivename (cdr (assoc 2 (entget e2)))) "NestedPanelTitle")
                              (setq Psize (LM:getattributevalue (cdr (car(entget e2))) "PANELNAME"))
                            )
                            (if (= (LM:name-&gt;effectivename (cdr (assoc 2 (entget e2)))) "AWC")
                              (LM:setattributevalue e2 "RUN_PROGRAM" "-")
                            )                            
                          ) 
                    (WriteNextScript)
                    (setq ctr 1)
                    
                  )
                  ((= (LM:getvisibilitystate (vlax-ename-&gt;vla-object (cdr (car (entget e))))) "NESTED (OFFCUT)")
                    (setq SheetSize (LM:assoc++ "OFFCUT" SheetSize))
                    (setq PSize (assoc "OFFCUT" SheetSize))
                    (setq Psize (strcat (car Psize)"-" (fixitoa (cdr Psize) 2)))
                    (WriteNextScript)
                    (setq ctr 1)
                  )
                  
                );cond
                
              )
            );WHILE
        );PROGN
    );IF
  
  (if (= nil s)(setq flag 0))
);while
  (DelAllLayout)
  (if (= chk nil)
    (princ "\nInvalid Object")
      (progn
        (setq file (open (strcat (getvar "dwgprefix") "CreateScript.scr") "A"))
        (write-line "LockAllVp" file)
        (write-line "MODEL" file)
        (write-line (strcat "-VIEW\tR " tempViewName "\n ") file)
        (write-line (strcat "-VIEW\tD " tempViewName "\n ") file)
        (write-line "REGENALL" file)
        (close file)
        (command "_.Layout" "Set" (car (layoutlist)))
        (command "_.script" (strcat (getvar "dwgprefix") "CreateScript.scr"))
      )
  )
  (setvar "CMDECHO" 1)
  (princ)
);defun

;=========================================================================

(defun LM:name-&gt;effectivename ( blk / rep )
  (if
    (and  (wcmatch blk "`**")
          (setq rep
            (cdadr
              (assoc -3
                (entget
                  (cdr (assoc 330 (entget (tblobjname "block" blk))))
                    '("AcDbBlockRepBTag")
                )
              )
            )
          )
          (setq rep (handent (cdr (assoc 1005 rep))))
    )
    (cdr (assoc 2 (entget rep)))
      blk
  )
)

;=========================================================================

(defun LM:boundingbox ( obj / a b lst )
    (if
        (and
            (vlax-method-applicable-p obj 'getboundingbox)
            (not (vl-catch-all-error-p (vl-catch-all-apply 'vla-getboundingbox (list obj 'a 'b))))
            (setq lst (mapcar 'vlax-safearray-&gt;list (list a b)))
        )
        (mapcar '(lambda ( a ) (mapcar '(lambda ( b ) ((eval b) lst)) a))
           '(
                (caar   cadar)
                (caadr  cadar)
                (caadr cadadr)
                (caar  cadadr)
            )
        )
    )
)

;=========================================================================

(defun LM:getattributevalue ( blk tag / enx )
    (if (and (setq blk (entnext blk)) (= "ATTRIB" (cdr (assoc 0 (setq enx (entget blk))))))
        (if (= (strcase tag) (strcase (cdr (assoc 2 enx))))
            (cdr (assoc 1 (reverse enx)))
            (LM:getattributevalue blk tag)
        )
    )
)

;=========================================================================

(defun LM:setattributevalue ( blk tag val / enx )
    (if (and (setq blk (entnext blk)) (= "ATTRIB" (cdr (assoc 0 (setq enx (entget blk))))))
        (if (= (strcase tag) (strcase (cdr (assoc 2 enx))))
            (if (entmod (subst (cons 1 val) (assoc 1 (reverse enx)) enx))
                (progn
                    (entupd blk)
                    val
                )
            )
            (LM:setattributevalue blk tag val)
        )
    )
)

;=========================================================================

(defun LM:effectivename ( obj )
    (vlax-get-property obj
        (if (vlax-property-available-p obj 'effectivename)
            'effectivename
            'name
        )
    )
)

;=========================================================================

(defun LM:assoc++ ( key lst / itm )
    (if (setq itm (assoc key lst))
        (subst (cons key (1+ (cdr itm))) itm lst)
        (cons  (cons key 1) lst)
    )
)

;=========================================================================

(defun CreateScript ()
  (setq file (open (strcat (getvar "dwgprefix") "CreateScript.scr") "W"))
  (write-line (strcat ".mview\tL\tOFF\tALL \nLAYOUT\tR\t" LaynName "\t" "-") file)
  (write-line (strcat "LAYOUT\tR\t" "-" "\t" PSize) file)
  (close file)
  (setq LaynName PSize)
  (crText (mapcar '+ '(150 2200) (list (car 1p) (cadr 1p))) 75 (strcat PrjName laynname))
)

;=========================================================================

(defun WriteScript ()
  
  (setq file (open (strcat (getvar "dwgprefix") "CreateScript.scr") "A"))
  (write-line (strcat "LAYOUT\tC\t" LaynName "\t" PSize "\tLAYOUT\tS\t" PSize "\tGoLast\tMspace\t-pan\t" y1p "\t" y2p "\tPspace") file)
  (close file)
  (setq LaynName PSize)
  (setq y2p y1p)
  (crText (mapcar '+ '(150 2200) (list (car 1p) (cadr 1p))) 75 (strcat PrjName laynname))
)

;=========================================================================

(defun WriteNextScript ()
  (setq file (open (strcat (getvar "dwgprefix") "CreateScript.scr") "A"))
  (write-line (strcat "LAYOUT\tC\t" LaynName "\t" PSize "\tLAYOUT\tS\t" PSize "\tGoLast\tMspace\t-pan\t" y1p "\t" y2p "\tPspace") file)
  (close file)
  (setq LaynName PSize)
  (setq y2p y1p)
  (crText (mapcar '+ '(150 2200) (list (car 1p) (cadr 1p))) 75 (strcat PrjName laynname))
)

;=========================================================================

(defun fixitoa ( #i #n / s ) (setq s (itoa #i))(while (&gt; #n (strlen s))(setq s (strcat "0" s))) s)

;=========================================================================

(defun LM:getvisibilitystate ( blk / vis )
    (if (setq vis (LM:getvisibilityparametername blk))
        (LM:getdynpropvalue blk vis)
    )
)

;=========================================================================

(defun LM:getvisibilityparametername ( blk / vis )  
    (if
        (and
            (vlax-property-available-p blk 'effectivename)
            (setq blk
                (vla-item
                    (vla-get-blocks (vla-get-document blk))
                    (vla-get-effectivename blk)
                )
            )
            (= :vlax-true (vla-get-isdynamicblock blk))
            (= :vlax-true (vla-get-hasextensiondictionary blk))
            (setq vis
                (vl-some
                   '(lambda ( pair )
                        (if
                            (and
                                (= 360 (car pair))
                                (= "BLOCKVISIBILITYPARAMETER" (cdr (assoc 0 (entget (cdr pair)))))
                            )
                            (cdr pair)
                        )
                    )
                    (dictsearch
                        (vlax-vla-object-&gt;ename (vla-getextensiondictionary blk))
                        "ACAD_ENHANCEDBLOCK"
                    )
                )
            )
        )
        (cdr (assoc 301 (entget vis)))
    )
)

;=========================================================================

(defun LM:getdynpropvalue ( blk prp )
    (setq prp (strcase prp))
    (vl-some '(lambda ( x ) (if (= prp (strcase (vla-get-propertyname x))) (vlax-get x 'value)))
        (vlax-invoke blk 'getdynamicblockproperties)
    )
)

;=========================================================================

(defun DelAllLayout ( / ll)
  (command "_.Layout" "Set" (car (getLayoutOrderList)))
  (while (/= 0 (setq ll (- (setq ll (length (getLayoutOrderList))) 1 )))
      (progn 
        (if (&gt; ll 0)
          (command "_-LAYOUT" "DELETE" (nth ll (getLayoutOrderList)))
        )
      );progn 
  );while
  (command "Model")
)

;=========================================================================

(defun getLayoutOrderList( / lst mklist mappend flatten)
    (defun mklist (x) (if (listp x) x (list x)))
    (defun mappend (fn lst)(apply 'append (mapcar fn lst))) 
    (defun flatten (expr)(mappend 'mklist expr))
    (vlax-for lay 
        (vla-get-layouts (vla-get-activedocument (vlax-get-acad-object)))
        (setq lst (cons (list (vla-get-taborder lay)(vla-get-name lay)) lst))
    )
    (cdr(flatten(mapcar 'cdr (vl-sort lst '(lambda (a b) (&lt; (car a)(car b)))))))
)

;=========================================================================

(defun c:GoLast (/ l)

  (if (and (&lt; 2
              (vla-get-count
                (setq l (vla-get-Layouts
                          (vla-get-ActiveDocument (vlax-get-acad-object))
                        )
                )
              )
           )
           (eq 0 (getvar 'TILEMODE))
      )
    (vla-put-taborder
      (vla-item l (getvar 'CTAB))
      (1- (vla-get-count l))
    )
    (princ "\n ** Command is not allowed in Model Space **")
  )
  (princ)
)

;=========================================================================

(defun C:LockAllVp ( / i oldlo oldcmde)
 (setq oldcmde (getvar "CMDECHO"))
 (setvar "CMDECHO" 0)
 (setq oldlo (getvar "CTAB"))
;cannot lock model
; (setvar "CTAB" "Model")
;all layouts
 (foreach i (layoutlist)
  (progn 
   (setvar "CTAB" i)
   (command "_-VPORTS" "_Lock" "_on" "_all" "")
   );progn 
 )
 (setvar "CTAB" oldlo)
 (setvar "CMDECHO" oldcmde)
 (princ "\nAll viewports locked.")
 (princ)
)

;=========================================================================

(defun crText ( ins hgt str / ent )
  (entmake 
    (list 
      '(000 . "TEXT")      
      '(100 . "AcDbText")
      '(7 .   "TEXT")
      '(8 .   "Defpoints")
      (cons 010 ins)      
      (cons 040 hgt)      
      (cons 001 str)      
    )
  )
)

;=========================================================================

  (defun *error* (msg)
    (if (not (wcmatch msg "quit/exit abort,function canceled"))
      (princ (strcat "\nError: " msg)) ; Display message for actual errors
    )
    (setvar "CMDECHO" 1) ; Ensure settings are reset
    (princ) ; Quiet exit
  )

;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
(princ
    (strcat
        "\n:: Version 1.1 | \\U+00A9 FT ::"
        "\n:: This Progam also works with Single Panel ::"
        "\n:: \"CRL\" to Create Layout ::"
    )
)
(princ)</pre>

<p>
	 
</p>
]]></description><guid isPermaLink="false">99137</guid><pubDate>Mon, 18 May 2026 04:05:09 +0000</pubDate></item><item><title>Dynamic block pipes and fittings on existing line like revit</title><link>https://www.cadtutor.net/forum/topic/99123-dynamic-block-pipes-and-fittings-on-existing-line-like-revit/</link><description><![CDATA[<p>
	Hello everyone, I need your help. I have a preset dynamic block for a pipe that I can stretch and adjust in size, along with several fittings like elbows, tees, reducers, etc. I want to know if there is a way, or a lisp, or any AutoCAD command, that I can use to automatically place these dynamic pipes and fittings on a previously drawn line or polyline routing, simply by selecting the routing so that AutoCAD can automatically position these fittings without me having to redraw them, matching and following the existing routing.
</p>
]]></description><guid isPermaLink="false">99123</guid><pubDate>Wed, 13 May 2026 17:08:02 +0000</pubDate></item><item><title>Batch convert dxf to dwg</title><link>https://www.cadtutor.net/forum/topic/78909-batch-convert-dxf-to-dwg/</link><description><![CDATA[<p>
	Hi, I'm trying the above for work so I'm on network, firewall etc. Can't really download much but lisp or script files I can use. Has someone done the above via a lisp or script. I've a few to do so don't want to open each one etc to make the change. Seems a relatively easy operation so I'm sure there's a fix. Thanks.
</p>
]]></description><guid isPermaLink="false">78909</guid><pubDate>Mon, 18 Dec 2023 13:55:53 +0000</pubDate></item><item><title>CONVERT TEXTS TO ATTRIBUTE BLOCK WORK FLOW USING TWO LISPS</title><link>https://www.cadtutor.net/forum/topic/99131-convert-texts-to-attribute-block-work-flow-using-two-lisps/</link><description><![CDATA[<p>
	The work flow makes the copying of the texts to attribute block so quick&gt;<br />
	Regards
</p>

<video controls class="ipsEmbeddedVideo" data-fileid="70317" data-video-embed>
	<source data-video-src="https://www.cadtutor.net/forum/uploads/monthly_2026_05/CONVERTTEXTSTOATTRIBUTEWORKFLOW-COMP.mp4.d8be772b813b076076fc2f4016d22a71.mp4" type="video/mp4">
	<a class="ipsAttachLink" href="//www.cadtutor.net/forum/applications/core/interface/file/attachment.php?id=70317&amp;key=112dfd07122d2fbd67c6e3508d28f5dc">CONVERT TEXTS TO ATTRIBUTE WORK FLOW-COMP.mp4</a>
</video><p>
<a class="ipsAttachLink" href="https://www.cadtutor.net/forum/applications/core/interface/file/attachment.php?id=70318&amp;key=41c0fa637f25f92a0af6a638f6479f9d" data-fileExt='LSP' data-fileid='70318' data-filekey='41c0fa637f25f92a0af6a638f6479f9d'>GTTB-BATCH-COPY ANY NUMBER OF TEXTS TO ATTRIB BLOCKS.LSP</a> 
<a class="ipsAttachLink" href="https://www.cadtutor.net/forum/applications/core/interface/file/attachment.php?id=70319&amp;key=45e377b0e52894ae6dc48e4fc092108e" data-fileExt='lsp' data-fileid='70319' data-filekey='45e377b0e52894ae6dc48e4fc092108e'>rec2txt-placing a specific object (like a .lsp</a> 
<a class="ipsAttachLink" href="https://www.cadtutor.net/forum/applications/core/interface/file/attachment.php?id=70320&amp;key=71e5e839bc6b9e8f57b53be7dfe6d6ca" data-fileExt='dwg' data-fileid='70320' data-filekey='71e5e839bc6b9e8f57b53be7dfe6d6ca'>H B2 FINISHS - ATT-2.dwg</a></p>]]></description><guid isPermaLink="false">99131</guid><pubDate>Sat, 16 May 2026 14:09:19 +0000</pubDate></item><item><title>I often experience this but don't know what to do.</title><link>https://www.cadtutor.net/forum/topic/99092-i-often-experience-this-but-dont-know-what-to-do/</link><description><![CDATA[<p>
	I'm using LISP to calculate the hatch area, but it keeps giving me errors, and it only works when I copy the code to a different file. Could you please take a look? Thank you.
</p>

<p>
	 
</p>
]]></description><guid isPermaLink="false">99092</guid><pubDate>Thu, 30 Apr 2026 09:50:32 +0000</pubDate></item><item><title>AutpLisp to Create X,Y Coordinates with Mleader</title><link>https://www.cadtutor.net/forum/topic/98285-autplisp-to-create-xy-coordinates-with-mleader/</link><description><![CDATA[<p>
	Hi all,
</p>

<p>
	I have a lisp which get the X &amp; Y coordinates with leader, text. But it would be very useful if the coordinates comes with MLEADER (Text/Arrow height - 2.5).
</p>

<p>
	Please help me out here anyone
</p>
]]></description><guid isPermaLink="false">98285</guid><pubDate>Sat, 14 Jun 2025 07:18:28 +0000</pubDate></item></channel></rss>
