Mercurial > hg > xemacs-beta
view lisp/efs/efs-vms.el @ 203:850242ba4a81 r20-3b28
Import from CVS: tag r20-3b28
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:02:21 +0200 |
parents | 9f59509498e1 |
children |
line wrap: on
line source
;; -*-Emacs-Lisp-*- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; File: efs-vms.el ;; Release: $efs release: 1.15 $ ;; Version: #Revision: 1.13 $ ;; RCS: ;; Description: VMS support for efs ;; Authors: Andy Norman, Joe Wells, Sandy Rutherford <sandy@itp.ethz.ch> ;; Modified: Sun Nov 27 18:44:59 1994 by sandy on gandalf ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; This file is part of efs. See efs.el for copyright ;;; (it's copylefted) and warrranty (there isn't one) information. (provide 'efs-vms) (require 'efs) (defconst efs-vms-version (concat (substring "$efs release: 1.15 $" 14 -2) "/" (substring "#Revision: 1.13 $" 11 -2))) ;;;; ------------------------------------------------------------ ;;;; VMS support. ;;;; ------------------------------------------------------------ ;;; efs has full support for VMS hosts, including tree dired support. It ;;; should be able to automatically recognize any VMS machine. However, if it ;;; fails to do this, you can use the command efs-add-vms-host. As well, ;;; you can set the variable efs-vms-host-regexp in your .emacs file. We ;;; would be grateful if you would report any failures to automatically ;;; recognize a VMS host as a bug. ;;; ;;; Filename Syntax: ;;; ;;; For ease of *implementation*, the user enters the VMS filename syntax in a ;;; UNIX-y way. For example: ;;; PUB$:[ANONYMOUS.SDSCPUB.NEXT]README.TXT;1 ;;; would be entered as: ;;; /PUB$$:/ANONYMOUS/SDSCPUB/NEXT/README.TXT;1 ;;; i.e. to log in as anonymous on ymir.claremont.edu and grab the file: ;;; [.CSV.POLICY]RULES.MEM ;;; you would type: ;;; C-x C-f /anonymous@ymir.claremont.edu:CSV/POLICY/RULES.MEM ;;; ;;; A legal VMS filename is of the form: FILE.TYPE;## ;;; where FILE can be up to 39 characters ;;; TYPE can be up to 39 characters ;;; ## is a version number (an integer between 1 and 32,767) ;;; Valid characters in FILE and TYPE are A-Z 0-9 _ - $ ;;; $ cannot begin a filename, and - cannot be used as the first or last ;;; character. ;;; ;;; Tips: ;;; 1. To access the latest version of file under VMS, you use the filename ;;; without the ";" and version number. You should always edit the latest ;;; version of a file. If you want to edit an earlier version, copy it to a ;;; new file first. This has nothing to do with efs, but is simply ;;; good VMS operating practice. Therefore, to edit FILE.TXT;3 (say 3 is ;;; latest version), do C-x C-f /ymir.claremont.edu:FILE.TXT. If you ;;; inadvertently do C-x C-f /ymir.claremont.edu:FILE.TXT;3, you will find ;;; that VMS will not allow you to save the file because it will refuse to ;;; overwrite FILE.TXT;3, but instead will want to create FILE.TXT;4, and ;;; attach the buffer to this file. To get out of this situation, M-x ;;; write-file /ymir.claremont.edu:FILE.TXT will attach the buffer to ;;; latest version of the file. For this reason, in tree dired "f" ;;; (dired-find-file), always loads the file sans version, whereas "v", ;;; (dired-view-file), always loads the explicit version number. The ;;; reasoning being that it reasonable to view old versions of a file, but ;;; not to edit them. ;;; 2. EMACS has a feature in which it does environment variable substitution ;;; in filenames. Therefore, to enter a $ in a filename, you must quote it ;;; by typing $$. There is a bug in EMACS, in that it neglects to quote the ;;; $'s in the default directory when it writes it in the minibuffer. You ;;; must edit the minibuffer to quote the $'s manually. Hopefully, this bug ;;; will be fixed in EMACS 19. If you use Sebastian Kremer's gmhist (V 4.26 ;;; or newer), you will not have this problem. ;; Because some VMS ftp servers convert filenames to lower case ;; we allow a-z in the filename regexp. (defconst efs-vms-filename-regexp "\\([_A-Za-z0-9$][-_A-Za-z0-9$]*\\)?\\.\\([-_A-Za-z0-9$]*\\);[0-9]+") ;; Regular expression to match for a valid VMS file name in Dired buffer. (defvar efs-vms-month-alist '(("JAN" . 1) ("FEB". 2) ("MAR" . 3) ("APR" . 4) ("MAY" . 5) ("JUN" . 6) ("JUL" . 7) ("AUG" . 8) ("SEP" . 9) ("OCT" . 10) ("NOV" . 11) ("DEC" . 12))) (defvar efs-vms-date-regexp (concat "\\([0-3]?[0-9]\\)-" "\\(JAN\\|FEB\\|MAR\\|APR\\|MAY\\|JUN\\|" "JUL\\|AUG\\|SEP\\|OCT\\|NOV\\|DEC\\)-" "\\([0-9][0-9][0-9]?[0-9]?\\) \\(\\([0-5][0-9]\\):\\([0-5][0-9]\\)" "\\(:[0-5][0-9]\\)?\\)? ")) ;;; The following two functions are entry points to this file. ;;; They are defined as efs-autoloads in efs.el (efs-defun efs-fix-path vms (path &optional reverse) ;; Convert PATH from UNIX-ish to VMS. ;; If REVERSE given then convert from VMS to UNIX-ish. (efs-save-match-data (if reverse (if (string-match "^\\([^:]+:\\)?\\(\\[[^]]+\\]\\)?\\([^][]*\\)$" path) (let (drive dir file) (if (match-beginning 1) (setq drive (substring path (match-beginning 1) (match-end 1)))) (if (match-beginning 2) (setq dir (substring path (match-beginning 2) (match-end 2)))) (if (match-beginning 3) (setq file (substring path (match-beginning 3) (match-end 3)))) (and dir (setq dir (apply (function concat) (mapcar (function (lambda (char) (if (= char ?.) (vector ?/) (vector char)))) (substring dir 1 -1))))) (concat (and drive (concat "/" drive "/")) dir (and dir "/") file)) (error "path %s didn't match" path)) (let (drive dir file) (if (string-match "^/[^:/]+:/" path) (setq drive (substring path 1 (1- (match-end 0))) path (substring path (1- (match-end 0))))) (setq dir (file-name-directory path) file (efs-internal-file-name-nondirectory path)) (if dir (let ((len (1- (length dir))) (n 0)) (if (<= len 0) (setq dir nil) (while (<= n len) (and (char-equal (aref dir n) ?/) (cond ((zerop n) (aset dir n ?\[)) ((= n len) (aset dir n ?\])) (t (aset dir n ?.)))) (setq n (1+ n)))))) (concat drive dir file))))) ;; It is important that this function barf for directories for which we know ;; that we cannot possibly get a directory listing, such as "/" and "/DEV:/". ;; This is because it saves an unnecessary FTP error, or possibly the listing ;; might succeed, but give erroneous info. This last case is particularly ;; likely for OS's (like MTS) for which we need to use a wildcard in order ;; to list a directory. (efs-defun efs-fix-dir-path vms (dir-path) ;; Convert path from UNIX-ish to VMS ready for a DIRectory listing. ;; Should there be entries for .. -> [-] and . -> [] below. Don't ;; think so, because expand-filename should have already short-circuited ;; them. (cond ((string-equal dir-path "/") (error "Cannot get listing for fictitious \"/\" directory.")) ((string-match "^/[-A-Z0-9_$]+:/$" dir-path) (error "Cannot get listing for device.")) ((efs-fix-path 'vms dir-path)))) ;; These parsing functions are as general as possible because the syntax ;; of ftp listings from VMS hosts is a bit erratic. What saves us is that ;; the VMS filename syntax is so rigid. If they bomb on a listing in the ;; standard VMS Multinet format, then this is a bug. If they bomb on a listing ;; from vms.weird.net, then too bad. (defmacro efs-parse-vms-filename () "Extract the next filename from a VMS dired-like listing." (` (if (re-search-forward efs-vms-filename-regexp nil t) (buffer-substring (match-beginning 0) (match-end 0))))) (defun efs-parse-vms-listing () ;; Parse the current buffer which is assumed to be a VMS DIR ;; listing (either a short (NLIST) or long listing). ;; Assumes that point is at the beginning of the buffer. (let ((tbl (efs-make-hashtable)) file) (goto-char (point-min)) (efs-save-match-data (while (setq file (efs-parse-vms-filename)) (if (string-match "\\.\\(DIR\\|dir\\);[0-9]+" file) ;; deal with directories (efs-put-hash-entry (substring file 0 (match-beginning 0)) '(t) tbl) (efs-put-hash-entry file '(nil) tbl) (if (string-match ";[0-9]+$" file) ; deal with extension ;; sans extension (efs-put-hash-entry (substring file 0 (match-beginning 0)) '(nil) tbl))) (forward-line 1)) ;; Would like to look for a "Total" line, or a "Directory" line to ;; make sure that the listing isn't complete garbage before putting ;; in "." and "..", but we can't even count on all VAX's giving us ;; either of these. (efs-put-hash-entry "." '(t) tbl) (efs-put-hash-entry ".." '(t) tbl)) tbl)) (efs-defun efs-parse-listing vms (host user dir path &optional switches) ;; Parse the current buffer which is assumed to be a VMS FTP dir ;; format, and return a hashtable as the result. SWITCHES are never used, ;; but they must be specified in the argument list for compatibility ;; with the unix version of this function. ;; HOST = remote host name ;; USER = user name ;; DIR = directory in as a full remote path ;; PATH = directory in full efs path syntax ;; SWITCHES = ls switches (not relevant here) (goto-char (point-min)) (efs-save-match-data ;; check for a DIR/FULL monstrosity (if (search-forward "\nSize:" nil t) (progn (efs-add-listing-type 'vms:full host user) ;; This will cause the buffer to be refilled with an NLIST (let ((efs-ls-uncache t)) (efs-ls path nil (format "Relisting %s" (efs-relativize-filename path)) t)) (goto-char (point-min)) (efs-parse-vms-listing)) (efs-parse-vms-listing)))) ;;;; Sorting of listings (efs-defun efs-t-converter vms (&optional regexp reverse) (if regexp nil (goto-char (point-min)) (efs-save-match-data (if (re-search-forward efs-vms-filename-regexp nil t) (let (list-start start end list) (beginning-of-line) (setq list-start (point)) (while (and (looking-at efs-vms-filename-regexp) (progn (setq start (point)) (goto-char (match-end 0)) (forward-line (if (eolp) 2 1)) (setq end (point)) (goto-char (match-end 0)) (re-search-forward efs-vms-date-regexp nil t))) (setq list (cons (cons (nconc (list (string-to-int (buffer-substring (match-beginning 3) (match-end 3))) ; year (cdr (assoc (buffer-substring (match-beginning 2) (match-end 2)) efs-vms-month-alist)) ; month (string-to-int (buffer-substring (match-beginning 1) (match-end 1)))) ;day (if (match-beginning 4) (list (string-to-int (buffer-substring (match-beginning 5) (match-end 5))) ; hour (string-to-int (buffer-substring (match-beginning 6) (match-end 6))) ; minute (if (match-beginning 7) (string-to-int (buffer-substring (1+ (match-beginning 7)) (match-end 7))) ; seconds 0)) (list 0 0 0))) (buffer-substring start end)) list)) (goto-char end)) (if list (progn (setq list (mapcar 'cdr (sort list 'efs-vms-t-converter-sort-pred))) (if reverse (setq list (nreverse list))) (delete-region list-start (point)) (apply 'insert list))) t))))) (defun efs-vms-t-converter-sort-pred (elt1 elt2) (let* ((data1 (car elt1)) (data2 (car elt2)) (year1 (car data1)) (year2 (car data2)) (month1 (nth 1 data1)) (month2 (nth 1 data2)) (day1 (nth 2 data1)) (day2 (nth 2 data2)) (hour1 (nth 3 data1)) (hour2 (nth 3 data2)) (minute1 (nth 4 data1)) (minute2 (nth 4 data2))) (or (> year1 year2) (and (= year1 year2) (or (> month1 month2) (and (= month1 month2) (or (> day1 day2) (and (= day1 day2) (or (> hour1 hour2) (and (= hour1 hour2) (or (> minute1 minute2) (and (= minute1 minute2) (or (> (nth 5 data1) (nth 5 data2))) )))))))))))) (efs-defun efs-X-converter vms (&optional regexp reverse) ;; Sorts by extension (if regexp nil (goto-char (point-min)) (efs-save-match-data (if (re-search-forward efs-vms-filename-regexp nil t) (let (list-start start list) (beginning-of-line) (setq list-start (point)) (while (looking-at efs-vms-filename-regexp) (setq start (point)) (goto-char (match-end 0)) (forward-line (if (eolp) 2 1)) (setq list (cons (cons (buffer-substring (match-beginning 2) (match-end 2)) (buffer-substring start (point))) list))) (setq list (mapcar 'cdr (sort list (if reverse (function (lambda (x y) (string< (car y) (car x)))) (function (lambda (x y) (string< (car x) (car y)))))))) (delete-region list-start (point)) (apply 'insert list) t))))) ;; This version only deletes file entries which have ;; explicit version numbers, because that is all VMS allows. (efs-defun efs-delete-file-entry vms (path &optional dir-p) (let ((ignore-case (memq 'vms efs-case-insensitive-host-types))) (if dir-p (let ((path (file-name-as-directory path)) files) (efs-del-hash-entry path efs-files-hashtable ignore-case) (setq path (directory-file-name path) files (efs-get-hash-entry (file-name-directory path) efs-files-hashtable ignore-case)) (if files (efs-del-hash-entry (efs-get-file-part path) files ignore-case))) (efs-save-match-data (let ((file (efs-get-file-part path))) (if (string-match ";[0-9]+$" file) ;; In VMS you can't delete a file without an explicit ;; version number, or wild-card (e.g. FOO;*) ;; For now, we give up on wildcards. (let ((files (efs-get-hash-entry (file-name-directory path) efs-files-hashtable ignore-case))) (if files (let ((root (substring file 0 (match-beginning 0))) (completion-ignore-case ignore-case) (len (match-beginning 0))) (efs-del-hash-entry file files ignore-case) ;; Now we need to check if there are any ;; versions left. If not, then delete the ;; root entry. (or (all-completions root files (function (lambda (sym) (string-match ";[0-9]+$" (symbol-name sym) len)))) (efs-del-hash-entry root files ignore-case))))))))) (efs-del-from-ls-cache path t ignore-case))) (efs-defun efs-add-file-entry vms (path dir-p size owner &optional modes nlinks mdtm) ;; The vms version of this function needs to keep track ;; of vms's file versions. (let ((ignore-case (memq 'vms efs-case-insensitive-host-types)) (ent (let ((dir-p (null (null dir-p)))) (if mdtm (list dir-p size owner nil nil mdtm) (list dir-p size owner))))) (if dir-p (let* ((path (directory-file-name path)) (files (efs-get-hash-entry (file-name-directory path) efs-files-hashtable ignore-case))) (if files (efs-put-hash-entry (efs-get-file-part path) ent files ignore-case))) (let ((files (efs-get-hash-entry (file-name-directory path) efs-files-hashtable ignore-case))) (if files (let ((file (efs-get-file-part path))) (efs-save-match-data ;; In VMS files must have an extension. If there isn't ;; one, it will be added. (or (string-match "^[^;]*\\." file) (if (string-match ";" file) (setq file (concat (substring file 0 (match-beginning 0)) ".;" (substring file (match-end 0)))) (setq file (concat file ".")))) (if (string-match ";[0-9]+$" file) (efs-put-hash-entry (substring file 0 (match-beginning 0)) ent files ignore-case) ;; Need to figure out what version of the file ;; is being added. (let* ((completion-ignore-case ignore-case) (len (length file)) (versions (all-completions file files (function (lambda (sym) (string-match ";[0-9]+$" (symbol-name sym) len))))) (N (1+ len)) (max (apply 'max (cons 0 (mapcar (function (lambda (x) (string-to-int (substring x N)))) versions))))) ;; No need to worry about case here. (efs-put-hash-entry (concat file ";" (int-to-string (1+ max))) ent files)))) (efs-put-hash-entry file ent files ignore-case))))) (efs-del-from-ls-cache path t ignore-case))) (efs-defun efs-really-file-p vms (file ent) ;; Returns whether the hash entry FILE with entry ENT is a real file. (or (car ent) ; file-directory-p (efs-save-match-data (string-match ";" file)))) (efs-defun efs-internal-file-name-as-directory vms (name) (efs-save-match-data (if (string-match "\\.\\(DIR\\|dir\\)\\(;[0-9]+\\)?$" name) (setq name (substring name 0 (match-beginning 0)))) (let (file-name-handler-alist) (file-name-as-directory name)))) (efs-defun efs-remote-directory-file-name vms (dir) ;; Returns the VMS filename in unix directory syntax for directory DIR. ;; This is something like /FM/SANDY/FOOBAR.DIR;1 (efs-save-match-data (setq dir (directory-file-name dir)) (concat dir (if (string-match "[a-z]" (nth 2 (efs-ftp-path dir))) ".dir;1" ".DIR;1")))) (efs-defun efs-allow-child-lookup vms (host user dir file) ;; Returns t if FILE in directory DIR could possibly be a subdir ;; according to its file-name syntax, and therefore a child listing should ;; be attempted. ;; Subdirs in VMS can't have an extension (other than .DIR, which we ;; have truncated). (not (or (string-match "\\." file) (and (boundp 'dired-local-variables-file) (stringp dired-local-variables-file) (string-equal dired-local-variables-file file))))) ;;; Tree dired support: ;; For this code I have borrowed liberally from Sebastian Kremer's ;; dired-vms.el ;; These regexps must be anchored to beginning of line. ;; Beware that the ftpd may put the device in front of the filename. (defconst efs-dired-vms-re-exe "^. [^ \t.]+\\.\\(EXE\\|exe\\)[; ]") (or (assq 'vms efs-dired-re-exe-alist) (setq efs-dired-re-exe-alist (cons (cons 'vms efs-dired-vms-re-exe) efs-dired-re-exe-alist))) (defconst efs-dired-vms-re-dir "^. [^ \t.]+\\.\\(DIR\\|dir\\)[; ]") (or (assq 'vms efs-dired-re-dir-alist) (setq efs-dired-re-dir-alist (cons (cons 'vms efs-dired-vms-re-dir) efs-dired-re-dir-alist))) (efs-defun efs-dired-insert-headerline vms (dir) ;; VMS inserts a headerline. I would prefer the headerline ;; to be in efs format. This version tries to ;; be careful, because we can't count on a headerline ;; over ftp, and we wouldn't want to delete anything ;; important. (save-excursion (if (looking-at "^ \\(list \\)?wildcard ") (forward-line 1)) ;; This is really aggressive. Too aggressive? (let ((start (point))) (skip-chars-forward " \t\n") (if (looking-at efs-vms-filename-regexp) (beginning-of-line) (forward-line 1) (skip-chars-forward " \t\n") (beginning-of-line)) (delete-region start (point))) (insert " \n")) (efs-real-dired-insert-headerline dir)) (efs-defun efs-dired-fixup-listing vms (file path &optional switches wildcard) ;; Some vms machines list the entire path. Scrape this off. (setq path (efs-fix-path 'vms ;; Need the file-name-directory, in case of widcards. ;; Note that path is a `local' path rel. the remote host. ;; Lose on wildcards in parent dirs. Fix if somebody complains. (let (file-name-handler-alist) (file-name-directory path)))) ;; Some machines put a Node name down too. (let ((regexp (concat "^\\([_A-Za-z0-9][-_A-Za-z0-9]*\\$\\)?" (regexp-quote path)))) (goto-char (point-min)) (while (re-search-forward regexp nil t) (delete-region (match-beginning 0) (match-end 0)))) ;; Now need to deal with continuation lines. (goto-char (point-min)) (let (col start end) (while (re-search-forward ";[0-9]+[ \t]*\\(\n[ \t]+\\)[^; \t\n]+[^\n;]*\n" nil t) (setq start (match-beginning 1) end (match-end 1)) ;; guess at the column dimensions (or col (save-excursion (goto-char (point-min)) (if (re-search-forward (concat efs-vms-filename-regexp "[ \t]+[^ \t\n\r]") nil t) (setq col (- (goto-char (match-end 0)) (progn (beginning-of-line) (point)) 1)) (setq col 0)))) ;; join cont. lines. (delete-region start end) (goto-char start) (insert-char ? (max (- col (current-column)) 2)))) ;; Some vms dir listings put a triple null line before the total line. (goto-char (point-min)) (skip-chars-forward "\n") (if (search-forward "\n\n\n" nil t) (delete-char -1))) (efs-defun efs-dired-manual-move-to-filename vms (&optional raise-error bol eol) ;; In dired, move to first char of filename on this line. ;; Returns position (point) or nil if no filename on this line. ;; This is the VMS version. (or eol (setq eol (save-excursion (skip-chars-forward "^\r\n") (point)))) (let (case-fold-search) (if bol (goto-char bol) (skip-chars-backward "^\n\r")) (if (re-search-forward efs-vms-filename-regexp eol t) (goto-char (match-beginning 0)) (and raise-error (error "No file on this line"))))) (efs-defun efs-dired-manual-move-to-end-of-filename vms (&optional no-error bol eol) ;; Assumes point is at beginning of filename. ;; So, it should be called only after (dired-move-to-filename t). ;; case-fold-search must be nil, at least for VMS. ;; On failure, signals an error or returns nil. ;; This is the VMS version. (let ((opoint (point))) (and selective-display (null no-error) (eq (char-after (1- (or bol (save-excursion (skip-chars-backward "^\r\n") (point))))) ?\r) ;; File is hidden or omitted. (cond ((dired-subdir-hidden-p (dired-current-directory)) (error (substitute-command-keys "File line is hidden. Type \\[dired-hide-subdir] to unhide."))) ((error (substitute-command-keys "File line is omitted. Type \\[dired-omit-toggle] to un-omit." ))))) (skip-chars-forward "-_A-Za-z0-9$.;") (if (or (= opoint (point)) (not (memq (following-char) '(?\ ?\t ?\n ?\r)))) (if no-error nil (error "No file on this line")) (point)))) (efs-defun efs-dired-ls-trim vms () (goto-char (point-min)) (let ((case-fold-search nil)) (re-search-forward efs-vms-filename-regexp)) (beginning-of-line) (delete-region (point-min) (point)) (forward-line 1) (delete-region (point) (point-max))) (efs-defun efs-internal-file-name-sans-versions vms (name &optional keep-backup-version) (efs-save-match-data (if (string-match ";[0-9]+$" name) (substring name 0 (match-beginning 0)) name))) (efs-defun efs-dired-collect-file-versions vms () ;; If it looks like file FN has versions, return a list of the versions. ;; That is a list of strings which are file names. ;; The caller may want to flag some of these files for deletion. (let ((completion-ignore-case (memq 'vms efs-case-insensitive-host-types)) result) (dired-map-dired-file-lines (function (lambda (fn) (if (string-match ";[0-9]+$" fn) (let* ((base-fn (substring fn 0 (match-beginning 0))) (base-version (file-name-nondirectory (substring fn 0 (1+ (match-beginning 0))))) (bv-length (length base-version)) (possibilities (and (null (assoc base-fn result)) (file-name-all-completions base-version (file-name-directory fn))))) (if possibilities (setq result (cons (cons base-fn ;; code this explicitly ;; using backup-extract-version has a ;; lot of function-call overhead. (mapcar (function (lambda (fn) (string-to-int (substring fn bv-length)))) possibilities)) result)))))))) result)) (efs-defun efs-dired-flag-backup-files vms (&optional unflag-p) (interactive "P") (let ((dired-kept-versions 1) (kept-old-versions 0) marker msg) (if unflag-p (setq marker ?\040 msg "Unflagging old versions") (setq marker dired-del-marker msg "Purging old versions")) (dired-clean-directory 1 marker msg))) (efs-defun efs-internal-diff-latest-backup-file vms (fn) ;; For FILE;#, returns the filename FILE;N, where N ;; is the largest number less than #, for which this file exists. ;; Returns nil if none found. (efs-save-match-data (and (string-match ";[0-9]+$" fn) (let ((base (substring fn 0 (1+ (match-beginning 0)))) (num (1- (string-to-int (substring fn (1+ (match-beginning 0)))))) found file) (while (and (setq found (> num 0)) (not (file-exists-p (setq file (concat base (int-to-string num)))))) (setq num (1- num))) (and found file))))) ;;;;-------------------------------------------------------------- ;;;; Support for VMS DIR/FULL listings. (listing type vms:full) ;;;;-------------------------------------------------------------- (efs-defun efs-parse-listing vms:full (host user dir path &optional switches) ;; Parse the current buffer which is assumed to be a VMS FTP dir ;; format, and return a hashtable as the result. SWITCHES are never used, ;; but they must be specified in the argument list for compatibility ;; with the unix version of this function. ;; HOST = remote host name ;; USER = user name ;; DIR = directory in as a full remote path ;; PATH = directory in full efs path syntax ;; SWITCHES = ls switches (not relevant here) (goto-char (point-min)) (efs-save-match-data (efs-parse-vms-listing))) ;;; Tree Dired (or (assq 'vms:full efs-dired-re-exe-alist) (setq efs-dired-re-exe-alist (cons (cons 'vms:full efs-dired-vms-re-exe) efs-dired-re-exe-alist))) (or (assq 'vms:full efs-dired-re-dir-alist) (setq efs-dired-re-dir-alist (cons (cons 'vms:full efs-dired-vms-re-dir) efs-dired-re-dir-alist))) (efs-defun efs-dired-insert-headerline vms:full (dir) ;; Insert a blank line for aesthetics. (insert " \n") (forward-char -2) (efs-real-dired-insert-headerline dir)) (efs-defun efs-dired-manual-move-to-filename vms:full (&optional raise-error bol eol) (let ((efs-dired-listing-type 'vms)) (efs-dired-manual-move-to-filename raise-error bol eol))) (efs-defun efs-dired-manual-move-to-end-of-filename vms:full (&optional no-error bol eol) (let ((efs-dired-listing-type 'vms)) (efs-dired-manual-move-to-end-of-filename no-error bol eol))) ;;; end of efs-vms.el