Jump to content

Stopping a recursive function prematurely


plackowski
 Share

Recommended Posts

I'm using Lee Mac's great DirectoryFiles routine (copied below) to get a list of files in a given root directory.

 

I'd like to stop the recursion prematurely and return nil if there are over 100 files in the list, but the recursion, mapcars, and lambdas are a bit above my head. Any help would be appreciated!

 

;; Directory Files  -  Lee Mac
;; Retrieves all files of a specified filetype residing in a directory (and subdirectories)
;; dir - [str] Root directory for which to return filenames
;; typ - [str] Optional filetype filter (DOS pattern)
;; sub - [bol] If T, subdirectories of the root directory are included
;; Returns: [lst] List of files matching the filetype criteria, else nil if none are found

(defun LM:directoryfiles ( dir typ sub )
    (setq dir (vl-string-right-trim "\\" (vl-string-translate "/" "\\" dir)))
    (append (mapcar '(lambda ( x ) (strcat dir "\\" x)) (vl-directory-files dir typ 1))
        (if sub
            (apply 'append
                (mapcar
                   '(lambda ( x )
                        (if (not (wcmatch x "`.,`.`."))
                            (LM:directoryfiles (strcat dir "\\" x) typ sub)
                        )
                    )
                    (vl-directory-files dir nil -1)
                )
            )
        )
    )
)

 

Link to comment
Share on other sites

;; Directory Files  -  Lee Mac
;; Retrieves all files of a specified filetype residing in a directory (and subdirectories)
;; dir - [str] Root directory for which to return filenames
;; typ - [str] Optional filetype filter (DOS pattern)
;; sub - [bol] If T, subdirectories of the root directory are included
;; Returns: [lst] List of files matching the filetype criteria, else nil if none are found
;; Mod. by M.R. for special purposes...

(defun LM:directoryfiles ( dir typ sub )
    (setq dir (vl-string-right-trim "\\" (vl-string-translate "/" "\\" dir)))
    (vl-some '(lambda ( x ) (if (<= (setq k (1+ k)) n) (progn (setq l (append l (list (strcat dir "\\" x)))) nil) t)) (vl-directory-files dir typ 1))
    (if (and sub (<= k n))
        (mapcar
           '(lambda ( x )
                (if (not (wcmatch x "`.,`.`."))
                    (LM:directoryfiles (strcat dir "\\" x) typ sub)
                )
            )
            (vl-directory-files dir nil -1)
        )
    )
)

;; Number of files to list - M.R.
(defun listfiles ( n dir typ sub / k l )
  (setq k 0)
  (LM:directoryfiles dir typ sub)
  l
)

(setq *l* (listfiles 100 "C:\\" "*.dwg" t)) ;;; *l* is global, so you nil it after you finish with your job...
;;; (length *l*) => 100 or less

HTH., M.R.

Edited by marko_ribar
Link to comment
Share on other sites

Both Doslib and Acet have commands and are  line entries

 

"Returns the list of files, which match the mask patterns (can contain wildcards)"

 

(setq dwgs (acet-file-dir  "*.dwg" 32 "d:\\acadtemp")) ; note 32 is archive
 

Link to comment
Share on other sites

Unfortunately I don't think either of these methods will solve my problem. To clarify, my intention is to stop the function before it finishes. I'm letting the user supply the path, but if the user accidentally chooses one of our main networks as the path, autoCAD will freeze up as it tries to process all the subdirectories. This is what I'm trying to avoid.

Link to comment
Share on other sites

3 minutes ago, plackowski said:

Unfortunately I don't think either of these methods will solve my problem. To clarify, my intention is to stop the function before it finishes. I'm letting the user supply the path, but if the user accidentally chooses one of our main networks as the path, autoCAD will freeze up as it tries to process all the subdirectories. This is what I'm trying to avoid.

 

I think you haven't analyzed my proposal well... You stated that you need to stop search after routine collects up to 100 files... This is exactly what my suggestion does and if and when that limit is reached, recursions and routine finishes... The problem is that when you specify some of root folders it will search sub folders and if there are many empty, it may continue until all processed - you can't avoid search if limit is not reached... Otherwise - if you specify 1 file and direct folder where there is more than 1 file - it will finish in a blink of an eye...

So what is that you exactly want : routine that performs ultra fast ( that's not possible ), or routine that does a job that's needed, but at a cost of time consumption... Either way you should consider supplying correct folder path in advance at the very start of process...

Link to comment
Share on other sites

2 hours ago, plackowski said:

Unfortunately I don't think either of these methods will solve my problem. To clarify, my intention is to stop the function before it finishes. I'm letting the user supply the path, but if the user accidentally chooses one of our main networks as the path, autoCAD will freeze up as it tries to process all the subdirectories. This is what I'm trying to avoid.

Why not check the input IE:

(setq pth "R:\\")
(if (wcmatch pth "@:\\")
  (alert "You picked the root of a drive!")
  ;; Else process
)

 

Link to comment
Share on other sites

Sorry marko_ribar, I didn't have time to fully review your code this morning, and I misunderstood its approach. I managed to get you're code working and it does do what I asked, but unfortunately you're also correct in that it still takes too long to cancel the operation. What if the limit wasn't on the number of files on the list, but instead on the number of recursions? Perhaps if I could stop it after calling the function maybe 30 times? The other problem I've encountered is I can't distinguish between a nil because it couldn't find any files and a nil because it hit the cap.

 

ronjonp, your solution also works, but I'm concerned it may not be restrictive enough. There are plenty of non-root paths that could cause a hang-up.

Link to comment
Share on other sites

For us oldies shell dir *. >dirlst /b /s then read how many lines in dirlst. so if its like 100's don't do.

 

My D Drive has  10300+ Directories if ran on C would be way more. Could just do a read line max 30 if reached (alert "To many directories")

 

Note the dir check is not fast but compared to wading through a drive may be worthwhile.

 

 

Edited by BIGAL
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...