diff lisp/efs/efs-mvs.el @ 98:0d2f883870bc r20-1b1

Import from CVS: tag r20-1b1
author cvs
date Mon, 13 Aug 2007 09:13:56 +0200
parents 8fc7fe29b841
children 7e54bd776075 9f59509498e1
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/efs/efs-mvs.el	Mon Aug 13 09:13:56 2007 +0200
@@ -0,0 +1,361 @@
+;; -*-Emacs-Lisp-*-
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; File:         efs-mvs.el
+;; Release:      $efs release: 1.15 $
+;; Version:      $Revision: 1.1 $
+;; RCS:          
+;; Description:  MVS support for efs
+;; Author:       Sandy Rutherford <sandy@math.ubc.ca, sandy@itp.ethz.ch>
+;; Created:      Sat Nov 14 02:04:54 1992
+;; Modified:     Sun Nov 27 18:37:54 1994 by sandy on gandalf
+;; Language:     Emacs-Lisp
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;; This file is part of efs. See efs.el for copyright
+;;; (it's copylefted) and warrranty (there isn't one) information.
+
+;;; --------------------------------------------------------
+;;; MVS support
+;;; --------------------------------------------------------
+
+(provide 'efs-mvs)
+(require 'efs)
+
+(defconst efs-mvs-version
+  (concat (substring "$efs release: 1.15 $" 14 -2)
+	  "/"
+	  (substring "$Revision: 1.1 $" 11 -2)))
+
+;; What's the MVS character set for valid partitioned data sets?
+;; I'll guess [-A-Z0-9_$+]
+
+;; The top level directory in MVS contains partitioned data sets.
+;; We will view these as directories. The data sets within each
+;; partitioned data set will be viewed as files.
+;;
+;; In MVS an entry for a "sub-dir" may have the same name as a plain
+;; file.  This is impossible in unix, so we retain the "dots" at the
+;; end of subdir names, to distinuguish.
+;; i.e. FOO.BAR --> /FOO./BAR
+
+(efs-defun efs-send-pwd mvs (host user &optional xpwd)
+  ;; Broken quoting for PWD output on some MVS servers.
+  (let* ((result (efs-send-cmd host user '(pwd) "Getting EXPLORER PWD"))
+	 (line (nth 1 result))
+	 dir)
+    (and (car result)
+	 (efs-save-match-data
+	   (and (string-match " \"'?\\([0-9A-Z]+\\)'?\"" line)
+		(setq dir (substring line (match-beginning 1)
+				     (match-end 1))))))
+    (cons dir line)))
+ 
+(efs-defun efs-fix-path mvs (path &optional reverse)
+  ;; Convert PATH from UNIX-ish to MVS.
+  (efs-save-match-data
+    (if reverse
+	(let ((start 0)
+	      (res "/"))
+	  ;; MVS has only files, some of which are partitioned
+	  ;; into smaller files (partitioned data sets). We will
+	  ;; assume that path starts with a partitioned dataset.
+	  (while (string-match "\\." path)
+	    ;; grab the dot too, because in mvs prefixes and plain
+	    ;; files can have the same name.
+	    (setq res (concat res (substring path start (match-end 0)) "/")
+		  start (match-end 0)))
+	  (concat res (substring path start)))
+      (let ((start 1)
+	    res)
+	(while (string-match "/" path start)
+	  (setq res (concat res (substring path start (match-beginning 0)))
+		start (match-end 0)))
+	(concat res (substring path start))))))
+		
+(efs-defun efs-fix-dir-path mvs (dir-path)
+  ;; Convert path from UNIX-ish to MVS for a DIR listing.
+  (cond
+   ((string-equal "/" dir-path)
+   " ")
+   (t (concat (efs-fix-path 'mvs dir-path) "*"))))
+
+(efs-defun efs-allow-child-lookup mvs (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.
+  ;; MVS file system is flat. Only partitioned data sets are "subdirs".
+  (efs-save-match-data
+    (string-match "\\.$" file)))
+
+(efs-defun efs-parse-listing mvs (host user dir path &optional switches)
+  ;; Guesses the type of mvs listings.
+  (efs-save-match-data
+    (goto-char (point-min))
+    (cond
+     ((looking-at "Volume ")
+      (efs-add-listing-type 'mvs:tcp  host user)
+      (efs-parse-listing 'mvs:tcp host user dir path switches))
+
+     ((looking-at "[-A-Z0-9_$.+]+ ")
+      (efs-add-listing-type 'mvs:nih host user)
+      (efs-parse-listing 'mvs:nih host user dir path switches))
+     
+     (t
+      ;; Since MVS works on a template system, return an empty hashtable.
+      (let ((tbl (efs-make-hashtable)))
+	(efs-put-hash-entry "." '(t) tbl)
+	(efs-put-hash-entry ".." '(t) tbl)
+	tbl)))))
+
+(efs-defun efs-ls-dumb-check mvs (line host file path lsargs msg noparse
+				       noerror nowait cont)
+  ;; Because of the template structure of the MVS file system, empty
+  ;; directories are the same as non-existent.  It's better for us to treat
+  ;; them as empty.
+  (and (string-match "^550 " line)
+       (let ((parse (or (null noparse) (eq noparse 'parse)
+			(efs-parsable-switches-p lsargs t))))
+	 (efs-add-to-ls-cache file lsargs "\n" parse)
+	 (if parse
+	     (efs-set-files file (let ((tbl (efs-make-hashtable)))
+				   (efs-put-hash-entry "." '(t) tbl)
+				   (efs-put-hash-entry ".." '(t) tbl)
+				   tbl)))
+	 (if nowait
+	     (progn
+	       (if cont
+		   (efs-call-cont cont "\n"))
+	       t)
+	   (if cont
+	       (efs-call-cont cont "\n"))
+	   "\n"))))
+
+;;;; ----------------------------------------------------
+;;;; Support for the NIH FTP server.
+;;;; ----------------------------------------------------
+
+(efs-defun efs-parse-listing mvs:nih
+  (host user dir path &optional switches)
+  ;; Parse the current buffer which is assumed to be an MVS listing
+  ;; Based on the listing format of the NIH server. Hope that this format
+  ;; is widespread. If a directory doesn't exist, get a 426 ftp error.
+  ;; HOST = remote host name
+  ;; USER = user name
+  ;; DIR = directory as a remote full path
+  ;; PATH = directory in full efs-syntax
+  (let ((tbl (efs-make-hashtable))
+	(top-p (string-equal "/" dir))
+	;; assume that everything top-level is a partitioned data set
+	)
+    (goto-char (point-min))
+    (efs-save-match-data
+      (while (re-search-forward "^[-A-Z0-9_$.+]+" nil t)
+	(efs-put-hash-entry
+	 (concat (buffer-substring (match-beginning 0) (match-end 0))
+		 (and top-p "."))
+	 (list top-p) tbl)
+	(forward-line 1))
+      (efs-put-hash-entry "." '(t) tbl)
+      (or top-p (efs-put-hash-entry ".." '(t) tbl)))
+    tbl))
+
+;;; Tree dired support
+
+(defconst efs-dired-mvs-re-exe
+  "^. [-A-Z0-9_$+]+\\.EXE "
+  "Regular expression to use to search for MVS executables.")
+
+(or (assq  'mvs:nih efs-dired-re-exe-alist)
+    (setq efs-dired-re-exe-alist
+	  (cons (cons 'mvs:nih efs-dired-mvs-re-exe)
+		efs-dired-re-exe-alist)))
+
+(efs-defun efs-dired-insert-headerline mvs:nih (dir)
+  ;; MVS has no total line, so we insert a blank line for
+  ;; aesthetics.
+  (insert "\n")
+  (forward-char -1)
+  (efs-real-dired-insert-headerline dir))
+
+(efs-defun efs-dired-manual-move-to-filename mvs:nih
+  (&optional raise-error bol eol)
+  ;; In dired, move to the first char of the filename on this line.
+  ;; This is the MVS version.
+  (or eol (setq eol (save-excursion (skip-chars-forward "^\n\r") (point))))
+  (let (case-fold-search)
+    (if bol
+	(goto-char bol)
+      (skip-chars-backward "^\n\r")
+      (setq bol (point)))
+    ;; MVS listings are pretty loose. Tough to tell when we've got a file line.
+    (if (and
+	 (> (- eol bol) 2)
+	 (progn
+	   (forward-char 2)
+	   (skip-chars-forward " \t")
+	   (looking-at "[-A-Z0-9$_.+]+[ \n\r]")))
+	(point)
+      (goto-char bol)
+      (and raise-error (error "No file on this line")))))
+
+(efs-defun efs-dired-manual-move-to-end-of-filename mvs:nih
+  (&optional no-error bol eol)
+  ;; Assumes point is at the 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 MVS 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-Z0-9$_.+" eol)
+    (if (or (= opoint (point)) (not (memq (following-char) '(?\n ?\r ?\ ))))
+	(if no-error
+	    nil
+	  (error "No file on this line"))
+      (point))))
+
+(efs-defun efs-dired-get-filename mvs:nih
+  (&optional localp no-error-if-not-filep)
+  (let ((name (efs-real-dired-get-filename localp no-error-if-not-filep))
+	(parsed (efs-ftp-path (dired-current-directory))))
+    (if (and name (string-equal "/" (nth 2 parsed)))
+	(concat name ".")
+      name)))
+
+(efs-defun efs-dired-fixup-listing mvs:nih
+  (file path &optional switches wildcard)
+  ;; MVS listings have trailing spaces to 80 columns.
+  ;; Can lead to a mess after indentation.
+  (goto-char (point-min))
+  (while (re-search-forward " +$" nil t)
+    (replace-match "")))
+
+;;;; -------------------------------------------------------
+;;;; Support for the TCPFTP MVS server
+;;;; -------------------------------------------------------
+;;;
+;;;  For TCPFTP IBM MVS V2R2.1  Does it really work?
+
+(efs-defun efs-parse-listing mvs:tcp
+  (host user dir path &optional switches)
+  ;; Parse the current buffer which is assumed to be an MVS listing
+  ;; Based on the listing format of the NIH server. Hope that this format
+  ;; is widespread. If a directory doesn't exist, get a 426 ftp error.
+  ;; HOST = remote host name
+  ;; USER = user name
+  ;; DIR = directory as a remote full path
+  ;; PATH = directory in full efs-syntax
+  (efs-save-match-data
+    (goto-char (point-min))
+    (and (looking-at "Volume ")
+	 (let ((top-tbl (efs-make-hashtable))
+	       (case-fold (memq 'mvs efs-case-insensitive-host-types))
+	       tbl-list file dn fn tbl dir-p)
+	   (forward-line 1)
+	   (while (not (eobp))
+	     (end-of-line)
+	     (setq file (buffer-substring (point)
+					  (progn (skip-chars-backward "^ ")
+						 (point)))
+		   dn path
+		   dir-p (string-match "\\." file))
+	     (efs-put-hash-entry file '(nil) top-tbl)
+	     (if dir-p
+		 (progn
+		   (setq dir-p (1+ dir-p)
+			 fn (substring file 0 dir-p))
+		   (efs-put-hash-entry fn '(t) top-tbl)
+		   (while dir-p
+		     (setq dn (efs-internal-file-name-as-directory nil
+			       (concat dn fn))
+			   file (substring file dir-p)
+			   tbl (cdr (assoc dn tbl-list)))
+		     (or tbl (setq tbl (efs-make-hashtable)
+				   tbl-list (cons (cons dn tbl) tbl-list)))
+		     (efs-put-hash-entry file '(nil) tbl)
+		     (setq dir-p (string-match "\\." file))
+		     (if dir-p
+			 (progn
+			   (setq dir-p (1+ dir-p)
+				 fn (substring file 0 dir-p))
+			   (efs-put-hash-entry fn '(t) tbl))))))
+	     (forward-line 1))
+	   (while tbl-list
+	     (efs-put-hash-entry (car (car tbl-list)) (cdr (car tbl-list))
+				 efs-files-hashtable case-fold)
+	     (setq tbl-list (cdr tbl-list)))
+	   top-tbl))))
+	       
+;;; Tree Dired
+
+(efs-defun efs-dired-manual-move-to-filename mvs:tcp
+  (&optional raise-error bol eol)
+  ;; In dired, move to the first char of the filename on this line.
+  ;; This is the MVS version.
+  (or eol (setq eol (save-excursion (skip-chars-forward "^\n\r") (point))))
+  (let (case-fold-search)
+    (if bol
+	(goto-char bol)
+      (skip-chars-backward "^\n\r")
+      (setq bol (point)))
+    (if (and (re-search-forward " [0-9][0-9]/[0-9][0-9]/[0-9][0-9] " eol t)
+	     (progn
+	       (goto-char eol)
+	       (skip-chars-backward "-A-Z0-9$_.")
+	       (char-equal (preceding-char) ?\ ))
+	     (/= eol (point)))
+	(point)
+      (goto-char bol)
+      (and raise-error (error "No file on this line")))))
+
+(efs-defun efs-dired-manual-move-to-end-of-filename mvs:tcp
+  (&optional no-error bol eol)
+  ;; Assumes point is at the 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 MVS 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-Z0-9$_.+" eol)
+    (if (or (= opoint (point)) (not (memq (following-char) '(?\n ?\r ?\ ))))
+	(if no-error
+	    nil
+	  (error "No file on this line"))
+      (point))))
+    
+;;; end of efs-mvs.el