changeset 84440:2311575b5cd3

(file-modes-char-to-who, file-modes-char-to-right) (file-modes-rights-to-number): Auxiliary functions for symbolic to numeric notation of file modes. (file-modes-symbolic-to-number): New. Convert symbolic modes to its numeric value. (read-file-modes): New. Read either an octal value of a file mode or a symbolic value, and return its numeric value.
author Michaël Cadilhac <michael.cadilhac@lrde.org>
date Mon, 10 Sep 2007 09:51:25 +0000
parents aed070a1f09b
children 056df43873df
files lisp/files.el
diffstat 1 files changed, 92 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/files.el	Mon Sep 10 09:42:13 2007 +0000
+++ b/lisp/files.el	Mon Sep 10 09:51:25 2007 +0000
@@ -5407,6 +5407,98 @@
 	  (t
 	   (apply operation arguments)))))
 
+;; Symbolic modes and read-file-modes.
+
+(defun file-modes-char-to-who (char)
+  "Convert CHAR to a who-mask from a symbolic mode notation.
+CHAR is in [ugoa] and represents the users on which rights are applied."
+  (cond ((= char ?u) #o4700)
+	((= char ?g) #o2070)
+	((= char ?o) #o1007)
+	((= char ?a) #o7777)
+	(t (error "%c: bad `who' character" char))))
+
+(defun file-modes-char-to-right (char &optional from)
+  "Convert CHAR to a right-mask from a symbolic mode notation.
+CHAR is in [rwxXstugo] and represents a right.
+If CHAR is in [Xugo], the value is extracted from FROM (or 0 if nil)."
+  (or from (setq from 0))
+  (cond ((= char ?r) #o0444)
+	((= char ?w) #o0222)
+	((= char ?x) #o0111)
+	((= char ?s) #o1000)
+	((= char ?t) #o6000)
+	;; Rights relative to the previous file modes.
+	((= char ?X) (if (= (logand from #o111) 0) 0 #o0111))
+	((= char ?u) (let ((uright (logand #o4700 from)))
+		       (+ uright (/ uright #o10) (/ uright #o100))))
+	((= char ?g) (let ((gright (logand #o2070 from)))
+		       (+ gright (/ gright #o10) (* gright #o10))))
+	((= char ?o) (let ((oright (logand #o1007 from)))
+		       (+ oright (* oright #o10) (* oright #o100))))
+	(t (error "%c: bad right character" char))))
+
+(defun file-modes-rights-to-number (rights who-mask &optional from)
+  "Convert a right string to a right-mask from a symbolic modes notation.
+RIGHTS is the right string, it should match \"([+=-][rwxXstugo]+)+\".
+WHO-MASK is the mask number of the users on which the rights are to be applied.
+FROM (or 0 if nil) is the orginal modes of the file to be chmod'ed."
+  (let* ((num-rights (or from 0))
+	 (list-rights (string-to-list rights))
+	 (op (pop list-rights)))
+    (while (memq op '(?+ ?- ?=))
+      (let ((num-right 0)
+	    char-right)
+	(while (memq (setq char-right (pop list-rights))
+		     '(?r ?w ?x ?X ?s ?t ?u ?g ?o))
+	  (setq num-right
+		(logior num-right
+			(file-modes-char-to-right char-right num-rights))))
+	(setq num-right (logand who-mask num-right)
+	      num-rights
+	      (cond ((= op ?+) (logior num-rights num-right))
+		    ((= op ?-) (logand num-rights (lognot num-right)))
+		    (t (logior (logand num-rights (lognot who-mask)) num-right)))
+	      op char-right)))
+    num-rights))
+
+(defun file-modes-symbolic-to-number (modes &optional from)
+  "Convert symbolic file modes to numeric file modes.
+MODES is the string to convert, it should match
+\"[ugoa]*([+-=][rwxXstugo]+)+,...\".
+See (info \"(coreutils)File permissions\") for more information on this
+notation.
+FROM (or 0 if nil) is the orginal modes of the file to be chmod'ed."
+  (save-match-data
+    (let ((case-fold-search nil)
+	  (num-modes (or from 0)))
+      (while (/= (string-to-char modes) 0)
+	(if (string-match "^\\([ugoa]*\\)\\([+=-][rwxXstugo]+\\)+\\(,\\|\\)" modes)
+	    (let ((num-who (apply 'logior 0
+				  (mapcar 'file-modes-char-to-who
+					  (match-string 1 modes)))))
+	      (when (= num-who 0)
+		(setq num-who (default-file-modes)))
+	      (setq num-modes
+		    (file-modes-rights-to-number (substring modes (match-end 1))
+						 num-who num-modes)
+		    modes (substring modes (match-end 3))))
+	  (error "Parse error in modes near `%s'" (substring modes 0))))
+      num-modes)))
+
+(defun read-file-modes (&optional prompt orig-file)
+  "Read file modes in octal or symbolic notation.
+PROMPT is used as the prompt, default to `File modes (octal or symbolic): '.
+ORIG-FILE is the original file of which modes will be change."
+  (let* ((modes (or (if orig-file (file-modes orig-file) 0)
+		    (error "File not found")))
+	 (value (read-string (or prompt "File modes (octal or symbolic): "))))
+    (save-match-data
+      (if (string-match "^[0-7]+" value)
+	  (string-to-number value 8)
+	(file-modes-symbolic-to-number value modes)))))
+
+
 (define-key ctl-x-map "\C-f" 'find-file)
 (define-key ctl-x-map "\C-r" 'find-file-read-only)
 (define-key ctl-x-map "\C-v" 'find-alternate-file)