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