Replace `string-to-int' by `string-to-number'.
[bpt/emacs.git] / lisp / progmodes / flymake.el
CommitLineData
4bcbcb9d
EZ
1;;; flymake.el -- a universal on-the-fly syntax checker
2
9a686ad2 3;; Copyright (C) 2003, 2005 Free Software Foundation
4bcbcb9d
EZ
4
5;; Author: Pavel Kobiakov <pk_at_work@yahoo.com>
6;; Maintainer: Pavel Kobiakov <pk_at_work@yahoo.com>
7;; Version: 0.3
8;; Keywords: c languages tools
9
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software; you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
14;; the Free Software Foundation; either version 2, or (at your option)
15;; any later version.
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
23;; along with GNU Emacs; see the file COPYING. If not, write to the
24;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25;; Boston, MA 02111-1307, USA.
26
27;;; Commentary:
28;;
29;; Flymake is a minor Emacs mode performing on-the-fly syntax
30;; checks using the external syntax check tool (for C/C++ this
31;; is usually the compiler)
32
33;;; Code:
34
ce721de4
KS
35;;;; [[ Xemacs overlay compatibility
36(if (featurep 'xemacs) (progn
4bcbcb9d
EZ
37(autoload 'make-overlay "overlay" "Overlay compatibility kit." t)
38(autoload 'overlayp "overlay" "Overlay compatibility kit." t)
39(autoload 'overlays-in "overlay" "Overlay compatibility kit." t)
40(autoload 'delete-overlay "overlay" "Overlay compatibility kit." t)
41(autoload 'overlay-put "overlay" "Overlay compatibility kit." t)
42(autoload 'overlay-get "overlay" "Overlay compatibility kit." t)
ce721de4 43))
4bcbcb9d
EZ
44;;;; ]]
45
46;;;; [[ cross-emacs compatibility routines
ce721de4
KS
47(defsubst flymake-makehash (&optional test)
48 (if (fboundp 'make-hash-table)
49 (if test (make-hash-table :test test) (make-hash-table))
50 (makehash test)))
5323b4b0 51
cd2325cd
SM
52(defalias 'flymake-float-time
53 (if (fboundp 'float-time)
54 'float-time
55 (lambda ()
56 (multiple-value-bind (s0 s1 s2) (current-time)
57 (+ (* (float (ash 1 16)) s0) (float s1) (* 0.0000001 s2))))))
ce721de4
KS
58
59(defsubst flymake-replace-regexp-in-string (regexp rep str)
cd2325cd
SM
60 (if (fboundp 'replace-regexp-in-string)
61 (replace-regexp-in-string regexp rep str)
62 (replace-in-string str regexp rep)))
ce721de4
KS
63
64(defun flymake-split-string (str pattern)
53ec26ed
RS
65 "Split STR into a list of substrings bounded by PATTERN.
66Zero-length substrings at the beginning and end of the list are omitted."
5323b4b0
RS
67 (let* ((splitted (split-string str pattern)))
68 (if (and (> (length splitted) 0) (= 0 (length (elt splitted 0))))
69 (setq splitted (cdr splitted)))
70 (if (and (> (length splitted) 0) (= 0 (length (elt splitted (1- (length splitted))))))
71 (setq splitted (reverse (cdr (reverse splitted)))))
72 splitted))
73
ce721de4 74(defsubst flymake-get-temp-dir ()
cd2325cd 75 (if (fboundp 'temp-directory)
ce721de4
KS
76 (temp-directory)
77 temporary-file-directory))
4bcbcb9d 78
cd2325cd
SM
79(defalias 'flymake-line-beginning-position
80 (if (fboundp 'line-beginning-position)
81 'line-beginning-position
82 (lambda (&optional arg) (save-excursion (beginning-of-line arg) (point)))))
4bcbcb9d 83
cd2325cd
SM
84(defalias 'flymake-line-end-position
85 (if (fboundp 'line-end-position)
86 'line-end-position
87 (lambda (&optional arg) (save-excursion (end-of-line arg) (point)))))
5323b4b0
RS
88
89(defun flymake-popup-menu (pos menu-data)
53ec26ed
RS
90 "Pop up the flymake menu at position POS, using the data MENU-DATA.
91POS is a list of the form ((X Y) WINDOW), where X and Y are
92pixels positions from the top left corner of WINDOW's frame.
93MENU-DATA is a list of error and warning messages returned by
94`flymake-make-err-menu-data'."
95 (if (featurep 'xemacs)
ce721de4
KS
96 (let* ((x-pos (nth 0 (nth 0 pos)))
97 (y-pos (nth 1 (nth 0 pos)))
98 (fake-event-props '(button 1 x 1 y 1)))
99 (setq fake-event-props (plist-put fake-event-props 'x x-pos))
100 (setq fake-event-props (plist-put fake-event-props 'y y-pos))
101 (popup-menu (flymake-make-xemacs-menu menu-data) (make-event 'button-press fake-event-props)))
102 (x-popup-menu pos (flymake-make-emacs-menu menu-data))))
4bcbcb9d 103
5323b4b0 104(defun flymake-make-emacs-menu (menu-data)
53ec26ed
RS
105 "Return a menu specifier using MENU-DATA.
106MENU-DATA is a list of error and warning messages returned by
107`flymake-make-err-menu-data'.
108See `x-popup-menu' for the menu specifier format."
5323b4b0
RS
109 (let* ((menu-title (nth 0 menu-data))
110 (menu-items (nth 1 menu-data))
111 (menu-commands nil))
5323b4b0
RS
112 (setq menu-commands (mapcar (lambda (foo)
113 (cons (nth 0 foo) (nth 1 foo)))
114 menu-items))
115 (list menu-title (cons "" menu-commands))))
4bcbcb9d 116
ce721de4
KS
117(if (featurep 'xemacs) (progn
118
cd2325cd
SM
119(defun flymake-nop ())
120
2aa13ec4 121(defun flymake-make-xemacs-menu (menu-data)
53ec26ed 122 "Return a menu specifier using MENU-DATA."
5323b4b0
RS
123 (let* ((menu-title (nth 0 menu-data))
124 (menu-items (nth 1 menu-data))
125 (menu-commands nil))
126 (setq menu-commands (mapcar (lambda (foo)
127 (vector (nth 0 foo) (or (nth 1 foo) '(flymake-nop)) t))
128 menu-items))
129 (cons menu-title menu-commands)))
130
131(defun flymake-xemacs-window-edges (&optional window)
132 (let ((edges (window-pixel-edges window))
133 tmp)
134 (setq tmp edges)
135 (setcar tmp (/ (car tmp) (face-width 'default)))
136 (setq tmp (cdr tmp))
137 (setcar tmp (/ (car tmp) (face-height 'default)))
138 (setq tmp (cdr tmp))
139 (setcar tmp (/ (car tmp) (face-width 'default)))
140 (setq tmp (cdr tmp))
141 (setcar tmp (/ (car tmp) (face-height 'default)))
142 edges))
143
ce721de4
KS
144)) ;; xemacs
145
5323b4b0
RS
146(defun flymake-current-row ()
147 "Return current row number in current frame."
cd2325cd
SM
148 (if (fboundp 'window-edges)
149 (+ (car (cdr (window-edges))) (count-lines (window-start) (point)))
150 (count-lines (window-start) (point))))
5323b4b0
RS
151
152(defun flymake-selected-frame ()
cd2325cd
SM
153 (if (fboundp 'window-edges)
154 (selected-frame)
155 (selected-window)))
4bcbcb9d
EZ
156
157;;;; ]]
158
159(defcustom flymake-log-level -1
cd2325cd 160 "Logging level, only messages with level lower or equal will be logged.
4bcbcb9d 161-1 = NONE, 0 = ERROR, 1 = WARNING, 2 = INFO, 3 = DEBUG"
5323b4b0
RS
162 :group 'flymake
163 :type 'integer)
4bcbcb9d 164
2aa13ec4 165(defun flymake-log (level text &rest args)
53ec26ed
RS
166 "Log a message at level LEVEL.
167If LEVEL is higher than `flymake-log-level', the message is
168ignored. Otherwise, it is printed using `message'.
169TEXT is a format control string, and the remaining arguments ARGS
170are the string substitutions (see `format')."
5323b4b0
RS
171 (if (<= level flymake-log-level)
172 (let* ((msg (apply 'format text args)))
173 (message msg)
174 ;;(with-temp-buffer
175 ;; (insert msg)
176 ;; (insert "\n")
177 ;; (flymake-save-buffer-in-file (current-buffer) "d:/flymake.log" t) ; make log file name customizable
178 ;;)
2aa13ec4 179 )))
4bcbcb9d 180
2aa13ec4 181(defun flymake-ins-after (list pos val)
5323b4b0
RS
182 "Insert VAL into LIST after position POS."
183 (let ((tmp (copy-sequence list))) ; (???)
184 (setcdr (nthcdr pos tmp) (cons val (nthcdr (1+ pos) tmp)))
185 tmp))
4bcbcb9d 186
2aa13ec4 187(defun flymake-set-at (list pos val)
9a686ad2 188 "Set VAL at position POS in LIST."
5323b4b0
RS
189 (let ((tmp (copy-sequence list))) ; (???)
190 (setcar (nthcdr pos tmp) val)
191 tmp))
4bcbcb9d 192
2aa13ec4 193(defvar flymake-pid-to-names (flymake-makehash)
53ec26ed 194 "Hash table mapping PIDs to source buffer names and output files.")
4bcbcb9d 195
2aa13ec4 196(defun flymake-reg-names (pid source-buffer-name)
53ec26ed 197 "Associate PID with SOURCE-BUFFER-NAME in `flymake-pid-to-names'."
5323b4b0
RS
198 (unless (stringp source-buffer-name)
199 (error "Invalid buffer name"))
200 (puthash pid (list source-buffer-name) flymake-pid-to-names))
4bcbcb9d 201
2aa13ec4 202(defun flymake-get-source-buffer-name (pid)
53ec26ed 203 "Return buffer name associated with PID in `flymake-pid-to-names'."
5323b4b0 204 (nth 0 (gethash pid flymake-pid-to-names)))
4bcbcb9d 205
2aa13ec4 206(defun flymake-unreg-names (pid)
53ec26ed 207 "Remove the entry associated with PID from `flymake-pid-to-names'."
5323b4b0 208 (remhash pid flymake-pid-to-names))
4bcbcb9d 209
2aa13ec4
RS
210(defvar flymake-buffer-data (flymake-makehash)
211 "Data specific to syntax check tool, in name-value pairs.")
4bcbcb9d 212
4bcbcb9d 213(make-variable-buffer-local 'flymake-buffer-data)
4bcbcb9d 214
2aa13ec4 215(defun flymake-get-buffer-value (buffer name)
53ec26ed 216 (gethash name (with-current-buffer buffer flymake-buffer-data)))
2aa13ec4
RS
217
218(defun flymake-set-buffer-value (buffer name value)
53ec26ed 219 (puthash name value (with-current-buffer buffer flymake-buffer-data)))
2aa13ec4 220
9a686ad2 221(defvar flymake-output-residual nil)
2aa13ec4 222
4bcbcb9d 223(make-variable-buffer-local 'flymake-output-residual)
2aa13ec4 224
5323b4b0
RS
225(defcustom flymake-allowed-file-name-masks
226 '((".+\\.c$" flymake-simple-make-init flymake-simple-cleanup flymake-get-real-file-name)
227 (".+\\.cpp$" flymake-simple-make-init flymake-simple-cleanup flymake-get-real-file-name)
228 (".+\\.xml$" flymake-xml-init flymake-simple-cleanup flymake-get-real-file-name)
229 (".+\\.html?$" flymake-xml-init flymake-simple-cleanup flymake-get-real-file-name)
230 (".+\\.cs$" flymake-simple-make-init flymake-simple-cleanup flymake-get-real-file-name)
231 (".+\\.pl$" flymake-perl-init flymake-simple-cleanup flymake-get-real-file-name)
232 (".+\\.h$" flymake-master-make-header-init flymake-master-cleanup flymake-get-real-file-name)
233 (".+\\.java$" flymake-simple-make-java-init flymake-simple-java-cleanup flymake-get-real-file-name)
234 (".+[0-9]+\\.tex$" flymake-master-tex-init flymake-master-cleanup flymake-get-real-file-name)
235 (".+\\.tex$" flymake-simple-tex-init flymake-simple-cleanup flymake-get-real-file-name)
236 (".+\\.idl$" flymake-simple-make-init flymake-simple-cleanup flymake-get-real-file-name)
9a686ad2
SM
237 ;; (".+\\.cpp$" 1)
238 ;; (".+\\.java$" 3)
239 ;; (".+\\.h$" 2 (".+\\.cpp$" ".+\\.c$")
240 ;; ("[ \t]*#[ \t]*include[ \t]*\"\\([\w0-9/\\_\.]*[/\\]*\\)\\(%s\\)\"" 1 2))
241 ;; (".+\\.idl$" 1)
242 ;; (".+\\.odl$" 1)
243 ;; (".+[0-9]+\\.tex$" 2 (".+\\.tex$")
244 ;; ("[ \t]*\\input[ \t]*{\\(.*\\)\\(%s\\)}" 1 2 ))
245 ;; (".+\\.tex$" 1)
5323b4b0
RS
246 )
247 "*Files syntax checking is allowed for."
248 :group 'flymake
249 :type '(repeat (string symbol symbol symbol)))
4bcbcb9d 250
2aa13ec4 251(defun flymake-get-file-name-mode-and-masks (file-name)
9a686ad2 252 "Return the corresponding entry from `flymake-allowed-file-name-masks'."
5323b4b0
RS
253 (unless (stringp file-name)
254 (error "Invalid file-name"))
17404091 255 (let ((fnm flymake-allowed-file-name-masks)
5323b4b0 256 (mode-and-masks nil))
17404091
SM
257 (while (and (not mode-and-masks) fnm)
258 (if (string-match (car (car fnm)) file-name)
259 (setq mode-and-masks (cdr (car fnm))))
260 (setq fnm (cdr fnm)))
5323b4b0
RS
261 (flymake-log 3 "file %s, init=%s" file-name (car mode-and-masks))
262 mode-and-masks))
4bcbcb9d 263
2aa13ec4 264(defun flymake-can-syntax-check-file (file-name)
5323b4b0 265 "Determine whether we can syntax check FILE-NAME.
2aa13ec4 266Return nil if we cannot, non-nil if we can."
5323b4b0 267 (if (flymake-get-init-function file-name) t nil))
4bcbcb9d 268
2aa13ec4 269(defun flymake-get-init-function (file-name)
5323b4b0
RS
270 "Return init function to be used for the file."
271 (let* ((init-f (nth 0 (flymake-get-file-name-mode-and-masks file-name))))
9a686ad2
SM
272 ;;(flymake-log 0 "calling %s" init-f)
273 ;;(funcall init-f (current-buffer))
5323b4b0 274 init-f))
4bcbcb9d 275
2aa13ec4 276(defun flymake-get-cleanup-function (file-name)
5323b4b0
RS
277 "Return cleanup function to be used for the file."
278 (nth 1 (flymake-get-file-name-mode-and-masks file-name)))
4bcbcb9d 279
2aa13ec4 280(defun flymake-get-real-file-name-function (file-name)
5323b4b0 281 (or (nth 2 (flymake-get-file-name-mode-and-masks file-name)) 'flymake-get-real-file-name))
4bcbcb9d
EZ
282
283(defcustom flymake-buildfile-dirs '("." ".." "../.." "../../.." "../../../.." "../../../../.." "../../../../../.." "../../../../../../.." "../../../../../../../.." "../../../../../../../../.." "../../../../../../../../../.." "../../../../../../../../../../..")
5323b4b0
RS
284 "Dirs to look for buildfile."
285 :group 'flymake
286 :type '(repeat (string)))
4bcbcb9d
EZ
287
288(defvar flymake-find-buildfile-cache (flymake-makehash 'equal))
4bcbcb9d 289
2aa13ec4 290(defun flymake-get-buildfile-from-cache (dir-name)
5323b4b0 291 (gethash dir-name flymake-find-buildfile-cache))
2aa13ec4
RS
292
293(defun flymake-add-buildfile-to-cache (dir-name buildfile)
5323b4b0 294 (puthash dir-name buildfile flymake-find-buildfile-cache))
2aa13ec4
RS
295
296(defun flymake-clear-buildfile-cache ()
5323b4b0 297 (clrhash flymake-find-buildfile-cache))
2aa13ec4
RS
298
299(defun flymake-find-buildfile (buildfile-name source-dir-name dirs)
5323b4b0 300 "Find buildfile starting from current directory.
2aa13ec4 301Buildfile includes Makefile, build.xml etc.
5323b4b0
RS
302Return its file name if found, or nil if not found."
303 (if (flymake-get-buildfile-from-cache source-dir-name)
304 (progn
305 (flymake-get-buildfile-from-cache source-dir-name))
306 (let* ((buildfile-dir nil)
307 (buildfile nil)
5323b4b0 308 (found nil))
17404091
SM
309 (while (and (not found) dirs)
310 (setq buildfile-dir (concat source-dir-name (car dirs)))
5323b4b0
RS
311 (setq buildfile (concat buildfile-dir "/" buildfile-name))
312 (when (file-exists-p buildfile)
313 (setq found t))
17404091 314 (setq dirs (cdr dirs)))
5323b4b0
RS
315 (if found
316 (progn
317 (flymake-log 3 "found buildfile at %s/%s" buildfile-dir buildfile-name)
318 (flymake-add-buildfile-to-cache source-dir-name buildfile-dir)
319 buildfile-dir)
4bcbcb9d 320 (progn
5323b4b0
RS
321 (flymake-log 3 "buildfile for %s not found" source-dir-name)
322 nil)))))
323
324(defun flymake-fix-file-name (name)
325 "Replace all occurences of '\' with '/'."
326 (when name
327 (let* ((new-name (flymake-replace-regexp-in-string "[\\]" "/" (expand-file-name name)))
328 (last-char (elt new-name (1- (length new-name)))))
329 (setq new-name (flymake-replace-regexp-in-string "\\./" "" new-name))
330 (if (equal "/" (char-to-string last-char))
331 (setq new-name (substring new-name 0 (1- (length new-name)))))
332 new-name)))
4bcbcb9d 333
2aa13ec4 334(defun flymake-same-files (file-name-one file-name-two)
5323b4b0 335 "Check if FILE-NAME-ONE and FILE-NAME-TWO point to same file.
2aa13ec4 336Return t if so, nil if not."
5323b4b0
RS
337 (equal (flymake-fix-file-name file-name-one)
338 (flymake-fix-file-name file-name-two)))
339
5323b4b0
RS
340(defun flymake-get-common-file-prefix (string-one string-two)
341 "Return common prefix for two file names STRING-ONE and STRING-TWO."
4bd0a5d0
SM
342 (setq string-one (file-name-as-directory string-one))
343 (setq string-two (file-name-as-directory string-two))
344 (let ((n (compare-strings string-one nil nil string-two nil nil)))
345 (if (eq n t) string-one
346 (setq n (abs (1+ n)))
347 (file-name-directory (substring string-one 0 n)))))
5323b4b0
RS
348
349(defun flymake-build-relative-filename (from-dir to-dir)
350 "Return rel: FROM-DIR/rel == TO-DIR."
9a686ad2 351 ;; FIXME: Why not use `file-relative-name'?
5323b4b0
RS
352 (if (not (equal (elt from-dir 0) (elt to-dir 0)))
353 (error "First chars in file names %s, %s must be equal (same drive)"
354 from-dir to-dir)
4bd0a5d0
SM
355 (let* ((from (file-name-as-directory (flymake-fix-file-name from-dir)))
356 (to (file-name-as-directory (flymake-fix-file-name to-dir)))
5323b4b0
RS
357 (prefix (flymake-get-common-file-prefix from to))
358 (from-suffix (substring from (length prefix)))
359 (up-count (length (flymake-split-string from-suffix "[/]")))
360 (to-suffix (substring to (length prefix)))
361 (idx 0)
362 (rel nil))
363 (if (and (> (length to-suffix) 0) (equal "/" (char-to-string (elt to-suffix 0))))
364 (setq to-suffix (substring to-suffix 1)))
365
366 (while (< idx up-count)
367 (if (> (length rel) 0)
368 (setq rel (concat rel "/")))
369 (setq rel (concat rel ".."))
370 (setq idx (1+ idx)))
371 (if (> (length rel) 0)
372 (setq rel (concat rel "/")))
373 (if (> (length to-suffix) 0)
374 (setq rel (concat rel to-suffix)))
375 (or rel "./"))))
4bcbcb9d
EZ
376
377(defcustom flymake-master-file-dirs '("." "./src" "./UnitTest")
9a686ad2 378 "Dirs where to look for master files."
5323b4b0
RS
379 :group 'flymake
380 :type '(repeat (string)))
4bcbcb9d
EZ
381
382(defcustom flymake-master-file-count-limit 32
5323b4b0
RS
383 "Max number of master files to check."
384 :group 'flymake
385 :type 'integer)
2aa13ec4 386
ce721de4
KS
387;; This is bound dynamically to pass a parameter to a sort predicate below
388(defvar flymake-included-file-name)
4bcbcb9d 389
2aa13ec4 390(defun flymake-find-possible-master-files (file-name master-file-dirs masks)
9a686ad2
SM
391 "Find (by name and location) all possible master files.
392Master files are .cpp and .c for and .h. Files are searched for
2aa13ec4 393starting from the .h directory and max max-level parent dirs.
4bcbcb9d 394File contents are not checked."
17404091 395 (let* ((dirs master-file-dirs)
5323b4b0 396 (files nil)
17404091
SM
397 (done nil))
398
399 (while (and (not done) dirs)
400 (let* ((dir (concat (flymake-fix-file-name (file-name-directory file-name))
401 "/" (car dirs)))
402 (masks masks))
403 (while (and (file-exists-p dir) (not done) masks)
404 (let* ((mask (car masks))
405 (dir-files (directory-files dir t mask)))
406
407 (flymake-log 3 "dir %s, %d file(s) for mask %s"
408 dir (length dir-files) mask)
409 (while (and (not done) dir-files)
410 (when (not (file-directory-p (car dir-files)))
411 (setq files (cons (car dir-files) files))
5323b4b0
RS
412 (when (>= (length files) flymake-master-file-count-limit)
413 (flymake-log 3 "master file count limit (%d) reached" flymake-master-file-count-limit)
414 (setq done t)))
17404091
SM
415 (setq dir-files (cdr dir-files))))
416 (setq masks (cdr masks))))
417 (setq dirs (cdr dirs)))
5323b4b0 418 (when files
ce721de4
KS
419 (let ((flymake-included-file-name (file-name-nondirectory file-name)))
420 (setq files (sort files 'flymake-master-file-compare))))
5323b4b0
RS
421 (flymake-log 3 "found %d possible master file(s)" (length files))
422 files))
4bcbcb9d 423
2aa13ec4 424(defun flymake-master-file-compare (file-one file-two)
5323b4b0 425 "Compare two files speccified by FILE-ONE and FILE-TWO.
2aa13ec4
RS
426This function is used in sort to move most possible file names
427to the beginning of the list (File.h -> File.cpp moved to top."
5323b4b0
RS
428 (and (equal (file-name-sans-extension flymake-included-file-name)
429 (file-name-sans-extension (file-name-nondirectory file-one)))
430 (not (equal file-one file-two))))
4bcbcb9d
EZ
431
432(defcustom flymake-check-file-limit 8192
5323b4b0
RS
433 "Max number of chars to look at when checking possible master file."
434 :group 'flymake
435 :type 'integer)
4bcbcb9d 436
2aa13ec4 437(defun flymake-check-patch-master-file-buffer (master-file-temp-buffer
5323b4b0
RS
438 master-file-name patched-master-file-name
439 source-file-name patched-source-file-name
440 include-dirs regexp-list)
441 "Check if MASTER-FILE-NAME is a master file for SOURCE-FILE-NAME.
2aa13ec4
RS
442For .cpp master file this means it includes SOURCE-FILE-NAME (.h).
443If yes, patch a copy of MASTER-FILE-NAME to include PATCHED-SOURCE-FILE-NAME
444instead of SOURCE-FILE-NAME.
445Whether a buffer for MATER-FILE-NAME exists, use it as a source
446instead of reading master file from disk."
5323b4b0
RS
447 (let* ((found nil)
448 (regexp (format (nth 0 regexp-list) ; "[ \t]*#[ \t]*include[ \t]*\"\\([\w0-9/\\_\.]*[/\\]*\\)\\(%s\\)\""
449 (file-name-nondirectory source-file-name)))
450 (path-idx (nth 1 regexp-list))
451 (name-idx (nth 2 regexp-list))
452 (inc-path nil)
453 (inc-name nil)
454 (search-limit flymake-check-file-limit))
455 (save-excursion
456 (unwind-protect
457 (progn
458 (set-buffer master-file-temp-buffer)
459 (when (> search-limit (point-max))
460 (setq search-limit (point-max)))
461 (flymake-log 3 "checking %s against regexp %s" master-file-name regexp)
462 (goto-char (point-min))
463 (while (and (< (point) search-limit) (re-search-forward regexp search-limit t))
464 (let* ((match-beg (match-beginning name-idx))
465 (match-end (match-end name-idx)))
466
467 (flymake-log 3 "found possible match for %s" (file-name-nondirectory source-file-name))
468 (setq inc-path (match-string path-idx))
469 (setq inc-name (match-string name-idx))
470 (when (string= inc-name (file-name-nondirectory source-file-name))
471 (flymake-log 3 "inc-path=%s inc-name=%s" inc-path inc-name)
472 (when (flymake-check-include source-file-name inc-path inc-name include-dirs)
473 (setq found t)
474 ;; replace-match is not used here as it fails in
9a686ad2 475 ;; XEmacs with 'last match not a buffer' error as
5323b4b0 476 ;; check-includes calls replace-in-string
4bd0a5d0 477 (flymake-replace-region match-beg match-end
5323b4b0
RS
478 (file-name-nondirectory patched-source-file-name))))
479 (forward-line 1)))
480 (when found
481 (flymake-save-buffer-in-file (current-buffer) patched-master-file-name)))
9a686ad2 482 ;;+(flymake-log 3 "killing buffer %s" (buffer-name master-file-temp-buffer))
5323b4b0 483 (kill-buffer master-file-temp-buffer)))
9a686ad2 484 ;;+(flymake-log 3 "check-patch master file %s: %s" master-file-name found)
5323b4b0
RS
485 (when found
486 (flymake-log 2 "found master file %s" master-file-name))
487 found))
4bcbcb9d 488
4bd0a5d0 489(defun flymake-replace-region (beg end rep)
5323b4b0
RS
490 "Replace text in BUFFER in region (BEG END) with REP."
491 (save-excursion
4bd0a5d0
SM
492 (goto-char end)
493 ;; Insert before deleting, so as to better preserve markers's positions.
494 (insert rep)
495 (delete-region beg end)))
4bcbcb9d 496
2aa13ec4 497(defun flymake-read-file-to-temp-buffer (file-name)
5323b4b0
RS
498 "Insert contents of FILE-NAME into newly created temp buffer."
499 (let* ((temp-buffer (get-buffer-create (generate-new-buffer-name (concat "flymake:" (file-name-nondirectory file-name))))))
cd2325cd 500 (with-current-buffer temp-buffer
5323b4b0
RS
501 (insert-file-contents file-name))
502 temp-buffer))
4bcbcb9d 503
2aa13ec4 504(defun flymake-copy-buffer-to-temp-buffer (buffer)
5323b4b0
RS
505 "Copy contents of BUFFER into newly created temp buffer."
506 (let ((contents nil)
507 (temp-buffer nil))
cd2325cd 508 (with-current-buffer buffer
5323b4b0
RS
509 (setq contents (buffer-string))
510
511 (setq temp-buffer (get-buffer-create (generate-new-buffer-name (concat "flymake:" (buffer-name buffer)))))
512 (set-buffer temp-buffer)
513 (insert contents))
514 temp-buffer))
4bcbcb9d 515
2aa13ec4 516(defun flymake-check-include (source-file-name inc-path inc-name include-dirs)
5323b4b0 517 "Check if SOURCE-FILE-NAME can be found in include path.
2aa13ec4 518Return t if it can be found via include path using INC-PATH and INC-NAME."
5323b4b0
RS
519 (if (file-name-absolute-p inc-path)
520 (flymake-same-files source-file-name (concat inc-path "/" inc-name))
17404091 521 (let* ((file-name nil)
5323b4b0 522 (found nil))
17404091
SM
523 (while (and (not found) include-dirs)
524 (setq file-name (concat (file-name-directory source-file-name)
525 "/" (car include-dirs)))
5323b4b0
RS
526 (if (> (length inc-path) 0)
527 (setq file-name (concat file-name "/" inc-path)))
528 (setq file-name (concat file-name "/" inc-name))
529 (when (flymake-same-files source-file-name file-name)
530 (setq found t))
17404091 531 (setq include-dirs (cdr include-dirs)))
5323b4b0 532 found)))
4bcbcb9d 533
2aa13ec4 534(defun flymake-find-buffer-for-file (file-name)
5323b4b0 535 "Check if there exists a buffer visiting FILE-NAME.
2aa13ec4 536Return t if so, nil if not."
5323b4b0
RS
537 (let ((buffer-name (get-file-buffer file-name)))
538 (if buffer-name
539 (get-buffer buffer-name))))
4bcbcb9d 540
2aa13ec4 541(defun flymake-create-master-file (source-file-name patched-source-file-name get-incl-dirs-f create-temp-f masks include-regexp-list)
5323b4b0 542 "Save SOURCE-FILE-NAME with a different name.
2aa13ec4 543Find master file, patch and save it."
5323b4b0
RS
544 (let* ((possible-master-files (flymake-find-possible-master-files source-file-name flymake-master-file-dirs masks))
545 (master-file-count (length possible-master-files))
546 (idx 0)
547 (temp-buffer nil)
548 (master-file-name nil)
549 (patched-master-file-name nil)
550 (found nil))
551
552 (while (and (not found) (< idx master-file-count))
553 (setq master-file-name (nth idx possible-master-files))
554 (setq patched-master-file-name (funcall create-temp-f master-file-name "flymake_master"))
555 (if (flymake-find-buffer-for-file master-file-name)
556 (setq temp-buffer (flymake-copy-buffer-to-temp-buffer (flymake-find-buffer-for-file master-file-name)))
557 (setq temp-buffer (flymake-read-file-to-temp-buffer master-file-name)))
558 (setq found
559 (flymake-check-patch-master-file-buffer
560 temp-buffer
561 master-file-name
562 patched-master-file-name
563 source-file-name
564 patched-source-file-name
565 (funcall get-incl-dirs-f (file-name-directory master-file-name))
566 include-regexp-list))
567 (setq idx (1+ idx)))
568 (if found
569 (list master-file-name patched-master-file-name)
570 (progn
571 (flymake-log 3 "none of %d master file(s) checked includes %s" master-file-count
572 (file-name-nondirectory source-file-name))
573 nil))))
4bcbcb9d 574
2aa13ec4 575(defun flymake-save-buffer-in-file (buffer file-name)
5323b4b0
RS
576 (or buffer
577 (error "Invalid buffer"))
cd2325cd 578 (with-current-buffer buffer
5323b4b0 579 (save-restriction
5323b4b0
RS
580 (widen)
581 (make-directory (file-name-directory file-name) 1)
582 (write-region (point-min) (point-max) file-name nil 566)))
583 (flymake-log 3 "saved buffer %s in file %s" (buffer-name buffer) file-name))
4bcbcb9d 584
2aa13ec4 585(defun flymake-save-string-to-file (file-name data)
5323b4b0
RS
586 "Save string DATA to file FILE-NAME."
587 (write-region data nil file-name nil 566))
4bcbcb9d 588
2aa13ec4 589(defun flymake-read-file-to-string (file-name)
5323b4b0
RS
590 "Read contents of file FILE-NAME and return as a string."
591 (with-temp-buffer
592 (insert-file-contents file-name)
593 (buffer-substring (point-min) (point-max))))
4bcbcb9d 594
2aa13ec4 595(defun flymake-process-filter (process output)
5323b4b0 596 "Parse OUTPUT and highlight error lines.
2aa13ec4 597It's flymake process filter."
5323b4b0
RS
598 (let* ((pid (process-id process))
599 (source-buffer (get-buffer (flymake-get-source-buffer-name pid))))
4bcbcb9d 600
5323b4b0
RS
601 (flymake-log 3 "received %d byte(s) of output from process %d" (length output) pid)
602 (when source-buffer
603 (flymake-parse-output-and-residual source-buffer output))))
4bcbcb9d 604
2aa13ec4 605(defun flymake-process-sentinel (process event)
5323b4b0
RS
606 "Sentinel for syntax check buffers."
607 (if (memq (process-status process) '(signal exit))
608 (let*((exit-status (process-exit-status process))
609 (command (process-command process))
610 (pid (process-id process))
611 (source-buffer (get-buffer (flymake-get-source-buffer-name pid)))
612 (cleanup-f (flymake-get-cleanup-function (buffer-file-name source-buffer))))
613
614 (flymake-log 2 "process %d exited with code %d" pid exit-status)
615 (condition-case err
616 (progn
617 (flymake-log 3 "cleaning up using %s" cleanup-f)
618 (funcall cleanup-f source-buffer)
619
620 (flymake-unreg-names pid)
621 (delete-process process)
622
623 (when source-buffer
cd2325cd 624 (with-current-buffer source-buffer
5323b4b0
RS
625
626 (flymake-parse-residual source-buffer)
627 (flymake-post-syntax-check source-buffer exit-status command)
53ec26ed 628 (setq flymake-is-running nil))))
5323b4b0
RS
629 (error
630 (let ((err-str (format "Error in process sentinel for buffer %s: %s"
631 source-buffer (error-message-string err))))
632 (flymake-log 0 err-str)
53ec26ed
RS
633 (with-current-buffer source-buffer
634 (setq flymake-is-running nil))))))))
4bcbcb9d 635
2aa13ec4 636(defun flymake-post-syntax-check (source-buffer exit-status command)
53ec26ed
RS
637 (with-current-buffer source-buffer
638 (setq flymake-err-info flymake-new-err-info)
639 (setq flymake-new-err-info nil)
640 (setq flymake-err-info
641 (flymake-fix-line-numbers
642 flymake-err-info 1 (flymake-count-lines source-buffer))))
5323b4b0 643 (flymake-delete-own-overlays source-buffer)
53ec26ed
RS
644 (flymake-highlight-err-lines
645 source-buffer (with-current-buffer source-buffer flymake-err-info))
646 (let (err-count warn-count)
647 (with-current-buffer source-buffer
648 (setq err-count (flymake-get-err-count flymake-err-info "e"))
649 (setq warn-count (flymake-get-err-count flymake-err-info "w"))
650 (flymake-log 2 "%s: %d error(s), %d warning(s) in %.2f second(s)"
5323b4b0 651 (buffer-name source-buffer) err-count warn-count
53ec26ed
RS
652 (- (flymake-float-time) flymake-check-start-time))
653 (setq flymake-check-start-time nil))
654
5323b4b0
RS
655 (if (and (equal 0 err-count) (equal 0 warn-count))
656 (if (equal 0 exit-status)
657 (flymake-report-status source-buffer "" "") ; PASSED
53ec26ed
RS
658 (if (not (with-current-buffer source-buffer
659 flymake-check-was-interrupted))
5323b4b0
RS
660 (flymake-report-fatal-status (current-buffer) "CFGERR"
661 (format "Configuration error has occured while running %s" command))
662 (flymake-report-status source-buffer nil ""))) ; "STOPPED"
663 (flymake-report-status source-buffer (format "%d/%d" err-count warn-count) ""))))
4bcbcb9d 664
2aa13ec4 665(defun flymake-parse-output-and-residual (source-buffer output)
5323b4b0 666 "Split OUTPUT into lines, merge in residual if necessary."
cd2325cd 667 (with-current-buffer source-buffer
53ec26ed 668 (let* ((buffer-residual flymake-output-residual)
5323b4b0
RS
669 (total-output (if buffer-residual (concat buffer-residual output) output))
670 (lines-and-residual (flymake-split-output total-output))
671 (lines (nth 0 lines-and-residual))
672 (new-residual (nth 1 lines-and-residual)))
53ec26ed
RS
673 (with-current-buffer source-buffer
674 (setq flymake-output-residual new-residual)
675 (setq flymake-new-err-info
676 (flymake-parse-err-lines
677 flymake-new-err-info
678 source-buffer lines))))))
4bcbcb9d 679
2aa13ec4 680(defun flymake-parse-residual (source-buffer)
5323b4b0 681 "Parse residual if it's non empty."
cd2325cd 682 (with-current-buffer source-buffer
53ec26ed
RS
683 (when flymake-output-residual
684 (setq flymake-new-err-info
685 (flymake-parse-err-lines
686 flymake-new-err-info
687 source-buffer
688 (list flymake-output-residual)))
689 (setq flymake-output-residual nil))))
4bcbcb9d
EZ
690
691(defvar flymake-err-info nil
2aa13ec4
RS
692 "Sorted list of line numbers and lists of err info in the form (file, err-text).")
693
4bcbcb9d 694(make-variable-buffer-local 'flymake-err-info)
2aa13ec4 695
2aa13ec4 696(defun flymake-er-make-er (line-no line-err-info-list)
5323b4b0 697 (list line-no line-err-info-list))
2aa13ec4
RS
698
699(defun flymake-er-get-line (err-info)
5323b4b0 700 (nth 0 err-info))
2aa13ec4
RS
701
702(defun flymake-er-get-line-err-info-list (err-info)
5323b4b0 703 (nth 1 err-info))
4bcbcb9d
EZ
704
705(defvar flymake-new-err-info nil
2aa13ec4
RS
706 "Same as 'flymake-err-info', effective when a syntax check is in progress.")
707
4bcbcb9d 708(make-variable-buffer-local 'flymake-new-err-info)
2aa13ec4 709
4bcbcb9d 710;; getters/setters for line-err-info: (file, line, type, text).
2aa13ec4 711(defun flymake-ler-make-ler (file line type text &optional full-file)
5323b4b0 712 (list file line type text full-file))
2aa13ec4
RS
713
714(defun flymake-ler-get-file (line-err-info)
5323b4b0 715 (nth 0 line-err-info))
2aa13ec4
RS
716
717(defun flymake-ler-get-line (line-err-info)
5323b4b0 718 (nth 1 line-err-info))
2aa13ec4
RS
719
720(defun flymake-ler-get-type (line-err-info)
5323b4b0 721 (nth 2 line-err-info))
2aa13ec4
RS
722
723(defun flymake-ler-get-text (line-err-info)
5323b4b0 724 (nth 3 line-err-info))
2aa13ec4
RS
725
726(defun flymake-ler-get-full-file (line-err-info)
5323b4b0 727 (nth 4 line-err-info))
2aa13ec4
RS
728
729(defun flymake-ler-set-file (line-err-info file)
5323b4b0 730 (flymake-ler-make-ler file
4bcbcb9d
EZ
731 (flymake-ler-get-line line-err-info)
732 (flymake-ler-get-type line-err-info)
733 (flymake-ler-get-text line-err-info)
2aa13ec4
RS
734 (flymake-ler-get-full-file line-err-info)))
735
736(defun flymake-ler-set-full-file (line-err-info full-file)
5323b4b0 737 (flymake-ler-make-ler (flymake-ler-get-file line-err-info)
4bcbcb9d
EZ
738 (flymake-ler-get-line line-err-info)
739 (flymake-ler-get-type line-err-info)
740 (flymake-ler-get-text line-err-info)
2aa13ec4
RS
741 full-file))
742
743(defun flymake-ler-set-line (line-err-info line)
5323b4b0 744 (flymake-ler-make-ler (flymake-ler-get-file line-err-info)
4bcbcb9d
EZ
745 line
746 (flymake-ler-get-type line-err-info)
747 (flymake-ler-get-text line-err-info)
2aa13ec4 748 (flymake-ler-get-full-file line-err-info)))
4bcbcb9d 749
2aa13ec4 750(defun flymake-get-line-err-count (line-err-info-list type)
5323b4b0 751 "Return number of errors of specified TYPE.
2aa13ec4 752Value of TYPE is eigher e or w."
5323b4b0
RS
753 (let* ((idx 0)
754 (count (length line-err-info-list))
755 (err-count 0))
4bcbcb9d 756
5323b4b0
RS
757 (while (< idx count)
758 (when (equal type (flymake-ler-get-type (nth idx line-err-info-list)))
759 (setq err-count (1+ err-count)))
760 (setq idx (1+ idx)))
761 err-count))
4bcbcb9d 762
2aa13ec4 763(defun flymake-get-err-count (err-info-list type)
5323b4b0
RS
764 "Return number of errors of specified TYPE for ERR-INFO-LIST."
765 (let* ((idx 0)
766 (count (length err-info-list))
767 (err-count 0))
768 (while (< idx count)
769 (setq err-count (+ err-count (flymake-get-line-err-count (nth 1 (nth idx err-info-list)) type)))
770 (setq idx (1+ idx)))
771 err-count))
2aa13ec4
RS
772
773(defun flymake-fix-line-numbers (err-info-list min-line max-line)
5323b4b0 774 "Replace line numbers with fixed value.
2aa13ec4
RS
775If line-numbers is less than MIN-LINE, set line numbers to MIN-LINE.
776If line numbers is greater than MAX-LINE, set line numbers to MAX-LINE.
ce721de4 777The reason for this fix is because some compilers might report
2aa13ec4 778line number outside the file being compiled."
5323b4b0
RS
779 (let* ((count (length err-info-list))
780 (err-info nil)
781 (line 0))
782 (while (> count 0)
783 (setq err-info (nth (1- count) err-info-list))
784 (setq line (flymake-er-get-line err-info))
785 (when (or (< line min-line) (> line max-line))
786 (setq line (if (< line min-line) min-line max-line))
787 (setq err-info-list (flymake-set-at err-info-list (1- count)
788 (flymake-er-make-er line
789 (flymake-er-get-line-err-info-list err-info)))))
790 (setq count (1- count))))
791 err-info-list)
4bcbcb9d 792
2aa13ec4 793(defun flymake-highlight-err-lines (buffer err-info-list)
5323b4b0 794 "Highlight error lines in BUFFER using info from ERR-INFO-LIST."
cd2325cd 795 (with-current-buffer buffer
5323b4b0
RS
796 (let* ((idx 0)
797 (count (length err-info-list)))
798 (while (< idx count)
799 (flymake-highlight-line (car (nth idx err-info-list)) (nth 1 (nth idx err-info-list)))
800 (setq idx (1+ idx))))))
4bcbcb9d 801
2aa13ec4 802(defun flymake-overlay-p (ov)
5323b4b0
RS
803 "Determine whether overlay OV was created by flymake."
804 (and (overlayp ov) (overlay-get ov 'flymake-overlay)))
4bcbcb9d 805
2aa13ec4 806(defun flymake-make-overlay (beg end tooltip-text face mouse-face)
5323b4b0
RS
807 "Allocate a flymake overlay in range BEG and END."
808 (when (not (flymake-region-has-flymake-overlays beg end))
809 (let ((ov (make-overlay beg end nil t t)))
810 (overlay-put ov 'face face)
811 (overlay-put ov 'mouse-face mouse-face)
812 (overlay-put ov 'help-echo tooltip-text)
813 (overlay-put ov 'flymake-overlay t)
814 (overlay-put ov 'priority 100)
9a686ad2 815 ;;+(flymake-log 3 "created overlay %s" ov)
5323b4b0
RS
816 ov)
817 (flymake-log 3 "created an overlay at (%d-%d)" beg end)))
4bcbcb9d 818
2aa13ec4 819(defun flymake-delete-own-overlays (buffer)
5323b4b0 820 "Delete all flymake overlays in BUFFER."
cd2325cd 821 (with-current-buffer buffer
5323b4b0
RS
822 (let ((ov (overlays-in (point-min) (point-max))))
823 (while (consp ov)
824 (when (flymake-overlay-p (car ov))
825 (delete-overlay (car ov))
9a686ad2 826 ;;+(flymake-log 3 "deleted overlay %s" ov)
5323b4b0
RS
827 )
828 (setq ov (cdr ov))))))
4bcbcb9d 829
2aa13ec4 830(defun flymake-region-has-flymake-overlays (beg end)
5323b4b0 831 "Check if region specified by BEG and END has overlay.
2aa13ec4 832Return t if it has at least one flymake overlay, nil if no overlay."
5323b4b0
RS
833 (let ((ov (overlays-in beg end))
834 (has-flymake-overlays nil))
835 (while (consp ov)
836 (when (flymake-overlay-p (car ov))
837 (setq has-flymake-overlays t))
cd2325cd
SM
838 (setq ov (cdr ov)))
839 has-flymake-overlays))
4bcbcb9d
EZ
840
841(defface flymake-errline-face
9a686ad2
SM
842 ;;+ '((((class color)) (:foreground "OrangeRed" :bold t :underline t))
843 ;;+ '((((class color)) (:underline "OrangeRed"))
5323b4b0
RS
844 '((((class color)) (:background "LightPink"))
845 (t (:bold t)))
846 "Face used for marking error lines."
847 :group 'flymake)
4bcbcb9d
EZ
848
849(defface flymake-warnline-face
5323b4b0
RS
850 '((((class color)) (:background "LightBlue2"))
851 (t (:bold t)))
852 "Face used for marking warning lines."
853 :group 'flymake)
4bcbcb9d 854
2aa13ec4 855(defun flymake-highlight-line (line-no line-err-info-list)
5323b4b0 856 "Highlight line LINE-NO in current buffer.
2aa13ec4 857Perhaps use text from LINE-ERR-INFO-ILST to enhance highlighting."
5323b4b0
RS
858 (goto-line line-no)
859 (let* ((line-beg (flymake-line-beginning-position))
860 (line-end (flymake-line-end-position))
861 (beg line-beg)
862 (end line-end)
863 (tooltip-text (flymake-ler-get-text (nth 0 line-err-info-list)))
864 (face nil))
865
866 (goto-char line-beg)
867 (while (looking-at "[ \t]")
868 (forward-char))
4bcbcb9d 869
5323b4b0 870 (setq beg (point))
4bcbcb9d 871
5323b4b0
RS
872 (goto-char line-end)
873 (while (and (looking-at "[ \t\r\n]") (> (point) 1))
874 (backward-char))
4bcbcb9d 875
5323b4b0 876 (setq end (1+ (point)))
4bcbcb9d 877
5323b4b0
RS
878 (when (<= end beg)
879 (setq beg line-beg)
880 (setq end line-end))
2aa13ec4 881
5323b4b0
RS
882 (when (= end beg)
883 (goto-char end)
884 (forward-line)
885 (setq end (point)))
2aa13ec4 886
5323b4b0
RS
887 (if (> (flymake-get-line-err-count line-err-info-list "e") 0)
888 (setq face 'flymake-errline-face)
889 (setq face 'flymake-warnline-face))
2aa13ec4 890
5323b4b0 891 (flymake-make-overlay beg end tooltip-text face nil)))
4bcbcb9d 892
2aa13ec4 893(defun flymake-parse-err-lines (err-info-list source-buffer lines)
5323b4b0
RS
894 "Parse err LINES, store info in ERR-INFO-LIST."
895 (let* ((count (length lines))
896 (idx 0)
897 (line-err-info nil)
898 (real-file-name nil)
899 (source-file-name (buffer-file-name source-buffer))
900 (get-real-file-name-f (flymake-get-real-file-name-function source-file-name)))
901
902 (while (< idx count)
903 (setq line-err-info (flymake-parse-line (nth idx lines)))
904 (when line-err-info
905 (setq real-file-name (funcall get-real-file-name-f source-buffer (flymake-ler-get-file line-err-info)))
906 (setq line-err-info (flymake-ler-set-full-file line-err-info real-file-name))
907
908 (if (flymake-same-files real-file-name source-file-name)
909 (setq line-err-info (flymake-ler-set-file line-err-info nil))
910 (setq line-err-info (flymake-ler-set-file line-err-info (file-name-nondirectory real-file-name))))
911
912 (setq err-info-list (flymake-add-err-info err-info-list line-err-info)))
913 (flymake-log 3 "parsed '%s', %s line-err-info" (nth idx lines) (if line-err-info "got" "no"))
914 (setq idx (1+ idx)))
915 err-info-list))
4bcbcb9d 916
2aa13ec4 917(defun flymake-split-output (output)
5323b4b0 918 "Split OUTPUT into lines.
9a686ad2
SM
919Return last one as residual if it does not end with newline char.
920Returns ((LINES) RESIDUAL)."
5323b4b0
RS
921 (when (and output (> (length output) 0))
922 (let* ((lines (flymake-split-string output "[\n\r]+"))
923 (complete (equal "\n" (char-to-string (aref output (1- (length output))))))
924 (residual nil))
925 (when (not complete)
926 (setq residual (car (last lines)))
927 (setq lines (butlast lines)))
928 (list lines residual))))
4bcbcb9d 929
2aa13ec4 930(defun flymake-reformat-err-line-patterns-from-compile-el (original-list)
5323b4b0 931 "Grab error line patterns from ORIGINAL-LIST in compile.el format.
2aa13ec4 932Convert it to flymake internal format."
5323b4b0 933 (let* ((converted-list '()))
cd2325cd
SM
934 (dolist (item original-list)
935 (setq item (cdr item))
936 (let ((regexp (nth 0 item))
937 (file (nth 1 item))
938 (line (nth 2 item))
939 (col (nth 3 item)))
940 (if (consp file) (setq file (car file)))
941 (if (consp line) (setq line (car line)))
942 (if (consp col) (setq col (car col)))
d799c278 943
cd2325cd
SM
944 (when (not (functionp line))
945 (setq converted-list (cons (list regexp file line col) converted-list)))))
5323b4b0 946 converted-list))
2aa13ec4
RS
947
948(eval-when-compile
5323b4b0
RS
949 (require 'compile))
950
951(defvar flymake-err-line-patterns ; regexp file-idx line-idx col-idx (optional) text-idx(optional), match-end to end of string is error text
952 (append
953 '(
9a686ad2 954 ;; MS Visual C++ 6.0
5323b4b0
RS
955 ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) \: \\(\\(error\\|warning\\|fatal error\\) \\(C[0-9]+\\):[ \t\n]*\\(.+\\)\\)"
956 1 3 nil 4)
9a686ad2 957 ;; jikes
5323b4b0
RS
958 ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)\:\\([0-9]+\\)\:[0-9]+\:[0-9]+\:[0-9]+\: \\(\\(Error\\|Warning\\|Caution\\|Semantic Error\\):[ \t\n]*\\(.+\\)\\)"
959 1 3 nil 4)
9a686ad2 960 ;; MS midl
5323b4b0
RS
961 ("midl[ ]*:[ ]*\\(command line error .*\\)"
962 nil nil nil 1)
9a686ad2 963 ;; MS C#
5323b4b0
RS
964 ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\),[0-9]+)\: \\(\\(error\\|warning\\|fatal error\\) \\(CS[0-9]+\\):[ \t\n]*\\(.+\\)\\)"
965 1 3 nil 4)
9a686ad2 966 ;; perl
5323b4b0 967 ("\\(.*\\) at \\([^ \n]+\\) line \\([0-9]+\\)[,.\n]" 2 3 nil 1)
9a686ad2
SM
968 ;; LaTeX warnings (fileless) ("\\(LaTeX \\(Warning\\|Error\\): .*\\) on input line \\([0-9]+\\)" 20 3 nil 1)
969 ;; ant/javac
5323b4b0
RS
970 (" *\\(\\[javac\\]\\)? *\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)\:\\([0-9]+\\)\:[ \t\n]*\\(.+\\)"
971 2 4 nil 5))
972 ;; compilation-error-regexp-alist)
ce721de4 973 (flymake-reformat-err-line-patterns-from-compile-el compilation-error-regexp-alist-alist))
9a686ad2
SM
974 "Patterns for matching error/warning lines.
975\(REGEXP FILE-IDX LINE-IDX ERR-TEXT-IDX).
976Use `flymake-reformat-err-line-patterns-from-compile-el' to add patterns
977from compile.el")
978
979;;(defcustom flymake-err-line-patterns
980;; '(
981;; ; MS Visual C++ 6.0
982;; ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) \: \\(\\(error\\|warning\\|fatal error\\) \\(C[0-9]+\\):[ \t\n]*\\(.+\\)\\)"
983;; 1 3 4)
984;; ; jikes
985;; ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)\:\\([0-9]+\\)\:[0-9]+\:[0-9]+\:[0-9]+\: \\(\\(Error\\|Warning\\|Caution\\):[ \t\n]*\\(.+\\)\\)"
986;; 1 3 4))
987;; "patterns for matching error/warning lines, (regexp file-idx line-idx err-text-idx)"
988;; :group 'flymake
989;; :type '(repeat (string number number number))
990;;)
4bcbcb9d 991
2aa13ec4 992(defun flymake-parse-line (line)
5323b4b0 993 "Parse LINE to see if it is an error of warning.
2aa13ec4 994Return its components if so, nil if no."
5323b4b0
RS
995 (let ((raw-file-name nil)
996 (line-no 0)
997 (err-type "e")
998 (err-text nil)
17404091 999 (patterns flymake-err-line-patterns)
5323b4b0 1000 (matched nil))
17404091
SM
1001 (while (and patterns (not matched))
1002 (when (string-match (car (car patterns)) line)
1003 (let* ((file-idx (nth 1 (car patterns)))
1004 (line-idx (nth 2 (car patterns))))
5323b4b0
RS
1005
1006 (setq raw-file-name (if file-idx (match-string file-idx line) nil))
027a4b6b 1007 (setq line-no (if line-idx (string-to-number (match-string line-idx line)) 0))
17404091
SM
1008 (setq err-text (if (> (length (car patterns)) 4)
1009 (match-string (nth 4 (car patterns)) line)
5323b4b0
RS
1010 (flymake-patch-err-text (substring line (match-end 0)))))
1011 (or err-text (setq err-text "<no error text>"))
1012 (if (and err-text (string-match "^[wW]arning" err-text))
1013 (setq err-type "w")
1014 )
1015 (flymake-log 3 "parse line: file-idx=%s line-idx=%s file=%s line=%s text=%s" file-idx line-idx
1016 raw-file-name line-no err-text)
1017 (setq matched t)))
17404091 1018 (setq patterns (cdr patterns)))
5323b4b0
RS
1019 (if matched
1020 (flymake-ler-make-ler raw-file-name line-no err-type err-text)
1021 ())))
4bcbcb9d 1022
2aa13ec4 1023(defun flymake-find-err-info (err-info-list line-no)
5323b4b0
RS
1024 "Find (line-err-info-list pos) for specified LINE-NO."
1025 (if err-info-list
1026 (let* ((line-err-info-list nil)
1027 (pos 0)
1028 (count (length err-info-list)))
1029
1030 (while (and (< pos count) (< (car (nth pos err-info-list)) line-no))
1031 (setq pos (1+ pos)))
1032 (when (and (< pos count) (equal (car (nth pos err-info-list)) line-no))
1033 (setq line-err-info-list (flymake-er-get-line-err-info-list (nth pos err-info-list))))
1034 (list line-err-info-list pos))
1035 '(nil 0)))
4bcbcb9d 1036
2aa13ec4 1037(defun flymake-line-err-info-is-less-or-equal (line-one line-two)
5323b4b0
RS
1038 (or (string< (flymake-ler-get-type line-one) (flymake-ler-get-type line-two))
1039 (and (string= (flymake-ler-get-type line-one) (flymake-ler-get-type line-two))
1040 (not (flymake-ler-get-file line-one)) (flymake-ler-get-file line-two))
1041 (and (string= (flymake-ler-get-type line-one) (flymake-ler-get-type line-two))
1042 (or (and (flymake-ler-get-file line-one) (flymake-ler-get-file line-two))
1043 (and (not (flymake-ler-get-file line-one)) (not (flymake-ler-get-file line-two)))))))
4bcbcb9d 1044
2aa13ec4 1045(defun flymake-add-line-err-info (line-err-info-list line-err-info)
53ec26ed
RS
1046 "Update LINE-ERR-INFO-LIST with the error LINE-ERR-INFO.
1047For the format of LINE-ERR-INFO, see `flymake-ler-make-ler'.
1048The new element is inserted in the proper position, according to
1049the predicate `flymake-line-err-info-is-less-or-equal'.
1050The updated value of LINE-ERR-INFO-LIST is returned."
5323b4b0
RS
1051 (if (not line-err-info-list)
1052 (list line-err-info)
1053 (let* ((count (length line-err-info-list))
1054 (idx 0))
1055 (while (and (< idx count) (flymake-line-err-info-is-less-or-equal (nth idx line-err-info-list) line-err-info))
1056 (setq idx (1+ idx)))
1057 (cond ((equal 0 idx) (setq line-err-info-list (cons line-err-info line-err-info-list)))
1058 (t (setq line-err-info-list (flymake-ins-after line-err-info-list (1- idx) line-err-info))))
1059 line-err-info-list)))
4bcbcb9d 1060
2aa13ec4 1061(defun flymake-add-err-info (err-info-list line-err-info)
53ec26ed
RS
1062 "Update ERR-INFO-LIST with the error LINE-ERR-INFO, preserving sort order.
1063Returns the updated value of ERR-INFO-LIST.
1064For the format of ERR-INFO-LIST, see `flymake-err-info'.
1065For the format of LINE-ERR-INFO, see `flymake-ler-make-ler'."
4bd0a5d0 1066 (let* ((line-no (if (flymake-ler-get-file line-err-info) 1 (flymake-ler-get-line line-err-info)))
5323b4b0
RS
1067 (info-and-pos (flymake-find-err-info err-info-list line-no))
1068 (exists (car info-and-pos))
1069 (pos (nth 1 info-and-pos))
1070 (line-err-info-list nil)
1071 (err-info nil))
1072
1073 (if exists
1074 (setq line-err-info-list (flymake-er-get-line-err-info-list (car (nthcdr pos err-info-list)))))
1075 (setq line-err-info-list (flymake-add-line-err-info line-err-info-list line-err-info))
1076
1077 (setq err-info (flymake-er-make-er line-no line-err-info-list))
1078 (cond (exists (setq err-info-list (flymake-set-at err-info-list pos err-info)))
1079 ((equal 0 pos) (setq err-info-list (cons err-info err-info-list)))
1080 (t (setq err-info-list (flymake-ins-after err-info-list (1- pos) err-info))))
1081 err-info-list))
4bcbcb9d 1082
2aa13ec4 1083(defun flymake-get-project-include-dirs-imp (basedir)
5323b4b0
RS
1084 "Include dirs for the project current file belongs to."
1085 (if (flymake-get-project-include-dirs-from-cache basedir)
1086 (progn
1087 (flymake-get-project-include-dirs-from-cache basedir))
9a686ad2 1088 ;;else
5323b4b0
RS
1089 (let* ((command-line (concat "make -C\"" basedir "\" DUMPVARS=INCLUDE_DIRS dumpvars"))
1090 (output (shell-command-to-string command-line))
1091 (lines (flymake-split-string output "\n"))
1092 (count (length lines))
1093 (idx 0)
1094 (inc-dirs nil))
1095 (while (and (< idx count) (not (string-match "^INCLUDE_DIRS=.*" (nth idx lines))))
1096 (setq idx (1+ idx)))
1097 (when (< idx count)
1098 (let* ((inc-lines (flymake-split-string (nth idx lines) " *-I"))
1099 (inc-count (length inc-lines)))
1100 (while (> inc-count 0)
1101 (when (not (string-match "^INCLUDE_DIRS=.*" (nth (1- inc-count) inc-lines)))
1102 (setq inc-dirs (cons (flymake-replace-regexp-in-string "\"" "" (nth (1- inc-count) inc-lines)) inc-dirs)))
1103 (setq inc-count (1- inc-count)))))
1104 (flymake-add-project-include-dirs-to-cache basedir inc-dirs)
1105 inc-dirs)))
4bcbcb9d
EZ
1106
1107(defcustom flymake-get-project-include-dirs-function 'flymake-get-project-include-dirs-imp
5323b4b0
RS
1108 "Function used to get project inc dirs, one paramater: basedir name."
1109 :group 'flymake
1110 :type 'function)
4bcbcb9d 1111
2aa13ec4 1112(defun flymake-get-project-include-dirs (basedir)
5323b4b0 1113 (funcall flymake-get-project-include-dirs-function basedir))
4bcbcb9d 1114
2aa13ec4 1115(defun flymake-get-system-include-dirs ()
5323b4b0
RS
1116 "System include dirs - from the 'INCLUDE' env setting."
1117 (let* ((includes (getenv "INCLUDE")))
1118 (if includes (flymake-split-string includes path-separator) nil)))
4bcbcb9d
EZ
1119
1120(defvar flymake-project-include-dirs-cache (flymake-makehash 'equal))
4bcbcb9d 1121
2aa13ec4 1122(defun flymake-get-project-include-dirs-from-cache (base-dir)
5323b4b0 1123 (gethash base-dir flymake-project-include-dirs-cache))
2aa13ec4
RS
1124
1125(defun flymake-add-project-include-dirs-to-cache (base-dir include-dirs)
5323b4b0 1126 (puthash base-dir include-dirs flymake-project-include-dirs-cache))
2aa13ec4
RS
1127
1128(defun flymake-clear-project-include-dirs-cache ()
5323b4b0 1129 (clrhash flymake-project-include-dirs-cache))
2aa13ec4
RS
1130
1131(defun flymake-get-include-dirs (base-dir)
5323b4b0
RS
1132 "Get dirs to use when resolving local file names."
1133 (let* ((include-dirs (append '(".") (flymake-get-project-include-dirs base-dir) (flymake-get-system-include-dirs))))
1134 include-dirs))
4bcbcb9d 1135
2aa13ec4 1136(defun flymake-find-file (rel-file-name include-dirs)
5323b4b0 1137 "Iterate through include-dirs to find file REL-FILE-NAME.
2aa13ec4 1138Return first 'INCLUDE-DIRS/REL-FILE-NAME' that exists, or just REL-FILE-NAME if not."
5323b4b0
RS
1139 (let* ((count (length include-dirs))
1140 (idx 0)
1141 (found nil)
1142 (full-file-name rel-file-name))
1143
1144 (while (and (not found) (< idx count))
1145 (let* ((dir (nth idx include-dirs)))
1146 (setq full-file-name (concat dir "/" rel-file-name))
1147 (when (file-exists-p full-file-name)
1148 (setq found t)))
1149 (setq idx (1+ idx)))
1150 (if found
1151 full-file-name
1152 rel-file-name)))
4bcbcb9d 1153
2aa13ec4 1154(defun flymake-restore-formatting (source-buffer)
5323b4b0
RS
1155 "Remove any formatting made by flymake."
1156 )
4bcbcb9d 1157
2aa13ec4 1158(defun flymake-get-program-dir (buffer)
5323b4b0
RS
1159 "Get dir to start program in."
1160 (unless (bufferp buffer)
cd2325cd
SM
1161 (error "Invalid buffer"))
1162 (with-current-buffer buffer
5323b4b0 1163 default-directory))
4bcbcb9d 1164
2aa13ec4 1165(defun flymake-safe-delete-file (file-name)
5323b4b0
RS
1166 (when (and file-name (file-exists-p file-name))
1167 (delete-file file-name)
1168 (flymake-log 1 "deleted file %s" file-name)))
4bcbcb9d 1169
2aa13ec4 1170(defun flymake-safe-delete-directory (dir-name)
5323b4b0
RS
1171 (condition-case err
1172 (progn
1173 (delete-directory dir-name)
1174 (flymake-log 1 "deleted dir %s" dir-name))
1175 (error
1176 (flymake-log 1 "Failed to delete dir %s, error ignored" dir-name))))
4bcbcb9d 1177
ce721de4 1178(defcustom flymake-compilation-prevents-syntax-check t
5323b4b0
RS
1179 "If non-nil, syntax check won't be started in case compilation is running."
1180 :group 'flymake
1181 :type 'boolean)
4bcbcb9d 1182
2aa13ec4 1183(defun flymake-start-syntax-check (buffer)
5323b4b0
RS
1184 "Start syntax checking for buffer BUFFER."
1185 (unless (bufferp buffer)
1186 (error "Expected a buffer"))
cd2325cd 1187 (with-current-buffer buffer
53ec26ed
RS
1188 (flymake-log 3 "flymake is running: %s" flymake-is-running)
1189 (when (and (not flymake-is-running)
5323b4b0
RS
1190 (flymake-can-syntax-check-file (buffer-file-name buffer)))
1191 (when (or (not flymake-compilation-prevents-syntax-check)
1192 (not (flymake-compilation-is-running))) ;+ (flymake-rep-ort-status buffer "COMP")
1193 (flymake-clear-buildfile-cache)
1194 (flymake-clear-project-include-dirs-cache)
1195
53ec26ed
RS
1196 (setq flymake-check-was-interrupted nil)
1197 (setq flymake-buffer-data (flymake-makehash 'equal))
5323b4b0
RS
1198
1199 (let* ((source-file-name (buffer-file-name buffer))
1200 (init-f (flymake-get-init-function source-file-name))
1201 (cleanup-f (flymake-get-cleanup-function source-file-name))
1202 (cmd-and-args (funcall init-f buffer))
1203 (cmd (nth 0 cmd-and-args))
1204 (args (nth 1 cmd-and-args))
1205 (dir (nth 2 cmd-and-args)))
1206 (if (not cmd-and-args)
1207 (progn
1208 (flymake-log 0 "init function %s for %s failed, cleaning up" init-f source-file-name)
1209 (funcall cleanup-f buffer))
1210 (progn
53ec26ed 1211 (setq flymake-last-change-time nil)
5323b4b0 1212 (flymake-start-syntax-check-process buffer cmd args dir))))))))
4bcbcb9d 1213
2aa13ec4 1214(defun flymake-start-syntax-check-process (buffer cmd args dir)
5323b4b0
RS
1215 "Start syntax check process."
1216 (let* ((process nil))
1217 (condition-case err
1218 (progn
1219 (when dir
1220 (let ((default-directory dir))
1221 (flymake-log 3 "starting process on dir %s" default-directory)))
1222 (setq process (get-process (apply 'start-process "flymake-proc" nil cmd args)))
1223 (set-process-sentinel process 'flymake-process-sentinel)
1224 (set-process-filter process 'flymake-process-filter)
1225
1226 (flymake-reg-names (process-id process) (buffer-name buffer))
1227
53ec26ed
RS
1228 (with-current-buffer buffer
1229 (setq flymake-is-running t)
1230 (setq flymake-last-change-time nil)
1231 (setq flymake-check-start-time (flymake-float-time)))
5323b4b0
RS
1232
1233 (flymake-report-status buffer nil "*")
1234 (flymake-log 2 "started process %d, command=%s, dir=%s"
1235 (process-id process) (process-command process) default-directory)
1236 process)
1237 (error
1238 (let* ((err-str (format "Failed to launch syntax check process '%s' with args %s: %s"
1239 cmd args (error-message-string err)))
1240 (source-file-name (buffer-file-name buffer))
1241 (cleanup-f (flymake-get-cleanup-function source-file-name)))
1242 (flymake-log 0 err-str)
1243 (funcall cleanup-f buffer)
1244 (flymake-report-fatal-status buffer "PROCERR" err-str))))))
4bcbcb9d 1245
2aa13ec4 1246(defun flymake-kill-process (pid &optional rest)
5323b4b0
RS
1247 "Kill process PID."
1248 (signal-process pid 9)
1249 (let* ((buffer-name (flymake-get-source-buffer-name pid)))
1250 (when (and buffer-name (get-buffer buffer-name))
53ec26ed
RS
1251 (with-current-buffer (get-buffer buffer-name)
1252 (setq flymake-check-was-interrupted t))))
5323b4b0 1253 (flymake-log 1 "killed process %d" pid))
4bcbcb9d 1254
2aa13ec4 1255(defun flymake-stop-all-syntax-checks ()
5323b4b0
RS
1256 "Kill all syntax check processes."
1257 (interactive)
1258 (let ((pids (copy-hash-table flymake-pid-to-names)))
1259 (maphash 'flymake-kill-process pids)))
4bcbcb9d 1260
2aa13ec4 1261(defun flymake-compilation-is-running ()
5323b4b0
RS
1262 (and (boundp 'compilation-in-progress)
1263 compilation-in-progress))
4bcbcb9d 1264
2aa13ec4 1265(defun flymake-compile ()
5323b4b0
RS
1266 "Kill all flymake syntax checks, start compilation."
1267 (interactive)
1268 (flymake-stop-all-syntax-checks)
1269 (call-interactively 'compile))
4bcbcb9d
EZ
1270
1271(defvar flymake-is-running nil
9a686ad2 1272 "If t, flymake syntax check process is running for the current buffer.")
2aa13ec4 1273
4bcbcb9d 1274(make-variable-buffer-local 'flymake-is-running)
2aa13ec4 1275
4bcbcb9d 1276(defvar flymake-timer nil
2aa13ec4
RS
1277 "Timer for starting syntax check.")
1278
4bcbcb9d 1279(make-variable-buffer-local 'flymake-timer)
2aa13ec4 1280
4bcbcb9d 1281(defvar flymake-last-change-time nil
2aa13ec4
RS
1282 "Time of last buffer change.")
1283
4bcbcb9d 1284(make-variable-buffer-local 'flymake-last-change-time)
2aa13ec4 1285
4bcbcb9d 1286(defvar flymake-check-start-time nil
2aa13ec4
RS
1287 "Time at which syntax check was started.")
1288
4bcbcb9d 1289(make-variable-buffer-local 'flymake-check-start-time)
2aa13ec4 1290
4bcbcb9d 1291(defvar flymake-check-was-interrupted nil
9a686ad2 1292 "Non-nil if syntax check was killed by `flymake-compile'.")
2aa13ec4 1293
4bcbcb9d 1294(make-variable-buffer-local 'flymake-check-was-interrupted)
2aa13ec4 1295
4bcbcb9d 1296(defcustom flymake-no-changes-timeout 0.5
5323b4b0
RS
1297 "Time to wait after last change before starting compilation."
1298 :group 'flymake
1299 :type 'number)
4bcbcb9d 1300
2aa13ec4 1301(defun flymake-on-timer-event (buffer)
5323b4b0 1302 "Start a syntax check for buffer BUFFER if necessary."
53ec26ed 1303 (when (bufferp buffer)
cd2325cd 1304 (with-current-buffer buffer
53ec26ed
RS
1305 (when (and (not flymake-is-running)
1306 flymake-last-change-time
1307 (> (flymake-float-time) (+ flymake-no-changes-timeout flymake-last-change-time)))
1308
1309 (setq flymake-last-change-time nil)
5323b4b0
RS
1310 (flymake-log 3 "starting syntax check as more than 1 second passed since last change")
1311 (flymake-start-syntax-check buffer)))))
4bcbcb9d 1312
2aa13ec4 1313(defun flymake-start-syntax-check-for-current-buffer ()
5323b4b0
RS
1314 "Run 'flymake-start-syntax-check' for current buffer if it isn't already running."
1315 (interactive)
1316 (flymake-start-syntax-check (current-buffer)))
4bcbcb9d 1317
2aa13ec4 1318(defun flymake-current-line-no ()
5323b4b0
RS
1319 "Return number of current line in current buffer."
1320 (interactive)
1321 (let ((beg (point-min))
1322 (end (if (= (point) (point-max)) (point) (1+ (point)))))
1323 (count-lines beg end)))
4bcbcb9d 1324
2aa13ec4 1325(defun flymake-count-lines (buffer)
5323b4b0 1326 "Return number of lines in buffer BUFFER."
cd2325cd 1327 (with-current-buffer buffer
5323b4b0 1328 (count-lines (point-min) (point-max))))
4bcbcb9d 1329
2aa13ec4 1330(defun flymake-get-point-pixel-pos ()
5323b4b0
RS
1331 "Return point position in pixels: (x, y)."
1332 (let ((mouse-pos (mouse-position))
1333 (pixel-pos nil)
1334 (ret nil))
1335 (if (car (cdr mouse-pos))
1336 (progn
1337 (set-mouse-position (flymake-selected-frame) (current-column) (flymake-current-row))
1338 (setq pixel-pos (mouse-pixel-position))
1339 (set-mouse-position (car mouse-pos) (car (cdr mouse-pos)) (cdr (cdr mouse-pos)))
1340 (setq ret (list (car (cdr pixel-pos)) (cdr (cdr pixel-pos)))))
1341 (progn
1342 (setq ret '(0 0))))
1343 (flymake-log 3 "mouse pos is %s" ret)
1344 ret))
4bcbcb9d 1345
2aa13ec4 1346(defun flymake-display-err-menu-for-current-line ()
5323b4b0
RS
1347 "Display a menu with errors/warnings for current line if it has errors and/or warnings."
1348 (interactive)
1349 (let* ((line-no (flymake-current-line-no))
53ec26ed 1350 (line-err-info-list (nth 0 (flymake-find-err-info flymake-err-info line-no)))
5323b4b0
RS
1351 (menu-data (flymake-make-err-menu-data line-no line-err-info-list))
1352 (choice nil)
1353 (mouse-pos (flymake-get-point-pixel-pos))
5323b4b0
RS
1354 (menu-pos (list (flymake-get-point-pixel-pos) (selected-window))))
1355 (if menu-data
1356 (progn
1357 (setq choice (flymake-popup-menu menu-pos menu-data))
1358 (flymake-log 3 "choice=%s" choice)
1359 (when choice
1360 (eval choice)))
1361 (flymake-log 1 "no errors for line %d" line-no))))
4bcbcb9d 1362
2aa13ec4 1363(defun flymake-make-err-menu-data (line-no line-err-info-list)
5323b4b0
RS
1364 "Make a (menu-title (item-title item-action)*) list with errors/warnings from line-err-info."
1365 (let* ((menu-items nil))
1366 (when line-err-info-list
1367 (let* ((count (length line-err-info-list))
1368 (menu-item-text nil))
1369 (while (> count 0)
1370 (setq menu-item-text (flymake-ler-get-text (nth (1- count) line-err-info-list)))
1371 (let* ((file (flymake-ler-get-file (nth (1- count) line-err-info-list)))
1372 (full-file (flymake-ler-get-full-file (nth (1- count) line-err-info-list)))
1373 (line (flymake-ler-get-line (nth (1- count) line-err-info-list))))
1374 (if file
1375 (setq menu-item-text (concat menu-item-text " - " file "(" (format "%d" line) ")")))
1376 (setq menu-items (cons (list menu-item-text
1377 (if file (list 'flymake-goto-file-and-line full-file line) nil))
1378 menu-items)))
1379 (setq count (1- count)))
1380 (flymake-log 3 "created menu-items with %d item(s)" (length menu-items))))
1381 (if menu-items
1382 (let* ((menu-title (format "Line %d: %d error(s), %d warning(s)" line-no
1383 (flymake-get-line-err-count line-err-info-list "e")
1384 (flymake-get-line-err-count line-err-info-list "w"))))
1385 (list menu-title menu-items))
1386 nil)))
4bcbcb9d 1387
2aa13ec4 1388(defun flymake-goto-file-and-line (file line)
9a686ad2 1389 "Try to get buffer for FILE and goto line LINE in it."
5323b4b0
RS
1390 (if (not (file-exists-p file))
1391 (flymake-log 1 "file %s does not exists" file)
1392 (progn
1393 (find-file file)
1394 (goto-line line))))
4bcbcb9d 1395
2aa13ec4 1396;; flymake minor mode declarations
4bd0a5d0 1397(defvar flymake-mode-line nil)
2aa13ec4 1398
4bcbcb9d 1399(make-variable-buffer-local 'flymake-mode-line)
2aa13ec4 1400
4bcbcb9d 1401(defvar flymake-mode-line-e-w nil)
2aa13ec4 1402
4bcbcb9d 1403(make-variable-buffer-local 'flymake-mode-line-e-w)
2aa13ec4 1404
4bcbcb9d 1405(defvar flymake-mode-line-status nil)
2aa13ec4 1406
4bcbcb9d 1407(make-variable-buffer-local 'flymake-mode-line-status)
4bcbcb9d 1408
2aa13ec4 1409(defun flymake-report-status (buffer e-w &optional status)
5323b4b0
RS
1410 "Show status in mode line."
1411 (when (bufferp buffer)
cd2325cd 1412 (with-current-buffer buffer
5323b4b0 1413 (when e-w
53ec26ed 1414 (setq flymake-mode-line-e-w e-w))
5323b4b0 1415 (when status
53ec26ed 1416 (setq flymake-mode-line-status status))
5323b4b0 1417 (let* ((mode-line " Flymake"))
53ec26ed
RS
1418 (when (> (length flymake-mode-line-e-w) 0)
1419 (setq mode-line (concat mode-line ":" flymake-mode-line-e-w)))
1420 (setq mode-line (concat mode-line flymake-mode-line-status))
1421 (setq flymake-mode-line mode-line)
5323b4b0 1422 (force-mode-line-update)))))
4bcbcb9d 1423
2aa13ec4 1424(defun flymake-display-warning (warning)
5323b4b0
RS
1425 "Display a warning to user."
1426 (message-box warning))
4bcbcb9d
EZ
1427
1428(defcustom flymake-gui-warnings-enabled t
5323b4b0
RS
1429 "Enables/disables gui warnings."
1430 :group 'flymake
1431 :type 'boolean)
4bcbcb9d 1432
2aa13ec4 1433(defun flymake-report-fatal-status (buffer status warning)
5323b4b0
RS
1434 "Display a warning and switch flymake mode off."
1435 (when flymake-gui-warnings-enabled
1436 (flymake-display-warning (format "Flymake: %s. Flymake will be switched OFF" warning))
1437 )
cd2325cd 1438 (with-current-buffer buffer
5323b4b0
RS
1439 (flymake-mode 0)
1440 (flymake-log 0 "switched OFF Flymake mode for buffer %s due to fatal status %s, warning %s"
1441 (buffer-name buffer) status warning)))
4bcbcb9d 1442
5ffc943b 1443;;;###autoload
4bd0a5d0
SM
1444(define-minor-mode flymake-mode
1445 "Minor mode to do on-the-fly syntax checking.
1446When called interactively, toggles the minor mode.
1447With arg, turn Flymake mode on if and only if arg is positive."
d799c278 1448 :group 'flymake :lighter flymake-mode-line
4bd0a5d0
SM
1449 (if flymake-mode
1450 (if (flymake-can-syntax-check-file (buffer-file-name))
1451 (flymake-mode-on)
1452 (flymake-log 2 "flymake cannot check syntax in buffer %s" (buffer-name)))
1453 (flymake-mode-off)))
2aa13ec4
RS
1454
1455(defcustom flymake-start-syntax-check-on-find-file t
5323b4b0
RS
1456 "Start syntax check on find file."
1457 :group 'flymake
1458 :type 'boolean)
4bcbcb9d 1459
4bcbcb9d 1460;;;###autoload
2aa13ec4 1461(defun flymake-mode-on ()
5323b4b0
RS
1462 "Turn flymake mode on."
1463 (when (not flymake-mode)
1464 (make-local-variable 'after-change-functions)
1465 (setq after-change-functions (cons 'flymake-after-change-function after-change-functions))
1466 (add-hook 'after-save-hook 'flymake-after-save-hook)
1467 (add-hook 'kill-buffer-hook 'flymake-kill-buffer-hook)
9a686ad2 1468 ;;+(add-hook 'find-file-hook 'flymake-find-file-hook)
4bcbcb9d 1469
5323b4b0 1470 (flymake-report-status (current-buffer) "" "")
4bcbcb9d 1471
53ec26ed
RS
1472 (setq flymake-timer
1473 (run-at-time nil 1 'flymake-on-timer-event (current-buffer)))
4bcbcb9d 1474
5323b4b0
RS
1475 (setq flymake-mode t)
1476 (flymake-log 1 "flymake mode turned ON for buffer %s" (buffer-name (current-buffer)))
1477 (when flymake-start-syntax-check-on-find-file
1478 (flymake-start-syntax-check-for-current-buffer)))) ; will be started by on-load hook
4bcbcb9d
EZ
1479
1480;;;###autoload
2aa13ec4 1481(defun flymake-mode-off ()
5323b4b0
RS
1482 "Turn flymake mode off."
1483 (when flymake-mode
1484 (setq after-change-functions (delq 'flymake-after-change-function after-change-functions))
1485 (remove-hook 'after-save-hook (function flymake-after-save-hook) t)
1486 (remove-hook 'kill-buffer-hook (function flymake-kill-buffer-hook) t)
9a686ad2 1487 ;;+(remove-hook 'find-file-hook (function flymake-find-file-hook) t)
4bcbcb9d 1488
5323b4b0 1489 (flymake-delete-own-overlays (current-buffer))
4bcbcb9d 1490
53ec26ed
RS
1491 (when flymake-timer
1492 (cancel-timer flymake-timer)
1493 (setq flymake-timer nil))
4bcbcb9d 1494
53ec26ed 1495 (setq flymake-is-running nil)
5323b4b0
RS
1496 (setq flymake-mode nil)
1497 (flymake-log 1 "flymake mode turned OFF for buffer %s" (buffer-name (current-buffer)))))
4bcbcb9d
EZ
1498
1499(defcustom flymake-start-syntax-check-on-newline t
5323b4b0
RS
1500 "Start syntax check if newline char was added/removed from the buffer."
1501 :group 'flymake
1502 :type 'boolean)
4bcbcb9d 1503
2aa13ec4 1504(defun flymake-after-change-function (start stop len)
9a686ad2
SM
1505 "Start syntax check for current buffer if it isn't already running."
1506 ;;+(flymake-log 0 "setting change time to %s" (flymake-float-time))
5323b4b0
RS
1507 (let((new-text (buffer-substring start stop)))
1508 (when (and flymake-start-syntax-check-on-newline (equal new-text "\n"))
1509 (flymake-log 3 "starting syntax check as new-line has been seen")
1510 (flymake-start-syntax-check-for-current-buffer))
53ec26ed 1511 (setq flymake-last-change-time (flymake-float-time))))
4bcbcb9d 1512
2aa13ec4 1513(defun flymake-after-save-hook ()
5323b4b0
RS
1514 (if (local-variable-p 'flymake-mode (current-buffer)) ; (???) other way to determine whether flymake is active in buffer being saved?
1515 (progn
1516 (flymake-log 3 "starting syntax check as buffer was saved")
1517 (flymake-start-syntax-check-for-current-buffer)))) ; no more mode 3. cannot start check if mode 3 (to temp copies) is active - (???)
4bcbcb9d 1518
2aa13ec4 1519(defun flymake-kill-buffer-hook ()
53ec26ed
RS
1520 (when flymake-timer
1521 (cancel-timer flymake-timer)
1522 (setq flymake-timer nil)))
4bcbcb9d 1523
2aa13ec4 1524(defun flymake-find-file-hook ()
9a686ad2
SM
1525 ;;+(when flymake-start-syntax-check-on-find-file
1526 ;;+ (flymake-log 3 "starting syntax check on file open")
1527 ;;+ (flymake-start-syntax-check-for-current-buffer)
1528 ;;+)
5323b4b0
RS
1529 (when (and (not (local-variable-p 'flymake-mode (current-buffer)))
1530 (flymake-can-syntax-check-file (buffer-file-name (current-buffer))))
1531 (flymake-mode)
1532 (flymake-log 3 "automatically turned ON flymake mode")))
4bcbcb9d 1533
2aa13ec4 1534(defun flymake-get-first-err-line-no (err-info-list)
5323b4b0
RS
1535 "Return first line with error."
1536 (when err-info-list
1537 (flymake-er-get-line (car err-info-list))))
4bcbcb9d 1538
2aa13ec4 1539(defun flymake-get-last-err-line-no (err-info-list)
5323b4b0
RS
1540 "Return last line with error."
1541 (when err-info-list
1542 (flymake-er-get-line (nth (1- (length err-info-list)) err-info-list))))
4bcbcb9d 1543
2aa13ec4 1544(defun flymake-get-next-err-line-no (err-info-list line-no)
5323b4b0
RS
1545 "Return next line with error."
1546 (when err-info-list
1547 (let* ((count (length err-info-list))
1548 (idx 0))
1549 (while (and (< idx count) (>= line-no (flymake-er-get-line (nth idx err-info-list))))
1550 (setq idx (1+ idx)))
1551 (if (< idx count)
1552 (flymake-er-get-line (nth idx err-info-list))))))
4bcbcb9d 1553
2aa13ec4 1554(defun flymake-get-prev-err-line-no (err-info-list line-no)
5323b4b0
RS
1555 "Return prev line with error."
1556 (when err-info-list
1557 (let* ((count (length err-info-list)))
1558 (while (and (> count 0) (<= line-no (flymake-er-get-line (nth (1- count) err-info-list))))
1559 (setq count (1- count)))
1560 (if (> count 0)
1561 (flymake-er-get-line (nth (1- count) err-info-list))))))
4bcbcb9d 1562
2aa13ec4 1563(defun flymake-skip-whitespace ()
5323b4b0
RS
1564 "Move forward until non-whitespace is reached."
1565 (while (looking-at "[ \t]")
1566 (forward-char)))
4bcbcb9d 1567
2aa13ec4 1568(defun flymake-goto-line (line-no)
9a686ad2 1569 "Go to line LINE-NO, then skip whitespace."
5323b4b0
RS
1570 (goto-line line-no)
1571 (flymake-skip-whitespace))
4bcbcb9d 1572
2aa13ec4 1573(defun flymake-goto-next-error ()
9a686ad2 1574 "Go to next error in err ring."
5323b4b0 1575 (interactive)
53ec26ed 1576 (let ((line-no (flymake-get-next-err-line-no flymake-err-info (flymake-current-line-no))))
5323b4b0 1577 (when (not line-no)
53ec26ed 1578 (setq line-no (flymake-get-first-err-line-no flymake-err-info))
5323b4b0
RS
1579 (flymake-log 1 "passed end of file"))
1580 (if line-no
1581 (flymake-goto-line line-no)
1582 (flymake-log 1 "no errors in current buffer"))))
4bcbcb9d 1583
2aa13ec4 1584(defun flymake-goto-prev-error ()
9a686ad2 1585 "Go to prev error in err ring."
5323b4b0 1586 (interactive)
53ec26ed 1587 (let ((line-no (flymake-get-prev-err-line-no flymake-err-info (flymake-current-line-no))))
5323b4b0 1588 (when (not line-no)
53ec26ed 1589 (setq line-no (flymake-get-last-err-line-no flymake-err-info))
5323b4b0
RS
1590 (flymake-log 1 "passed beginning of file"))
1591 (if line-no
1592 (flymake-goto-line line-no)
1593 (flymake-log 1 "no errors in current buffer"))))
4bcbcb9d 1594
2aa13ec4 1595(defun flymake-patch-err-text (string)
5323b4b0
RS
1596 (if (string-match "^[\n\t :0-9]*\\(.*\\)$" string)
1597 (match-string 1 string)
1598 string))
4bcbcb9d
EZ
1599
1600;;;; general init-cleanup and helper routines
2aa13ec4 1601(defun flymake-create-temp-inplace (file-name prefix)
5323b4b0
RS
1602 (unless (stringp file-name)
1603 (error "Invalid file-name"))
1604 (or prefix
1605 (setq prefix "flymake"))
1606 (let* ((temp-name (concat (file-name-sans-extension file-name)
1607 "_" prefix
1608 (and (file-name-extension file-name)
1609 (concat "." (file-name-extension file-name))))))
1610 (flymake-log 3 "create-temp-inplace: file=%s temp=%s" file-name temp-name)
1611 temp-name))
4bcbcb9d 1612
2aa13ec4 1613(defun flymake-create-temp-with-folder-structure (file-name prefix)
5323b4b0
RS
1614 (unless (stringp file-name)
1615 (error "Invalid file-name"))
4bcbcb9d 1616
5323b4b0
RS
1617 (let* ((dir (file-name-directory file-name))
1618 (slash-pos (string-match "/" dir))
4bd0a5d0 1619 (temp-dir (concat (file-name-as-directory (flymake-get-temp-dir)) (substring dir (1+ slash-pos)))))
4bcbcb9d 1620
4bd0a5d0 1621 (file-truename (concat (file-name-as-directory temp-dir)
5323b4b0 1622 (file-name-nondirectory file-name)))))
4bcbcb9d 1623
2aa13ec4 1624(defun flymake-strrchr (str ch)
5323b4b0
RS
1625 (let* ((count (length str))
1626 (pos nil))
1627 (while (and (not pos) (> count 0))
1628 (if (= ch (elt str (1- count)))
1629 (setq pos (1- count)))
1630 (setq count (1- count)))
1631 pos))
4bcbcb9d 1632
2aa13ec4 1633(defun flymake-delete-temp-directory (dir-name)
9a686ad2 1634 "Attempt to delete temp dir created by `flymake-create-temp-with-folder-structure', do not fail on error."
5323b4b0
RS
1635 (let* ((temp-dir (flymake-get-temp-dir))
1636 (suffix (substring dir-name (1+ (length temp-dir))))
1637 (slash-pos nil))
1638
1639 (while (> (length suffix) 0)
9a686ad2 1640 ;;+(flymake-log 0 "suffix=%s" suffix)
4bd0a5d0 1641 (flymake-safe-delete-directory (file-truename (concat (file-name-as-directory temp-dir) suffix)))
5323b4b0
RS
1642 (setq slash-pos (flymake-strrchr suffix (string-to-char "/")))
1643 (if slash-pos
1644 (setq suffix (substring suffix 0 slash-pos))
1645 (setq suffix "")))))
4bcbcb9d 1646
2aa13ec4 1647(defun flymake-init-create-temp-buffer-copy (buffer create-temp-f)
5323b4b0
RS
1648 "Make a temporary copy of the current buffer, save its name in buffer data and return the name."
1649 (let* ((source-file-name (buffer-file-name buffer))
1650 (temp-source-file-name (funcall create-temp-f source-file-name "flymake")))
4bcbcb9d 1651
5323b4b0
RS
1652 (flymake-save-buffer-in-file buffer temp-source-file-name)
1653 (flymake-set-buffer-value buffer "temp-source-file-name" temp-source-file-name)
1654 temp-source-file-name))
4bcbcb9d 1655
2aa13ec4 1656(defun flymake-simple-cleanup (buffer)
5323b4b0 1657 "Do cleanup after 'flymake-init-create-temp-buffer-copy'.
2aa13ec4 1658Delete temp file."
5323b4b0
RS
1659 (let* ((temp-source-file-name (flymake-get-buffer-value buffer "temp-source-file-name")))
1660 (flymake-safe-delete-file temp-source-file-name)
53ec26ed
RS
1661 (with-current-buffer buffer
1662 (setq flymake-last-change-time nil))))
4bcbcb9d 1663
2aa13ec4 1664(defun flymake-get-real-file-name (buffer file-name-from-err-msg)
9a686ad2
SM
1665 "Translate file name from error message to \"real\" file name.
1666Return full-name. Names are real, not patched."
5323b4b0
RS
1667 (let* ((real-name nil)
1668 (source-file-name (buffer-file-name buffer))
1669 (master-file-name (flymake-get-buffer-value buffer "master-file-name"))
1670 (temp-source-file-name (flymake-get-buffer-value buffer "temp-source-file-name"))
1671 (temp-master-file-name (flymake-get-buffer-value buffer "temp-master-file-name"))
1672 (base-dirs (list (flymake-get-buffer-value buffer "base-dir")
1673 (file-name-directory source-file-name)
1674 (if master-file-name (file-name-directory master-file-name) nil)))
1675 (files (list (list source-file-name source-file-name)
1676 (list temp-source-file-name source-file-name)
1677 (list master-file-name master-file-name)
1678 (list temp-master-file-name master-file-name))))
1679
1680 (when (equal 0 (length file-name-from-err-msg))
1681 (setq file-name-from-err-msg source-file-name))
1682
1683 (setq real-name (flymake-get-full-patched-file-name file-name-from-err-msg base-dirs files))
9a686ad2 1684 ;; if real-name is nil, than file name from err msg is none of the files we've patched
5323b4b0
RS
1685 (if (not real-name)
1686 (setq real-name (flymake-get-full-nonpatched-file-name file-name-from-err-msg base-dirs)))
1687 (if (not real-name)
1688 (setq real-name file-name-from-err-msg))
1689 (setq real-name (flymake-fix-file-name real-name))
1690 (flymake-log 3 "get-real-file-name: file-name=%s real-name=%s" file-name-from-err-msg real-name)
1691 real-name))
4bcbcb9d 1692
2aa13ec4 1693(defun flymake-get-full-patched-file-name (file-name-from-err-msg base-dirs files)
5323b4b0
RS
1694 (let* ((base-dirs-count (length base-dirs))
1695 (file-count (length files))
1696 (real-name nil))
1697
1698 (while (and (not real-name) (> base-dirs-count 0))
1699 (setq file-count (length files))
1700 (while (and (not real-name) (> file-count 0))
1701 (let* ((this-dir (nth (1- base-dirs-count) base-dirs))
1702 (this-file (nth 0 (nth (1- file-count) files)))
1703 (this-real-name (nth 1 (nth (1- file-count) files))))
9a686ad2 1704 ;;+(flymake-log 0 "this-dir=%s this-file=%s this-real=%s msg-file=%s" this-dir this-file this-real-name file-name-from-err-msg)
5323b4b0 1705 (when (and this-dir this-file (flymake-same-files
b8471a02 1706 (expand-file-name file-name-from-err-msg this-dir)
5323b4b0
RS
1707 this-file))
1708 (setq real-name this-real-name)))
1709 (setq file-count (1- file-count)))
1710 (setq base-dirs-count (1- base-dirs-count)))
1711 real-name))
4bcbcb9d 1712
2aa13ec4 1713(defun flymake-get-full-nonpatched-file-name (file-name-from-err-msg base-dirs)
5323b4b0
RS
1714 (let* ((real-name nil))
1715 (if (file-name-absolute-p file-name-from-err-msg)
1716 (setq real-name file-name-from-err-msg)
1717 (let* ((base-dirs-count (length base-dirs)))
1718 (while (and (not real-name) (> base-dirs-count 0))
b8471a02
SM
1719 (let* ((full-name (expand-file-name file-name-from-err-msg
1720 (nth (1- base-dirs-count) base-dirs))))
5323b4b0
RS
1721 (if (file-exists-p full-name)
1722 (setq real-name full-name))
1723 (setq base-dirs-count (1- base-dirs-count))))))
1724 real-name))
4bcbcb9d 1725
2aa13ec4 1726(defun flymake-init-find-buildfile-dir (buffer source-file-name buildfile-name)
5323b4b0
RS
1727 "Find buildfile, store its dir in buffer data and return its dir, if found."
1728 (let* ((buildfile-dir (flymake-find-buildfile buildfile-name
1729 (file-name-directory source-file-name)
1730 flymake-buildfile-dirs)))
1731 (if (not buildfile-dir)
1732 (progn
1733 (flymake-log 1 "no buildfile (%s) for %s" buildfile-name source-file-name)
1734 (flymake-report-fatal-status buffer "NOMK" (format "No buildfile (%s) found for %s" buildfile-name source-file-name))
1735 )
1736 (progn
1737 (flymake-set-buffer-value buffer "base-dir" buildfile-dir)))
1738 buildfile-dir))
4bcbcb9d 1739
2aa13ec4 1740(defun flymake-init-create-temp-source-and-master-buffer-copy (buffer get-incl-dirs-f create-temp-f master-file-masks include-regexp-list)
5323b4b0
RS
1741 "Find master file (or buffer), create it's copy along with a copy of the source file."
1742 (let* ((source-file-name (buffer-file-name buffer))
1743 (temp-source-file-name (flymake-init-create-temp-buffer-copy buffer create-temp-f))
1744 (master-file-name nil)
1745 (temp-master-file-name nil)
1746 (master-and-temp-master (flymake-create-master-file
1747 source-file-name temp-source-file-name
1748 get-incl-dirs-f create-temp-f
1749 master-file-masks include-regexp-list)))
1750
1751 (if (not master-and-temp-master)
1752 (progn
1753 (flymake-log 1 "cannot find master file for %s" source-file-name)
1754 (flymake-report-status buffer "!" "") ; NOMASTER
1755 )
1756 (progn
1757 (setq master-file-name (nth 0 master-and-temp-master))
1758 (setq temp-master-file-name (nth 1 master-and-temp-master))
1759 (flymake-set-buffer-value buffer "master-file-name" master-file-name)
1760 (flymake-set-buffer-value buffer "temp-master-file-name" temp-master-file-name)
1761 ))
1762 temp-master-file-name))
4bcbcb9d 1763
2aa13ec4 1764(defun flymake-master-cleanup (buffer)
5323b4b0
RS
1765 (flymake-simple-cleanup buffer)
1766 (flymake-safe-delete-file (flymake-get-buffer-value buffer "temp-master-file-name")))
4bcbcb9d
EZ
1767
1768;;;; make-specific init-cleanup routines
2aa13ec4 1769(defun flymake-get-syntax-check-program-args (source-file-name base-dir use-relative-base-dir use-relative-source get-cmd-line-f)
5323b4b0
RS
1770 "Create a command line for syntax check using GET-CMD-LINE-F."
1771 (let* ((my-base-dir base-dir)
1772 (my-source source-file-name))
4bcbcb9d 1773
5323b4b0
RS
1774 (when use-relative-base-dir
1775 (setq my-base-dir (flymake-build-relative-filename (file-name-directory source-file-name) base-dir)))
4bcbcb9d 1776
5323b4b0
RS
1777 (when use-relative-source
1778 (setq my-source (concat (flymake-build-relative-filename base-dir (file-name-directory source-file-name))
1779 (file-name-nondirectory source-file-name))))
1780 (funcall get-cmd-line-f my-source my-base-dir)))
4bcbcb9d 1781
2aa13ec4 1782(defun flymake-get-make-cmdline (source base-dir)
5323b4b0
RS
1783 (list "make"
1784 (list "-s"
1785 "-C"
1786 base-dir
1787 (concat "CHK_SOURCES=" source)
1788 "SYNTAX_CHECK_MODE=1"
1789 "check-syntax")))
4bcbcb9d 1790
2aa13ec4 1791(defun flymake-get-ant-cmdline (source base-dir)
5323b4b0
RS
1792 (list "ant"
1793 (list "-buildfile"
1794 (concat base-dir "/" "build.xml")
1795 (concat "-DCHK_SOURCES=" source)
1796 "check-syntax")))
4bcbcb9d 1797
2aa13ec4 1798(defun flymake-simple-make-init-impl (buffer create-temp-f use-relative-base-dir use-relative-source build-file-name get-cmdline-f)
5323b4b0 1799 "Create syntax check command line for a directly checked source file.
2aa13ec4 1800Use CREATE-TEMP-F for creating temp copy."
5323b4b0
RS
1801 (let* ((args nil)
1802 (source-file-name (buffer-file-name buffer))
1803 (buildfile-dir (flymake-init-find-buildfile-dir buffer source-file-name build-file-name)))
1804 (if buildfile-dir
1805 (let* ((temp-source-file-name (flymake-init-create-temp-buffer-copy buffer create-temp-f)))
1806 (setq args (flymake-get-syntax-check-program-args temp-source-file-name buildfile-dir
1807 use-relative-base-dir use-relative-source
1808 get-cmdline-f))))
1809 args))
4bcbcb9d 1810
2aa13ec4 1811(defun flymake-simple-make-init (buffer)
5323b4b0 1812 (flymake-simple-make-init-impl buffer 'flymake-create-temp-inplace t t "Makefile" 'flymake-get-make-cmdline))
4bcbcb9d 1813
2aa13ec4 1814(defun flymake-master-make-init (buffer get-incl-dirs-f master-file-masks include-regexp-list)
9a686ad2 1815 "Create make command line for a source file checked via master file compilation."
5323b4b0
RS
1816 (let* ((make-args nil)
1817 (temp-master-file-name (flymake-init-create-temp-source-and-master-buffer-copy
1818 buffer get-incl-dirs-f 'flymake-create-temp-inplace
1819 master-file-masks include-regexp-list)))
1820 (when temp-master-file-name
1821 (let* ((buildfile-dir (flymake-init-find-buildfile-dir buffer temp-master-file-name "Makefile")))
1822 (if buildfile-dir
1823 (setq make-args (flymake-get-syntax-check-program-args
1824 temp-master-file-name buildfile-dir nil nil 'flymake-get-make-cmdline)))))
1825 make-args))
4bcbcb9d 1826
2aa13ec4 1827(defun flymake-find-make-buildfile (source-dir)
5323b4b0 1828 (flymake-find-buildfile "Makefile" source-dir flymake-buildfile-dirs))
4bcbcb9d
EZ
1829
1830;;;; .h/make specific
2aa13ec4 1831(defun flymake-master-make-header-init (buffer)
5323b4b0
RS
1832 (flymake-master-make-init buffer
1833 'flymake-get-include-dirs
1834 '(".+\\.cpp$" ".+\\.c$")
1835 '("[ \t]*#[ \t]*include[ \t]*\"\\([\w0-9/\\_\.]*[/\\]*\\)\\(%s\\)\"" 1 2)))
4bcbcb9d
EZ
1836
1837;;;; .java/make specific
2aa13ec4 1838(defun flymake-simple-make-java-init (buffer)
5323b4b0 1839 (flymake-simple-make-init-impl buffer 'flymake-create-temp-with-folder-structure nil nil "Makefile" 'flymake-get-make-cmdline))
4bcbcb9d 1840
2aa13ec4 1841(defun flymake-simple-ant-java-init (buffer)
5323b4b0 1842 (flymake-simple-make-init-impl buffer 'flymake-create-temp-with-folder-structure nil nil "build.xml" 'flymake-get-ant-cmdline))
4bcbcb9d 1843
2aa13ec4 1844(defun flymake-simple-java-cleanup (buffer)
9a686ad2 1845 "Cleanup after `flymake-simple-make-java-init' -- delete temp file and dirs."
5323b4b0
RS
1846 (let* ((temp-source-file-name (flymake-get-buffer-value buffer "temp-source-file-name")))
1847 (flymake-safe-delete-file temp-source-file-name)
1848 (when temp-source-file-name
1849 (flymake-delete-temp-directory (file-name-directory temp-source-file-name)))))
4bcbcb9d
EZ
1850
1851;;;; perl-specific init-cleanup routines
2aa13ec4 1852(defun flymake-perl-init (buffer)
4bd0a5d0
SM
1853 (let* ((temp-file (flymake-init-create-temp-buffer-copy
1854 buffer 'flymake-create-temp-inplace))
1855 (local-file (concat (flymake-build-relative-filename
1856 (file-name-directory buffer-file-name)
1857 (file-name-directory temp-file))
5323b4b0
RS
1858 (file-name-nondirectory temp-file))))
1859 (list "perl" (list "-wc " local-file))))
4bcbcb9d
EZ
1860
1861;;;; tex-specific init-cleanup routines
2aa13ec4 1862(defun flymake-get-tex-args (file-name)
9a686ad2 1863 ;;(list "latex" (list "-c-style-errors" file-name))
5323b4b0 1864 (list "texify" (list "--pdf" "--tex-option=-c-style-errors" file-name)))
4bcbcb9d 1865
2aa13ec4 1866(defun flymake-simple-tex-init (buffer)
5323b4b0 1867 (flymake-get-tex-args (flymake-init-create-temp-buffer-copy buffer 'flymake-create-temp-inplace)))
4bcbcb9d 1868
2aa13ec4 1869(defun flymake-master-tex-init (buffer)
5323b4b0
RS
1870 (let* ((temp-master-file-name (flymake-init-create-temp-source-and-master-buffer-copy
1871 buffer 'flymake-get-include-dirs-dot 'flymake-create-temp-inplace
1872 '(".+\\.tex$")
1873 '("[ \t]*\\input[ \t]*{\\(.*\\)\\(%s\\)}" 1 2))))
1874 (when temp-master-file-name
1875 (flymake-get-tex-args temp-master-file-name))))
4bcbcb9d 1876
2aa13ec4 1877(defun flymake-get-include-dirs-dot (base-dir)
5323b4b0 1878 '("."))
4bcbcb9d
EZ
1879
1880;;;; xml-specific init-cleanup routines
4bd0a5d0 1881(defun flymake-xml-init (buffer)
5323b4b0 1882 (list "xml" (list "val" (flymake-init-create-temp-buffer-copy buffer 'flymake-create-temp-inplace))))
2aa13ec4
RS
1883
1884(provide 'flymake)
4bcbcb9d 1885
9a686ad2 1886;; arch-tag: 8f0d6090-061d-4cac-8862-7c151c4a02dd
4bcbcb9d 1887;;; flymake.el ends here