240
241
Note that this feature forces backups to be made by copying.
241
242
Yet, at the same time, saving a precious file
242
breaks any hard links between it and other files."
243
breaks any hard links between it and other files.
245
This feature is advisory: for example, if the directory in which the
246
file is being saved is not writable, Emacs may ignore a non-nil value
247
of `file-precious-flag' and write directly into the file.
249
See also: `break-hardlink-on-save'."
253
(defcustom break-hardlink-on-save nil
254
"Non-nil means when saving a file that exists under several names
255
\(i.e., has multiple hardlinks), break the hardlink associated with
256
`buffer-file-name' and write to a new file, so that the other
257
instances of the file are not affected by the save.
259
If `buffer-file-name' refers to a symlink, do not break the symlink.
261
Unlike `file-precious-flag', `break-hardlink-on-save' is not advisory.
262
For example, if the directory in which a file is being saved is not
263
itself writable, then error instead of saving in some
264
hardlink-nonbreaking way.
266
See also `backup-by-copying' and `backup-by-copying-when-linked'."
246
271
(defcustom version-control nil
247
272
"Control use of version numbers for backup files.
248
273
When t, make numeric backup versions unconditionally.
716
741
string nil action))
717
742
(make-obsolete 'locate-file-completion 'locate-file-completion-table "23.1")
719
(defun locate-dominating-file (file regexp)
720
"Look up the directory hierarchy from FILE for a file matching REGEXP."
722
;; `user' is not initialized yet because `file' may not exist, so we may
723
;; have to walk up part of the hierarchy before we find the "initial UID".
725
;; Abbreviate, so as to stop when we cross ~/.
726
(dir (abbreviate-file-name (file-name-as-directory file)))
729
;; As a heuristic, we stop looking up the hierarchy of
730
;; directories as soon as we find a directory belonging to
731
;; another user. This should save us from looking in
732
;; things like /net and /afs. This assumes that all the
733
;; files inside a project belong to the same user.
734
(let ((prev-user user))
735
(setq user (nth 2 (file-attributes dir)))
736
(or (null prev-user) (equal user prev-user))))
737
(if (setq files (condition-case nil
738
(directory-files dir 'full regexp)
740
(throw 'found (car files))
742
(setq dir (file-name-directory
743
(directory-file-name dir))))
744
(defvar locate-dominating-stop-dir-regexp
745
"\\`\\(?:[\\/][\\/]\\|/\\(?:net\\|afs\\|\\.\\.\\.\\)/\\)\\'"
746
"Regexp of directory names which stop the search in `locate-dominating-file'.
747
Any directory whose name matches this regexp will be treated like
748
a kind of root directory by `locate-dominating-file' which will stop its search
749
when it bumps into it.
750
The default regexp prevents fruitless and time-consuming attempts to find
751
special files in directories in which filenames are interpreted as hostnames.")
753
;; (defun locate-dominating-files (file regexp)
754
;; "Look up the directory hierarchy from FILE for a file matching REGEXP.
755
;; Stop at the first parent where a matching file is found and return the list
756
;; of files that that match in this directory."
758
;; ;; `user' is not initialized yet because `file' may not exist, so we may
759
;; ;; have to walk up part of the hierarchy before we find the "initial UID".
761
;; ;; Abbreviate, so as to stop when we cross ~/.
762
;; (dir (abbreviate-file-name (file-name-as-directory file)))
765
;; ;; As a heuristic, we stop looking up the hierarchy of
766
;; ;; directories as soon as we find a directory belonging to
767
;; ;; another user. This should save us from looking in
768
;; ;; things like /net and /afs. This assumes that all the
769
;; ;; files inside a project belong to the same user.
770
;; (let ((prev-user user))
771
;; (setq user (nth 2 (file-attributes dir)))
772
;; (or (null prev-user) (equal user prev-user))))
773
;; (if (setq files (condition-case nil
774
;; (directory-files dir 'full regexp 'nosort)
776
;; (throw 'found files)
778
;; (setq dir (file-name-directory
779
;; (directory-file-name dir))))
783
(defun locate-dominating-file (file name)
784
"Look up the directory hierarchy from FILE for a file named NAME.
785
Stop at the first parent directory containing a file NAME,
786
and return the directory. Return nil if not found."
787
;; We used to use the above locate-dominating-files code, but the
788
;; directory-files call is very costly, so we're much better off doing
789
;; multiple calls using the code in here.
791
;; Represent /home/luser/foo as ~/foo so that we don't try to look for
792
;; `name' in /home or in /.
793
(setq file (abbreviate-file-name file))
796
;; `user' is not initialized outside the loop because
797
;; `file' may not exist, so we may have to walk up part of the
798
;; hierarchy before we find the "initial UID".
803
;; FIXME: Disabled this heuristic because it is sometimes
805
;; As a heuristic, we stop looking up the hierarchy of
806
;; directories as soon as we find a directory belonging
807
;; to another user. This should save us from looking in
808
;; things like /net and /afs. This assumes that all the
809
;; files inside a project belong to the same user.
810
;; (let ((prev-user user))
811
;; (setq user (nth 2 (file-attributes file)))
812
;; (and prev-user (not (equal user prev-user))))
813
(string-match locate-dominating-stop-dir-regexp file)))
814
(setq try (file-exists-p (expand-file-name name file)))
815
(cond (try (setq root file))
816
((equal file (setq prev-file file
817
file (file-name-directory
818
(directory-file-name file))))
747
823
(defun executable-find (command)
748
824
"Search for COMMAND in `exec-path' and return the absolute file name.
1047
1127
(rename-file encoded new-encoded ok-if-already-exists)
1130
(defcustom confirm-nonexistent-file-or-buffer 'after-completion
1131
"Whether confirmation is requested before visiting a new file or buffer.
1132
If nil, confirmation is not requested.
1133
If the value is `after-completion', confirmation is only
1134
requested if the user called `minibuffer-complete' right before
1135
`minibuffer-complete-and-exit'.
1136
Any other non-nil value means to request confirmation.
1138
This affects commands like `switch-to-buffer' and `find-file'."
1141
:type '(choice (const :tag "After completion" after-completion)
1142
(const :tag "Never" nil)
1143
(other :tag "Always" t)))
1145
(defun confirm-nonexistent-file-or-buffer ()
1146
"Whether to request confirmation before visiting a new file or buffer.
1147
The variable `confirm-nonexistent-file-or-buffer' determines the
1148
return value, which may be passed as the REQUIRE-MATCH arg to
1149
`read-buffer' or `find-file-read-args'."
1150
(cond ((eq confirm-nonexistent-file-or-buffer 'after-completion)
1151
'confirm-after-completion)
1152
(confirm-nonexistent-file-or-buffer
1050
1156
(defun read-buffer-to-switch (prompt)
1051
1157
"Read the name of a buffer to switch to and return as a string.
1052
1158
It is intended for `switch-to-buffer' family of commands since they
1054
1160
and default values."
1055
1161
(let ((rbts-completion-table (internal-complete-buffer-except)))
1056
1162
(minibuffer-with-setup-hook
1057
(lambda () (setq minibuffer-completion-table rbts-completion-table))
1058
(read-buffer prompt (other-buffer (current-buffer))))))
1060
(defun switch-to-buffer-other-window (buffer &optional norecord)
1061
"Select buffer BUFFER in another window.
1062
If BUFFER does not identify an existing buffer, then this function
1063
creates a buffer with that name.
1065
When called from Lisp, BUFFER can be a buffer, a string \(a buffer name),
1066
or nil. If BUFFER is nil, then this function chooses a buffer
1067
using `other-buffer'.
1068
Optional second arg NORECORD non-nil means
1069
do not put this buffer at the front of the list of recently selected ones.
1070
This function returns the buffer it switched to.
1164
(setq minibuffer-completion-table rbts-completion-table)
1165
;; Since rbts-completion-table is built dynamically, we
1166
;; can't just add it to the default value of
1167
;; icomplete-with-completion-tables, so we add it
1169
(if (and (boundp 'icomplete-with-completion-tables)
1170
(listp icomplete-with-completion-tables))
1171
(set (make-local-variable 'icomplete-with-completion-tables)
1172
(cons rbts-completion-table
1173
icomplete-with-completion-tables))))
1174
(read-buffer prompt (other-buffer (current-buffer))
1175
(confirm-nonexistent-file-or-buffer)))))
1177
(defun switch-to-buffer-other-window (buffer-or-name &optional norecord)
1178
"Select the buffer specified by BUFFER-OR-NAME in another window.
1179
BUFFER-OR-NAME may be a buffer, a string \(a buffer name), or
1180
nil. Return the buffer switched to.
1182
If called interactively, prompt for the buffer name using the
1183
minibuffer. The variable `confirm-nonexistent-file-or-buffer'
1184
determines whether to request confirmation before creating a new
1187
If BUFFER-OR-NAME is a string and does not identify an existing
1188
buffer, create a new buffer with that name. If BUFFER-OR-NAME is
1189
nil, switch to the buffer returned by `other-buffer'.
1191
Optional second argument NORECORD non-nil means do not put this
1192
buffer at the front of the list of recently selected ones.
1072
1194
This uses the function `display-buffer' as a subroutine; see its
1073
1195
documentation for additional customization information."
1075
1197
(list (read-buffer-to-switch "Switch to buffer in other window: ")))
1076
1198
(let ((pop-up-windows t)
1077
;; Don't let these interfere.
1078
1199
same-window-buffer-names same-window-regexps)
1079
(pop-to-buffer buffer t norecord)))
1081
(defun switch-to-buffer-other-frame (buffer &optional norecord)
1082
"Switch to buffer BUFFER in another frame.
1200
(pop-to-buffer buffer-or-name t norecord)))
1202
(defun switch-to-buffer-other-frame (buffer-or-name &optional norecord)
1203
"Switch to buffer BUFFER-OR-NAME in another frame.
1204
BUFFER-OR-NAME may be a buffer, a string \(a buffer name), or
1205
nil. Return the buffer switched to.
1207
If called interactively, prompt for the buffer name using the
1208
minibuffer. The variable `confirm-nonexistent-file-or-buffer'
1209
determines whether to request confirmation before creating a new
1212
If BUFFER-OR-NAME is a string and does not identify an existing
1213
buffer, create a new buffer with that name. If BUFFER-OR-NAME is
1214
nil, switch to the buffer returned by `other-buffer'.
1083
1216
Optional second arg NORECORD non-nil means do not put this
1084
1217
buffer at the front of the list of recently selected ones.
1085
This function returns the buffer it switched to.
1087
This uses the function `display-buffer' as a subroutine; see
1088
its documentation for additional customization information."
1219
This uses the function `display-buffer' as a subroutine; see its
1220
documentation for additional customization information."
1090
1222
(list (read-buffer-to-switch "Switch to buffer in other frame: ")))
1091
1223
(let ((pop-up-frames t)
1092
1224
same-window-buffer-names same-window-regexps)
1093
(pop-to-buffer buffer t norecord)))
1225
(pop-to-buffer buffer-or-name t norecord)))
1095
1227
(defun display-buffer-other-frame (buffer)
1096
1228
"Display buffer BUFFER in another frame.
2642
2768
This hook is called only if there is at least one file-local
2643
2769
variable to set.")
2645
(defun hack-local-variables-confirm (all-vars unsafe-vars risky-vars project)
2771
(defun hack-local-variables-confirm (all-vars unsafe-vars risky-vars dir-name)
2646
2772
"Get confirmation before setting up local variable values.
2647
2773
ALL-VARS is the list of all variables to be set up.
2648
2774
UNSAFE-VARS is the list of those that aren't marked as safe or risky.
2649
2775
RISKY-VARS is the list of those that are marked as risky.
2650
PROJECT is a directory name if these settings come from directory-local
2651
settings, or nil otherwise."
2776
DIR-NAME is a directory name if these settings come from
2777
directory-local variables, or nil otherwise."
2652
2778
(if noninteractive
2654
(let ((name (if buffer-file-name
2655
(file-name-nondirectory buffer-file-name)
2656
(concat "buffer " (buffer-name))))
2780
(let ((name (or dir-name
2781
(if buffer-file-name
2782
(file-name-nondirectory buffer-file-name)
2783
(concat "buffer " (buffer-name)))))
2657
2784
(offer-save (and (eq enable-local-variables t) unsafe-vars))
2659
2786
(save-window-excursion
2796
(defun hack-local-variables-filter (variables project)
2922
(defun hack-local-variables-filter (variables dir-name)
2797
2923
"Filter local variable settings, querying the user if necessary.
2798
2924
VARIABLES is the alist of variable-value settings. This alist is
2799
2925
filtered based on the values of `ignored-local-variables',
2800
2926
`enable-local-eval', `enable-local-variables', and (if necessary)
2801
2927
user interaction. The results are added to
2802
2928
`file-local-variables-alist', without applying them.
2803
PROJECT is a directory name if these settings come from
2804
directory-local settings, or nil otherwise."
2929
DIR-NAME is a directory name if these settings come from
2930
directory-local variables, or nil otherwise."
2805
2931
;; Strip any variables that are in `ignored-local-variables'.
2806
2932
(dolist (ignored ignored-local-variables)
2807
2933
(setq variables (assq-delete-all ignored variables)))
3055
3181
(set-text-properties 0 (length val) nil val))
3056
3182
(set (make-local-variable var) val))))
3058
;;; Handling directory local variables, aka project settings.
3060
(defvar project-class-alist '()
3061
"Alist mapping project class names (symbols) to project variable lists.")
3063
(defvar project-directory-alist '()
3064
"Alist mapping project directory roots to project classes.")
3066
(defsubst project-get-alist (class)
3067
"Return the project variable list for project CLASS."
3068
(cdr (assq class project-class-alist)))
3070
(defun project-collect-bindings-from-alist (mode-alist settings)
3071
"Collect local variable settings from MODE-ALIST.
3072
SETTINGS is the initial list of bindings.
3184
;;; Handling directory-local variables, aka project settings.
3186
(defvar dir-locals-class-alist '()
3187
"Alist mapping class names (symbols) to variable lists.")
3189
(defvar dir-locals-directory-alist '()
3190
"Alist mapping directory roots to variable classes.")
3192
(defsubst dir-locals-get-class-variables (class)
3193
"Return the variable list for CLASS."
3194
(cdr (assq class dir-locals-class-alist)))
3196
(defun dir-locals-collect-mode-variables (mode-variables variables)
3197
"Collect directory-local variables from MODE-VARIABLES.
3198
VARIABLES is the initial list of variables.
3073
3199
Returns the new list."
3074
(dolist (pair mode-alist settings)
3200
(dolist (pair mode-variables variables)
3075
3201
(let* ((variable (car pair))
3076
3202
(value (cdr pair))
3077
(slot (assq variable settings)))
3203
(slot (assq variable variables)))
3079
3205
(setcdr slot value)
3080
3206
;; Need a new cons in case we setcdr later.
3081
(push (cons variable value) settings)))))
3207
(push (cons variable value) variables)))))
3083
(defun project-collect-binding-list (binding-list root settings)
3084
"Collect entries from BINDING-LIST into SETTINGS.
3209
(defun dir-locals-collect-variables (class-variables root variables)
3210
"Collect entries from CLASS-VARIABLES into VARIABLES.
3085
3211
ROOT is the root directory of the project.
3086
Return the new settings list."
3212
Return the new variables list."
3087
3213
(let* ((file-name (buffer-file-name))
3088
3214
(sub-file-name (if file-name
3089
3215
(substring file-name (length root)))))
3090
(dolist (entry binding-list settings)
3216
(dolist (entry class-variables variables)
3091
3217
(let ((key (car entry)))
3096
3222
(when (and sub-file-name
3097
3223
(>= (length sub-file-name) (length key))
3098
3224
(string= key (substring sub-file-name 0 (length key))))
3099
(setq settings (project-collect-binding-list (cdr entry)
3225
(setq variables (dir-locals-collect-variables
3226
(cdr entry) root variables))))
3102
3228
(derived-mode-p key))
3103
(setq settings (project-collect-bindings-from-alist (cdr entry)
3229
(setq variables (dir-locals-collect-mode-variables
3230
(cdr entry) variables))))))))
3106
(defun set-directory-project (directory class)
3107
"Declare that the project rooted at DIRECTORY is an instance of CLASS.
3232
(defun dir-locals-set-directory-class (directory class)
3233
"Declare that the DIRECTORY root is an instance of CLASS.
3108
3234
DIRECTORY is the name of a directory, a string.
3109
3235
CLASS is the name of a project class, a symbol.
3111
3237
When a file beneath DIRECTORY is visited, the mode-specific
3112
settings from CLASS will be applied to the buffer. The settings
3113
for a class are defined using `define-project-bindings'."
3238
variables from CLASS will be applied to the buffer. The variables
3239
for a class are defined using `dir-locals-set-class-variables'."
3114
3240
(setq directory (file-name-as-directory (expand-file-name directory)))
3115
(unless (assq class project-class-alist)
3116
(error "No such project class `%s'" (symbol-name class)))
3117
(push (cons directory class) project-directory-alist))
3241
(unless (assq class dir-locals-class-alist)
3242
(error "No such class `%s'" (symbol-name class)))
3243
(push (cons directory class) dir-locals-directory-alist))
3119
(defun define-project-bindings (class list)
3120
"Map the project type CLASS to a list of variable settings.
3121
CLASS is the project class, a symbol.
3122
LIST is a list that declares variable settings for the class.
3123
An element in LIST is either of the form:
3245
(defun dir-locals-set-class-variables (class variables)
3246
"Map the type CLASS to a list of variable settings.
3247
CLASS is the project class, a symbol. VARIABLES is a list
3248
that declares directory-local variables for the class.
3249
An element in VARIABLES is either of the form:
3124
3250
(MAJOR-MODE . ALIST)
3126
3252
(DIRECTORY . LIST)
3146
3272
* If the element is of the form (DIRECTORY . LIST), and DIRECTORY
3147
3273
is an initial substring of the file's directory, then LIST is
3148
3274
applied by recursively following these rules."
3149
(let ((elt (assq class project-class-alist)))
3275
(let ((elt (assq class dir-locals-class-alist)))
3152
(push (cons class list) project-class-alist))))
3154
(defun project-find-settings-file (file)
3155
"Find the settings file for FILE.
3277
(setcdr elt variables)
3278
(push (cons class variables) dir-locals-class-alist))))
3280
(defconst dir-locals-file ".dir-locals.el"
3281
"File that contains directory-local variables.
3282
It has to be constant to enforce uniform values
3283
across different environments and users.")
3285
(defun dir-locals-find-file (file)
3286
"Find the directory-local variables FILE.
3156
3287
This searches upward in the directory tree.
3157
If a settings file is found, the file name is returned.
3158
If the file is in a registered project, a cons from
3159
`project-directory-alist' is returned.
3288
If a local variables file is found, the file name is returned.
3289
If the file is already registered, a cons from
3290
`dir-locals-directory-alist' is returned.
3160
3291
Otherwise this returns nil."
3161
3292
(setq file (expand-file-name file))
3162
(let* ((settings (locate-dominating-file file "\\`\\.dir-settings\\.el\\'"))
3293
(let* ((dir-locals-file-name
3294
(if (eq system-type 'ms-dos)
3295
(dosified-file-name dir-locals-file)
3297
(locals-file (locate-dominating-file file dir-locals-file-name))
3164
3299
;; `locate-dominating-file' may have abbreviated the name.
3165
(if settings (setq settings (expand-file-name settings)))
3166
(dolist (x project-directory-alist)
3167
(when (and (eq t (compare-strings file nil (length (car x))
3169
(> (length (car x)) (length (car pda))))
3171
(if (and settings pda)
3172
(if (> (length (file-name-directory settings))
3175
(or settings pda))))
3301
(setq locals-file (expand-file-name dir-locals-file-name locals-file)))
3302
(dolist (elt dir-locals-directory-alist)
3303
(when (and (eq t (compare-strings file nil (length (car elt))
3306
'(windows-nt cygwin ms-dos))))
3307
(> (length (car elt)) (length (car dir-elt))))
3308
(setq dir-elt elt)))
3309
(if (and locals-file dir-elt)
3310
(if (> (length (file-name-directory locals-file))
3311
(length (car dir-elt)))
3314
(or locals-file dir-elt))))
3177
(defun project-define-from-project-file (settings-file)
3178
"Load a settings file and register a new project class and instance.
3179
SETTINGS-FILE is the name of the file holding the settings to apply.
3180
The new class name is the same as the directory in which SETTINGS-FILE
3316
(defun dir-locals-read-from-file (file)
3317
"Load a variables FILE and register a new class and instance.
3318
FILE is the name of the file holding the variables to apply.
3319
The new class name is the same as the directory in which FILE
3181
3320
is found. Returns the new class name."
3182
3321
(with-temp-buffer
3183
;; We should probably store the modtime of SETTINGS-FILE and then
3322
;; We should probably store the modtime of FILE and then
3184
3323
;; reload it whenever it changes.
3185
(insert-file-contents settings-file)
3186
(let* ((dir-name (file-name-directory settings-file))
3324
(insert-file-contents file)
3325
(let* ((dir-name (file-name-directory file))
3187
3326
(class-name (intern dir-name))
3188
(list (read (current-buffer))))
3189
(define-project-bindings class-name list)
3190
(set-directory-project dir-name class-name)
3327
(variables (read (current-buffer))))
3328
(dir-locals-set-class-variables class-name variables)
3329
(dir-locals-set-directory-class dir-name class-name)
3193
3332
(declare-function c-postprocess-file-styles "cc-mode" ())
3195
(defun hack-project-variables ()
3196
"Read local variables for the current buffer based on project settings.
3197
Store the project variables in `file-local-variables-alist',
3334
(defun hack-dir-local-variables ()
3335
"Read per-directory local variables for the current buffer.
3336
Store the directory-local variables in `file-local-variables-alist',
3198
3337
without applying them."
3199
3338
(when (and enable-local-variables
3200
3339
(buffer-file-name)
3201
3340
(not (file-remote-p (buffer-file-name))))
3202
;; Find the settings file.
3203
(let ((settings (project-find-settings-file (buffer-file-name)))
3341
;; Find the variables file.
3342
(let ((variables-file (dir-locals-find-file (buffer-file-name)))
3208
(setq root-dir (file-name-directory (buffer-file-name)))
3209
(setq class (project-define-from-project-file settings)))
3211
(setq root-dir (car settings))
3212
(setq class (cdr settings))))
3346
((stringp variables-file)
3347
(setq dir-name (file-name-directory (buffer-file-name)))
3348
(setq class (dir-locals-read-from-file variables-file)))
3349
((consp variables-file)
3350
(setq dir-name (car variables-file))
3351
(setq class (cdr variables-file))))
3215
(project-collect-binding-list (project-get-alist class)
3218
(hack-local-variables-filter bindings root-dir)))))))
3354
(dir-locals-collect-variables
3355
(dir-locals-get-class-variables class) dir-name nil)))
3357
(hack-local-variables-filter variables dir-name)))))))
3221
3360
(defcustom change-major-mode-with-file-name t
4066
4211
(error "Attempt to save to a file which you aren't allowed to write"))))))
4067
4212
(or buffer-backed-up
4068
4213
(setq setmodes (backup-buffer)))
4069
(let ((dir (file-name-directory buffer-file-name)))
4070
(if (and file-precious-flag
4071
(file-writable-p dir))
4072
;; If file is precious, write temp name, then rename it.
4214
(let* ((dir (file-name-directory buffer-file-name))
4215
(dir-writable (file-writable-p dir)))
4216
(if (or (and file-precious-flag dir-writable)
4217
(and break-hardlink-on-save
4218
(> (file-nlinks buffer-file-name) 1)
4220
(error (concat (format
4221
"Directory %s write-protected; " dir)
4222
"cannot break hardlink when saving")))))
4223
;; Write temp name, then rename it.
4073
4224
;; This requires write access to the containing dir,
4074
4225
;; which is why we don't try it if we don't have that access.
4075
4226
(let ((realname buffer-file-name)
5592
5760
"Offer to save each buffer, then kill the current connection.
5593
5761
If the current frame has no client, kill Emacs itself.
5595
With prefix arg, silently save all file-visiting buffers, then kill.
5763
With prefix ARG, silently save all file-visiting buffers, then kill.
5597
5765
If emacsclient was started with a list of filenames to edit, then
5598
5766
only these files will be asked to be saved."
5599
5767
(interactive "P")
5600
(let ((proc (frame-parameter (selected-frame) 'client))
5601
(frame (selected-frame)))
5603
(save-buffers-kill-emacs)
5604
(server-save-buffers-kill-terminal proc arg))))
5768
(if (frame-parameter (selected-frame) 'client)
5769
(server-save-buffers-kill-terminal arg)
5770
(save-buffers-kill-emacs arg)))
5607
5772
;; We use /: as a prefix to "quote" a file name
5608
5773
;; so that magic file name handlers will not apply to it.
5723
5891
(t (error "%c: bad right character" char))))
5725
5893
(defun file-modes-rights-to-number (rights who-mask &optional from)
5726
"Convert a right string to a right-mask from a symbolic modes notation.
5727
RIGHTS is the right string, it should match \"([+=-][rwxXstugo]+)+\".
5728
WHO-MASK is the mask number of the users on which the rights are to be applied.
5729
FROM (or 0 if nil) is the orginal modes of the file to be chmod'ed."
5894
"Convert a symbolic mode string specification to an equivalent number.
5895
RIGHTS is the symbolic mode spec, it should match \"([+=-][rwxXstugo]+)+\".
5896
WHO-MASK is the bit-mask specifying the category of users to which to
5897
apply the access permissions. See `file-modes-char-to-who'.
5898
FROM (or 0 if nil) gives the mode bits on which to base permissions if
5899
RIGHTS request to add, remove, or set permissions based on existing ones,
5730
5901
(let* ((num-rights (or from 0))
5731
5902
(list-rights (string-to-list rights))
5732
5903
(op (pop list-rights)))