1 |
;;; radconf-mode.el --- major mode for editing GNU radius raddb/config file |
;;; radconf-mode.el --- major mode for editing GNU radius raddb/config file |
2 |
|
|
3 |
;; Authors: 2001 Sergey Poznyakoff |
;; Authors: 2001,2--3 Sergey Poznyakoff |
4 |
;; Version: 1.0 |
;; Version: 1.1 |
5 |
;; Keywords: radius |
;; Keywords: radius |
6 |
;; $Id$ |
;; $Id$ |
7 |
|
|
8 |
;; This file is part of GNU Radius. |
;; This file is part of GNU Radius. |
9 |
;; Copyright (c) 2001, Sergey Poznyakoff |
;; Copyright (c) 2001,2003 Sergey Poznyakoff |
10 |
|
|
11 |
;; GNU Radius is free software; you can redistribute it and/or modify |
;; GNU Radius is free software; you can redistribute it and/or modify |
12 |
;; it under the terms of the GNU General Public License as published by |
;; it under the terms of the GNU General Public License as published by |
54 |
(modify-syntax-entry ?/ ". 14" radconf-mode-syntax-table) |
(modify-syntax-entry ?/ ". 14" radconf-mode-syntax-table) |
55 |
(modify-syntax-entry ?* ". 23" radconf-mode-syntax-table) |
(modify-syntax-entry ?* ". 23" radconf-mode-syntax-table) |
56 |
(modify-syntax-entry ?\n ">" radconf-mode-syntax-table) |
(modify-syntax-entry ?\n ">" radconf-mode-syntax-table) |
57 |
(modify-syntax-entry ?- "w" radconf-mode-syntax-table) ) |
(modify-syntax-entry ?- "w" radconf-mode-syntax-table) |
58 |
|
(modify-syntax-entry ?_ "w" radconf-mode-syntax-table)) |
59 |
|
|
60 |
(defvar radconf-mode-abbrev-table |
(defvar radconf-mode-abbrev-table |
61 |
nil |
nil |
75 |
(defvar radconf-level-indent 8 |
(defvar radconf-level-indent 8 |
76 |
"Amount of additional indentation per nesting level") |
"Amount of additional indentation per nesting level") |
77 |
|
|
|
(defconst radconf-toplevel-keywords |
|
|
'(option logging auth acct proxy cntl snmp) |
|
|
"List of the keywords that open their blocks") |
|
|
|
|
78 |
;; Find the block opened by one of the keywords from KEYWORD-LIST, |
;; Find the block opened by one of the keywords from KEYWORD-LIST, |
79 |
;; such that it contains the point. |
;; such that it contains the point. |
80 |
;; Return cons whose car is a keyword (or nil if no block was found) |
(defun radconf-locate-block (&optional keylist) |
|
;; and cdr is the nesting level counted from that block downwards. |
|
|
(defun radconf-find-block (keyword-list) |
|
81 |
(save-excursion |
(save-excursion |
82 |
(let ((off (if (progn |
(beginning-of-line) |
83 |
(beginning-of-line) |
(let ((keyword nil) |
|
(looking-at "[^#\n]*}.*$")) |
|
|
1 |
|
|
0)) |
|
|
(level 0) |
|
|
(keyword nil) |
|
84 |
(state (list 'start))) |
(state (list 'start))) |
85 |
(while (and (not (eq (car state) 'stop)) |
(while (and (not (eq (car state) 'stop)) |
86 |
(= (forward-line -1) 0)) |
(= (forward-line -1) 0)) |
90 |
(setq state (cdr state)))) |
(setq state (cdr state)))) |
91 |
((eq (car state) 'in-block) |
((eq (car state) 'in-block) |
92 |
(cond |
(cond |
93 |
((looking-at "[^#\n]*{.*$") |
((looking-at "\\s *\\w+\\s *\\(\\s \\w+\\s *\\)?{") |
94 |
(setq state (cdr state))) |
(setq state (cdr state))) |
95 |
((looking-at "[^#\n]*}.*$") |
((looking-at "[^#\n]*}\\s *;\\s *$") |
96 |
(setq state (append (list 'in-block) state))))) |
(setq state (append (list 'in-block) state))))) |
97 |
(t ;; 'start |
(t ;; 'start |
98 |
(let* ((bound (save-excursion |
(let* ((bound (save-excursion |
108 |
(t |
(t |
109 |
(buffer-substring (point) bound))))) |
(buffer-substring (point) bound))))) |
110 |
(cond |
(cond |
111 |
((string-match "}" string) |
((string-match "}\\s *;" string) |
112 |
(setq state (append (list 'in-block) state))) |
(setq state (append (list 'in-block) state))) |
113 |
((string-match "\\*/" string) |
((string-match "\\*/" string) |
114 |
(if (not (string-match "/\\*" string)) |
(if (not (string-match "/\\*" string)) |
115 |
(setq state (append (list 'in-comment) state)))) |
(setq state (append (list 'in-comment) state)))) |
116 |
((string-match "{" string) |
((search-forward-regexp "^\\s *\\(\\w+\\)\\s *\\(\\s \\w+\\s *\\)?{" bound t) |
117 |
(beginning-of-line) |
(let ((word (intern (buffer-substring (match-beginning 1) |
118 |
(setq level (1+ level)) |
(match-end 1))))) |
119 |
(cond |
(setq keyword (append (list word) keyword)) |
120 |
((search-forward-regexp "\\s *\\w+\\s +\\w+\\s *{" bound t) |
(if (assoc word keylist) |
121 |
;; Skip `channel' and `category' statements |
(setq state (list 'stop)))))))))) |
122 |
) |
keyword))) |
|
((search-forward-regexp "\\s *\\(\\w+\\)\\s *{" bound t) |
|
|
(let ((word (intern (buffer-substring (match-beginning 1) |
|
|
(match-end 1))))) |
|
|
(if (and (memq word keyword-list) |
|
|
(null (cdr state))) |
|
|
(setq keyword word |
|
|
state (list 'stop)))))))))))) |
|
|
(if (> level 0) |
|
|
(- level off)) |
|
|
(cons keyword level)))) |
|
123 |
|
|
124 |
;; Determine the nesting level of point. |
;; Determine the nesting level of point. |
125 |
(defun radconf-nesting-level () |
(defun radconf-nesting-level () |
126 |
(let ((block (radconf-find-block radconf-toplevel-keywords))) |
(length (radconf-locate-block))) |
|
(cdr block))) |
|
127 |
|
|
128 |
;; Indent current line. Optional LEVEL-OFFSET is subtracted from |
;; Indent current line. Optional LEVEL-OFFSET is subtracted from |
129 |
;; the determined amount of indentation. |
;; the determined amount of indentation. |
150 |
(radconf-indent-line)) |
(radconf-indent-line)) |
151 |
|
|
152 |
;; A list of keywords allowed in each block |
;; A list of keywords allowed in each block |
153 |
|
|
154 |
(defconst radconf-keyword-dict |
(defconst radconf-keyword-dict |
155 |
;; Block Keyword-list |
;; Block Keyword-list |
156 |
'((nil usedbm |
'((nil usedbm |
160 |
acct |
acct |
161 |
proxy |
proxy |
162 |
snmp |
snmp |
163 |
guile) |
guile |
164 |
|
rewrite |
165 |
|
message |
166 |
|
filters) |
167 |
(option source-ip |
(option source-ip |
168 |
max-requests |
max-requests |
169 |
|
max-processes |
170 |
|
process-idle-timeout |
171 |
|
master-read-timeout |
172 |
|
master-write-timeout |
173 |
exec-program-user |
exec-program-user |
174 |
log-dir |
log-dir |
175 |
acct-dir |
acct-dir |
176 |
resolve) |
resolve |
177 |
|
username-chars) |
178 |
(logging channel |
(logging channel |
179 |
category) |
category |
180 |
(channel file |
(channel file |
181 |
syslog |
syslog |
182 |
option |
option |
183 |
print-pid |
print-pid |
184 |
print-category |
print-category |
185 |
print-cons |
print-cons |
186 |
print-level |
print-level |
187 |
print-priority) |
print-priority |
188 |
|
print-severity |
189 |
|
print-milliseconds) |
190 |
|
(category channel |
191 |
|
;; FIXME: These three are allowed |
192 |
|
;; only in category auth |
193 |
|
print-auth |
194 |
|
print-failed-pass |
195 |
|
print-pass |
196 |
|
;; FIXME: level is applicable only |
197 |
|
;; in category debug. |
198 |
|
level)) |
199 |
(auth port |
(auth port |
200 |
listen |
listen |
201 |
spawn |
spawn |
205 |
detail |
detail |
206 |
strip-names |
strip-names |
207 |
checkrad-assume-logged |
checkrad-assume-logged |
208 |
password-expire-warning) |
password-expire-warning |
209 |
|
compare-atribute-flag) |
210 |
(acct port |
(acct port |
211 |
listen |
listen |
212 |
spawn |
spawn |
213 |
max-requests |
max-requests |
214 |
time-to-live |
time-to-live |
215 |
request-cleanup-delay) |
request-cleanup-delay |
216 |
(proxy max-requests |
compare-atribute-flag) |
|
request-cleanup-delay) |
|
|
(notify host |
|
|
port |
|
|
retry |
|
|
delay) |
|
217 |
(snmp port |
(snmp port |
218 |
spawn |
spawn |
219 |
max-requests |
max-requests |
222 |
ident |
ident |
223 |
community |
community |
224 |
network |
network |
225 |
acl) |
(acl allow |
226 |
(acl allow |
deny) |
227 |
deny) |
(storage file |
228 |
|
perms |
229 |
|
max-nas-count |
230 |
|
max-port-count)) |
231 |
(guile debug |
(guile debug |
232 |
load-path |
load-path |
233 |
load) |
load |
234 |
|
outfile |
235 |
|
gc-interval) |
236 |
(rewrite stack-size) |
(rewrite stack-size) |
237 |
(filters filter) |
(filters filter |
238 |
(filter common |
(filter exec-path |
239 |
exec-path |
error-log |
240 |
error-log |
auth |
241 |
auth |
acct |
242 |
acct))) |
(auth input-format |
243 |
|
wait-reply) |
244 |
|
(acct input-format |
245 |
|
wait-reply))) |
246 |
|
(message account-closed |
247 |
|
password-expired |
248 |
|
password-expire-warning |
249 |
|
access-denied |
250 |
|
realm-quota |
251 |
|
multiple-login |
252 |
|
second-login |
253 |
|
timespan-violation))) |
254 |
|
|
255 |
;; Valid successors for keywords. |
;; Valid successors for keywords. |
256 |
(defconst radconf-keyword-successor |
(defconst radconf-keyword-successor |
263 |
(checkrad-assume-logged yes no) |
(checkrad-assume-logged yes no) |
264 |
(usedbm yes no) |
(usedbm yes no) |
265 |
(print-pid yes no) |
(print-pid yes no) |
|
(print-tid yes no) |
|
266 |
(print-category yes no) |
(print-category yes no) |
267 |
(print-cons yes no) |
(print-cons yes no) |
268 |
(print-level yes no) |
(print-level yes no) |
269 |
(print-priority yes no) )) |
(print-priority yes no) |
270 |
|
(print-milliseconds yes no) |
271 |
|
(print-severity yes no) |
272 |
|
(print-auth yes no) |
273 |
|
(print-failed-pass yes no) |
274 |
|
(print-pass yes no))) |
275 |
|
|
276 |
(defconst radconf-keyword-nodes |
(defconst radconf-keyword-nodes |
277 |
;; Block kwd Info file Info node |
;; Block kwd Info file Info node |
280 |
(logging "radius" "logging") |
(logging "radius" "logging") |
281 |
(auth "radius" "auth") |
(auth "radius" "auth") |
282 |
(acct "radius" "acct") |
(acct "radius" "acct") |
|
(proxy "radius" "proxy") |
|
283 |
(notify "radius" "notify") |
(notify "radius" "notify") |
284 |
(snmp "radius" "snmp") |
(snmp "radius" "snmp") |
285 |
(guile "radius" "guile") )) |
(guile "radius" "guile") |
286 |
|
(filters "radius" "filters") |
287 |
;; Find the topmost block containing the point |
(message "radius" "message") |
288 |
(defun radconf-block () |
(rewrite "radius" "rewrite") )) |
|
(car (radconf-find-block radconf-toplevel-keywords))) |
|
289 |
|
|
290 |
;; Complete a given keyword |
;; Complete a given keyword |
291 |
(defun radconf-complete-keyword (word &optional prompt require-match) |
(defun radconf-complete-keyword (word &optional prompt require-match) |
292 |
(let ((table (assoc (radconf-block) radconf-keyword-dict))) |
(let ((dict radconf-keyword-dict) |
293 |
(if table |
(kwlist (radconf-locate-block))) |
294 |
(let ((compl (completing-read (or prompt "what? ") |
(while (and kwlist dict (listp dict)) |
295 |
(mapcar |
(let ((kw (car kwlist))) |
296 |
(lambda (x) |
(setq kwlist (cdr kwlist)) |
297 |
(cons (symbol-name x) nil)) |
(setq dict (assoc kw dict)))) |
298 |
(cdr table)) |
(if dict |
299 |
nil require-match word nil))) |
(let ((compl (completing-read (or prompt "what? ") |
300 |
(or compl word))))) |
(mapcar |
301 |
|
(lambda (x) |
302 |
|
(cons (symbol-name (if (listp x) |
303 |
|
(car x) |
304 |
|
x)) |
305 |
|
nil)) |
306 |
|
(cdr dict)) |
307 |
|
nil require-match word nil))) |
308 |
|
(or compl word))))) |
309 |
|
|
310 |
;; Complete the argument to a keyword. |
;; Complete the argument to a keyword. |
311 |
(defun radconf-complete-argument (pred word &optional prompt require-match) |
(defun radconf-complete-argument (pred word &optional prompt require-match) |
314 |
(let ((compl (completing-read (or prompt "what? ") |
(let ((compl (completing-read (or prompt "what? ") |
315 |
(mapcar |
(mapcar |
316 |
(lambda (x) |
(lambda (x) |
317 |
(cons (symbol-name x) nil)) |
(cons (symbol-name (if (listp x) |
318 |
|
(car x) |
319 |
|
x)) |
320 |
|
nil)) |
321 |
(cdr table)) |
(cdr table)) |
322 |
nil require-match word nil))) |
nil require-match word nil))) |
323 |
(or compl word))))) |
(or compl word))))) |
330 |
(bound (save-excursion |
(bound (save-excursion |
331 |
(beginning-of-line) |
(beginning-of-line) |
332 |
(point)))) |
(point)))) |
333 |
(if (or (search-backward-regexp "^\\W\\(\\w+\\)" bound t) |
(if (search-backward-regexp "^\\W*\\(\\w+\\)" bound t) |
334 |
(search-backward-regexp "^\\(\\w+\\)" bound t)) |
(let* ((from (match-beginning 1)) |
|
(let* ((from (match-beginning 1)) |
|
335 |
(to (match-end 1)) |
(to (match-end 1)) |
336 |
(word (buffer-substring from to))) |
(word (buffer-substring from to))) |
337 |
(if (= to here) |
(if (= to here) |