;; cached prefix version (define *completion-check-executable* #f) (define *cache-alist* '()) (define (strings-with-prefix strings prefix) (let ((plen (string-length prefix))) (filter (lambda (s) (and (>= (string-length s) plen) (string=? (substring s 0 plen) prefix))) strings))) (define (check-cache-for-prefix prefix) (let ((p (assoc prefix *cache-alist*))) (if p (cdr p) (let loop ((nprefix prefix)) (if (string=? nprefix "") #f (let* ((nprefix (substring prefix 0 (- (string-length nprefix) 1))) (p (assoc nprefix *cache-alist*))) (if p (strings-with-prefix (cdr p) prefix) (loop nprefix)))))))) (define (has-prefix prefix s) (let ((pl (string-length prefix))) (and (>= (string-length s) (string-length prefix)) (string=? (substring s 0 pl) prefix)))) (define (add-to-cache prefix list) (let ((prefixes (strings-with-prefix (map car *cache-alist*) prefix))) (receive (longer-ones others) (partition (lambda (p) (has-prefix prefix (car p))) *cache-alist*) (set! *cache-alist* (cons (cons prefix (append list (append-map cdr longer-ones))) others))))) (define (executables-in-path/prefix prefix) (let ((maybe-result (check-cache-for-prefix prefix))) (or maybe-result (let ((result (append-map! (lambda (dir) (dir-executables/prefix dir prefix)) (thread-fluid exec-path-list)))) (add-to-cache prefix result) result)))) (define (dir-executables/prefix dir prefix) (if (file-readable? dir) (map file-name-nondirectory (let ((files (glob (string-append dir "/" prefix "*")))) (if *completion-check-executable* (filter executable? files) files))) '())) ;; caching version (define *cache* #f) (define (executables-in-path) (or *cache* (begin (set! *cache* (executables-in-path-list (thread-fluid exec-path-list))) *cache*))) (define (executables-in-path-list path-list) (append-map! dir-executables path-list)) (define (dir-executables dir) (if (file-readable? dir) (map file-name-nondirectory (filter executable? (glob (string-append dir "/*")))) '())) (define (executable? name) ;; TODO maybe check if executable by this user (with-errno-handler ((errno packet) (else #f)) (let ((info (file-info name))) (and (file-info-executable? info) (file-info-regular? info)))))