Skip to content

Commit 8e48184

Browse files
Merge pull request #8 from gilles-peskine-arm/tools-create-emacs
Emacs support: indentation style; test data file mode
2 parents 0028540 + 62f2107 commit 8e48184

File tree

2 files changed

+389
-0
lines changed

2 files changed

+389
-0
lines changed

tools/emacs/mbedtls-autoloads.el

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
;;; mbedtls-autoloads -- definitions for Mbed TLS development
2+
3+
;; Add the directory containing this file to your `load-path` and
4+
;; put (require 'mbedtls-autoloads) in your Emacs init file.
5+
6+
;;; Code:
7+
8+
;; Mbed TLS test data mode
9+
(add-to-list 'auto-mode-alist
10+
'("mbedtls.*/.*\\.data\\'" . mbedtls-test-data-mode))
11+
(autoload 'mbedtls-test-data-mode "mbedtls-test-data-mode"
12+
"Major mode to edit Mbed TLS test data files."
13+
t)
14+
15+
;; .function files are C code
16+
(add-to-list 'auto-mode-alist '("/suites/[^/]+\\.function\\'" . c-mode))
17+
18+
;; Mbed TLS indentation style
19+
20+
(defun cc-style-lineup-if-with-else (context)
21+
"When there is a newline in else/if, indent if like else.
22+
That is, indent like this:
23+
if (...)
24+
...
25+
else
26+
if (...)
27+
...
28+
instead of this:
29+
if (...)
30+
...
31+
else
32+
if (...)
33+
...
34+
To achieve this, add `(substatement cc-style-lineup-if-with-else +)'
35+
to `c-offsets-alist'."
36+
;; https://emacs.stackexchange.com/questions/31038/stop-reindenting-if-after-else/31041#31041
37+
(pcase context
38+
(`(substatement . ,anchor)
39+
(save-excursion
40+
(back-to-indentation)
41+
(when (looking-at-p "if\\_>")
42+
(goto-char anchor)
43+
(when (looking-at-p "\\(else\\|switch\\)\\_>")
44+
0))))))
45+
46+
(defun cc-style-make-mbedtls ()
47+
(let ((entry (assoc "mbedtls" c-style-alist)))
48+
(unless entry
49+
(setq entry (cons "mbedtls" nil))
50+
(setq c-style-alist (cons entry c-style-alist)))
51+
(setcdr entry '((c-basic-offset . 4)
52+
(c-hanging-braces-alist
53+
(arglist-cont before after)
54+
(arglist-cont-nonempty before after)
55+
(substatement-open before after))
56+
(c-offsets-alist
57+
(case-label . +)
58+
(inextern-lang . 0)
59+
(label . 0)
60+
(substatement cc-style-lineup-if-with-else +)
61+
(substatement-open . 0)
62+
(substatement-label . 0)
63+
)))))
64+
(eval-after-load "cc-styles" '(cc-style-make-mbedtls))
65+
66+
(provide 'mbedtls-autoloads)
67+
68+
;;; That's all.

tools/emacs/mbedtls-test-data-mode.el

+321
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,321 @@
1+
;;; mbedtls-test-data-mode.el --- mode for Mbed TLS test data files
2+
3+
;;; Code:
4+
5+
(defvar mbedtls-test-data-mode-syntax-table
6+
(let ((table (make-syntax-table)))
7+
(modify-syntax-entry ?\n ">" table)
8+
(modify-syntax-entry ?\" "\"" table)
9+
table)
10+
"Syntax table to use in Mbed TLS test data mode.")
11+
12+
(defvar mbedtls-test-data-functions nil
13+
"List of test functions available for this data file.
14+
Each element of the list has the form (NAME ARGUMENTS).
15+
NAME is the name of the test function.
16+
ARGUMENTS is a vector of argument names.")
17+
(make-variable-buffer-local 'mbedtls-test-data-functions)
18+
19+
(defvar mbedtls-test-data-function-buffer nil
20+
"Buffer visiting the associated .function file.")
21+
(make-variable-buffer-local 'mbedtls-test-data-function-buffer)
22+
23+
(defun mbedtls-test-data-function-file-name (&optional data-file)
24+
"Return the name of the .function file associated with the current .data file.
25+
With no argument or with nil as an argument, use the current buffer's file name.
26+
If the optional argument DATA-FILE is a buffer, use its buffer file name.
27+
If the optional argument DATA-FILE is a string, use that as the name of the
28+
.data file."
29+
(let ((file-name (if (stringp data-file)
30+
data-file
31+
(buffer-file-name data-file)))
32+
(case-fold-search t))
33+
(save-match-data
34+
(if (string-match "\\(\\.[-0-9A-Z_a-z]+\\)?\\.data\\'" file-name)
35+
(setq file-name (substring file-name 0 (match-beginning 0)))))
36+
(concat file-name ".function")))
37+
38+
(defun mbedtls-test-data-visit-function-file (&optional data-file
39+
no-error
40+
select)
41+
"Visit the .function file associated with the current .data file.
42+
Return the buffer visiting the file.
43+
Interpret optional argument DATA-FILE as `mbedtls-test-data-visit-function-file'.
44+
If the optional argument NO-ERROR is non-nil, don't error out if the file
45+
cannot be visited, just return nil.
46+
If the optional argument SELECT is non-nil, display the buffer. This is the
47+
default when this function is called interactively."
48+
(interactive '(nil nil t))
49+
(let ((filename (mbedtls-test-data-function-file-name data-file)))
50+
(cond
51+
(select (find-file filename))
52+
(no-error (condition-case nil
53+
(find-file-noselect filename t)
54+
(error nil)))
55+
(t (find-file-noselect filename t)))))
56+
57+
(defun mbedtls-test-data-parse-function-argument-name (function-data limit)
58+
(let ((found nil))
59+
(while (and (< limit (point))
60+
(not (setq found (looking-at "[0-9A-Z_a-z]+"))))
61+
(condition-case nil
62+
(backward-sexp)
63+
;; "Containing expression ends prematurely" on an empty
64+
;; parameter list.
65+
(scan-error (goto-char limit))))
66+
(if found
67+
(setcdr function-data (cons (substring-no-properties (match-string 0))
68+
(cdr function-data))))))
69+
70+
(defun mbedtls-test-data-parse-function-file-contents ()
71+
(let ((entries nil)
72+
(case-fold-search nil))
73+
(while (search-forward-regexp "^/\\*\\s-+BEGIN_CASE\\>" nil t)
74+
(forward-line)
75+
(when (looking-at "[^\n()]*\\s-\\([0-9A-Z_a-z]+\\)\\s-*(")
76+
(let ((function-data (list (substring-no-properties (match-string 1))))
77+
(arguments-start (match-end 0)))
78+
(goto-char (1- (match-end 0)))
79+
(forward-sexp)
80+
(backward-char)
81+
(mbedtls-test-data-parse-function-argument-name function-data
82+
arguments-start)
83+
(when (cdr function-data)
84+
(while (search-backward "," arguments-start t)
85+
(mbedtls-test-data-parse-function-argument-name function-data
86+
arguments-start)))
87+
(setq entries (cons (list (car function-data)
88+
(apply #'vector (cdr function-data)))
89+
entries)))))
90+
entries))
91+
92+
(defun mbedtls-test-data-parse-function-file (&optional no-error)
93+
"Parse the .function file associated with the current .data file.
94+
Store the results in `mbedtls-test-data-functions'.
95+
If NO-ERROR is non-nil, do nothing if the .function file cannot be visited."
96+
(interactive "@")
97+
(or (buffer-live-p mbedtls-test-data-function-buffer)
98+
(setq mbedtls-test-data-function-buffer
99+
(mbedtls-test-data-visit-function-file nil no-error)))
100+
(when mbedtls-test-data-function-buffer
101+
(save-match-data
102+
(with-current-buffer mbedtls-test-data-function-buffer
103+
(save-excursion
104+
(save-restriction
105+
(widen)
106+
(goto-char (point-min))
107+
(setq mbedtls-test-data-functions
108+
(mbedtls-test-data-parse-function-file-contents))))))))
109+
110+
(defun mbedtls-test-data-get-functions ()
111+
"Return information about available test functions.
112+
This is the value of `mbedtls-test-data-functions' in the associated .function
113+
buffer.
114+
Use a cached result if available. Call `mbedtls-test-data-parse-function-file'
115+
to update the cache."
116+
(or (buffer-live-p mbedtls-test-data-function-buffer)
117+
(setq mbedtls-test-data-function-buffer
118+
(mbedtls-test-data-visit-function-file nil t)))
119+
(when mbedtls-test-data-function-buffer
120+
(with-current-buffer mbedtls-test-data-function-buffer
121+
(or mbedtls-test-data-functions
122+
(mbedtls-test-data-parse-function-file t))
123+
mbedtls-test-data-functions)))
124+
125+
(defun mbedtls-test-data-backward-argument (&optional arg)
126+
"Move backward to after the previous `:'.
127+
With a prefix argument, repeat that many times. If the prefix argument is
128+
negative, call `mbedtls-test-data-forward-argument' to move backward."
129+
(interactive "@p")
130+
(if (< arg 0)
131+
(mbedtls-test-data-forward-argument (- n))
132+
(while (> arg 0)
133+
(backward-char)
134+
(skip-chars-backward "^:\n")
135+
(setq arg (1- arg)))))
136+
137+
(defun mbedtls-test-data-forward-argument (&optional arg)
138+
"Move forward to after the next `:'.
139+
With a prefix argument, repeat that many times. If the prefix argument is
140+
negative, call `mbedtls-test-data-backward-argument' to move backward."
141+
(interactive "@p")
142+
(if (< arg 0)
143+
(mbedtls-test-data-backward-argument (- n))
144+
(while (> arg 0)
145+
(skip-chars-forward "^:\n")
146+
(forward-char)
147+
(setq arg (1- arg)))))
148+
149+
(defun mbedtls-test-data-goto-function-line ()
150+
"Move point to the start of the line containing the function and its arguments."
151+
(interactive "@")
152+
(forward-paragraph)
153+
(if (bolp)
154+
(forward-line -1)
155+
(beginning-of-line)))
156+
157+
(defun mbedtls-test-data-get-function-name-at-point ()
158+
"Return the name of the test function in the test case containing point."
159+
(save-excursion
160+
(mbedtls-test-data-goto-function-line)
161+
(let ((beg (point)))
162+
(skip-chars-forward "^:\n")
163+
(buffer-substring-no-properties beg (point)))))
164+
165+
(defun mbedtls-test-data-get-function-information-at-point ()
166+
"Return information about the test function in the test case containing point.
167+
This is the relevant element from `mbedtls-test-data-functions'."
168+
(let ((info (mbedtls-test-data-get-functions)))
169+
(and info
170+
(assoc (mbedtls-test-data-get-function-name-at-point) info))))
171+
172+
(defun mbedtls-test-data-show-function-information (info arg)
173+
(let ((argument-names (cadr info)))
174+
(cond
175+
((or (null arg) (<= arg 0))
176+
(message "%s %s"
177+
(car info)
178+
(mapconcat #'identity argument-names " ")))
179+
((> arg (length argument-names))
180+
(message "%s takes %d arguments (no argument %d)"
181+
(car info) (length argument-names) arg))
182+
(t
183+
(message "%d: %s" arg (aref argument-names (1- arg)))))))
184+
185+
(defun mbedtls-test-data-show-argument-information (&optional arg)
186+
"Show the name of the argument around point.
187+
With a prefix argument, or if point is not on a function argument, show
188+
information about the function called by this test case."
189+
(interactive "@P")
190+
(let ((original-point (point))
191+
(all-info (mbedtls-test-data-get-functions)))
192+
(when all-info
193+
(save-excursion
194+
(mbedtls-test-data-goto-function-line)
195+
(let* ((beg (point))
196+
(function-name (progn
197+
(skip-chars-forward "^:\n")
198+
(buffer-substring-no-properties beg (point))))
199+
(function-info (assoc function-name all-info))
200+
(pos (if (> original-point (point))
201+
(cl-count ?: (buffer-substring-no-properties
202+
beg original-point))
203+
0)))
204+
(mbedtls-test-data-show-function-information function-info pos))))))
205+
206+
(defun mbedtls-test-data-visit-function-definition (&optional arg)
207+
"Visit the function definition for the current test case.
208+
209+
With just \\[universal-argument] or a numerical prefix argument between 1 and 4,
210+
visit in another window with `switch-to-buffer-other-window'. With two
211+
\\[universal-argument] or a numerical prefix argument larger than 4, visit
212+
in another frame with `switch-to-buffer-other-frame'. With a negative prefix
213+
argument, don't display the function definition, only load the file and set
214+
point in the buffer visiting it. In any case, return the function file buffer."
215+
(interactive "@p")
216+
(let ((function-name (mbedtls-test-data-get-function-name-at-point)))
217+
(if function-name
218+
(let ((buffer (mbedtls-test-data-visit-function-file))
219+
(switch-function (cond
220+
((null arg) 'switch-to-buffer)
221+
((symbolp arg) arg)
222+
((and (integerp arg) (> arg 4))
223+
'switch-to-buffer-other-frame)
224+
((and (integerp arg) (> arg 1))
225+
'switch-to-buffer-other-window)
226+
((and (integerp arg) (< arg 0)) 'ignore)
227+
(t 'switch-to-buffer))))
228+
(with-current-buffer buffer
229+
(funcall switch-function buffer)
230+
(push-mark)
231+
(goto-char (point-min))
232+
(search-forward-regexp "^ */\\*+ *BEGIN_CASE\\b")
233+
(save-match-data
234+
(search-forward-regexp (concat "^\\w[^\n()]*\\s-"
235+
function-name
236+
"\\s-*("))
237+
(backward-char)
238+
(forward-sexp)
239+
(forward-line))
240+
buffer))
241+
(message "Unable to determine the test case function name"))))
242+
243+
(defun mbedtls-test-data-copy-to-top ()
244+
"Copy the current test case to the top of the file."
245+
(interactive "@*")
246+
(save-excursion
247+
(save-restriction
248+
(let* ((begin (progn (backward-paragraph)
249+
(skip-chars-forward "\n")
250+
(point)))
251+
(end (progn (forward-paragraph)
252+
(point)))
253+
(text (buffer-substring-no-properties begin end)))
254+
(goto-char (point-min))
255+
(insert text "\n#### ^^^^ Temporary copy ^^^^ ####\n\n")
256+
(if (interactive-p)
257+
(message "Copied %s"
258+
(save-match-data
259+
(substring text 0 (string-match "\n" text)))))))))
260+
261+
(defvar mbedtls-test-data-mode-font-lock-keywords
262+
'(
263+
("^#.*$" (0 font-lock-comment-face))
264+
("^depends_on:"
265+
(0 font-lock-keyword-face)
266+
("[^\n:]+" () ()
267+
(0 font-lock-builtin-face)))
268+
("^\\([A-Z_a-z][0-9A-Z_a-z]*\\)\\(:\\)"
269+
(1 font-lock-function-name-face)
270+
(2 font-lock-keyword-face))
271+
(":" (0 font-lock-keyword-face))
272+
(".\\{66\\}\\(.+\\)"
273+
(1 font-lock-warning-face))
274+
)
275+
"Value of `font-lock-keywords' in Mbed TLS test data mode.")
276+
277+
(defvar mbedtls-test-data-mode-font-lock-defaults
278+
'(mbedtls-test-data-mode-font-lock-keywords
279+
t
280+
nil
281+
((?_ . "w")))
282+
"Value of `font-lock-defaults' in Mbed TLS test data mode.")
283+
284+
(defvar mbedtls-test-data-mode-map
285+
(let ((map (make-sparse-keymap)))
286+
(substitute-key-definition 'backward-sentence
287+
'mbedtls-test-data-backward-argument
288+
map global-map)
289+
(substitute-key-definition 'forward-sentence
290+
'mbedtls-test-data-forward-argument
291+
map global-map)
292+
(define-key map "\C-c\C-a" 'mbedtls-test-data-show-argument-information)
293+
(define-key map "\C-c\C-f" 'mbedtls-test-data-visit-function-definition)
294+
(define-key map "\C-c\C-n" 'mbedtls-test-data-parse-function-file)
295+
(define-key map "\C-c\C-t" 'mbedtls-test-data-copy-to-top)
296+
map)
297+
"Keymap used in Mbed TLS test data mode.")
298+
299+
(defvar mbedtls-test-data-mode-hook nil
300+
"Normal hook to run when entering Mbed TLS test data mode.")
301+
302+
(defun mbedtls-test-data-mode ()
303+
"Major mode to edit Mbed TLS test data files.
304+
305+
\\{mbedtls-test-data-mode-map}"
306+
(interactive)
307+
(kill-all-local-variables)
308+
(setq major-mode 'mbedtls-test-data-mode)
309+
(setq mode-name "MbedTLS")
310+
(set-syntax-table mbedtls-test-data-mode-syntax-table)
311+
(setq comment-start "# "
312+
comment-end "")
313+
(use-local-map mbedtls-test-data-mode-map)
314+
(make-variable-buffer-local 'font-lock-defaults)
315+
(setq font-lock-defaults mbedtls-test-data-mode-font-lock-defaults)
316+
(mbedtls-test-data-parse-function-file t)
317+
(run-hooks 'mbedtls-test-data-mode-hook))
318+
319+
(provide 'mbedtls-test-data-mode)
320+
321+
;;; That's all.

0 commit comments

Comments
 (0)