home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / elisp / misc / mult-compile.el < prev    next >
Encoding:
Text File  |  1991-06-14  |  31.5 KB  |  724 lines

  1. ; Path: dg-rtp!rock.concert.net!mcnc!stanford.edu!bu.edu!dimacs.rutgers.edu!mips!zaphod.mps.ohio-state.edu!wuarchive!uunet!wsrcc.com!wolfgang
  2. ; From: wolfgang@wsrcc.com (Wolfgang S. Rupprecht)
  3. ; Newsgroups: comp.emacs,comp.unix.aix,gnu.emacs.sources
  4. ; Subject: Re: GNU Emacs with xlc on AIX3.1 Was: Shutdown: EMACS vs. vi
  5. ; Date: 6 Jun 91 15:39:08 GMT
  6. ; References: <2995.9106031725@seq.hull.ac.uk> <1991Jun04.063328.21379@lynx.CS.ORST.EDU> <Q=4_#5@uzi-9mm.fulcrum.bt.co.uk>
  7. ; Organization: Wolfgang S Rupprecht Computer Consulting, Washington DC.
  8. ; igb@fulcrum.bt.co.uk (Ian G Batten) writes:
  9. ; >> Speaking of line number and related stuff, is there a way to let the GNU
  10. ; >> Emacs 18.57 to understand the error messages from cc on AIX 3.1? 
  11. ; >I'm on the point of writing the code to do this.  Has anyone else
  12. ; >started?
  13. ; Ok, I'll bite.  
  14. ; Here is a general error message parser that I have been using in
  15. ; various forms since 1987.  It is all table driven and adding another
  16. ; parser template is as trivial as adding one regexp to describe the
  17. ; error output.
  18. ; It already knows about most errors that I have needed to parse.  In
  19. ; addition it does 3-window hacks for lint's inconsistent usage
  20. ; messages.  It can also hunt for files (as in make's "Make: error on
  21. ; line 31" type errors, or the brain damaged multi-line System V lint
  22. ; output.)
  23. ; Unlike the normal emacs function, this next error is cursor-driven,
  24. ; and doesn't pre-parse any errors.  One can select an error message by
  25. ; moving the cursor to the line *above* the desired message and invoking
  26. ; next-error.
  27. ; This file also contains a multiple *compilation* buffer hack.  This
  28. ; allows one to compile in one buffer, grep in another, and watch
  29. ; something else in a third.  One selects the current compilation buffer
  30. ; (for next-error use) by typing "C-u C-x `" from inside the buffer one
  31. ; wants to select.  (Anyone have any good ideas on how to input &optional
  32. ; args from (interactive)?  Perhaps a "M-x command<space>option" syntax?)
  33. ; I normally start off a compilation and then rename the *compilation*
  34. ; buffer to be something more descriptive (eg. *make-dirname* ,
  35. ; *grep-dirname*, *lint-dirname*, etc.).  This is just the thing when
  36. ; one has greps of several source trees, and a few compiles active and
  37. ; needs to switch between them.
  38. ; One can also have wrappers to start up compilations in different
  39. ; buffers as in:
  40. ;     (defun gidbuild (command)
  41. ;       (interactive (list (read-input "Run gid (with args): "
  42. ;                      (symbol-around-point))))
  43. ;       (let ((default-directory (substitute-in-file-name "$BUILD")))
  44. ;       (compile1 (concat "gid " command)
  45. ;         "No more gidbuild hits" "gidbuild" "*gidbuild*")))
  46. ; To install it just put the the rest of the message into a single file
  47. ; called 'compile.el' somewhere in your emacs load-path.
  48. ; -wolfgang
  49. ; ---
  50. ; Wolfgang Rupprecht    wolfgang@wsrcc.com (or) uunet!wsrcc!wolfgang
  51. ; Snail Mail Address:   Box 6524, Alexandria, VA 22306-0524
  52.  
  53. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  54. ;;                                                                           ;;
  55. ;;      File:     mult-compile.el                                            ;;
  56. ;;      Author:   Wolfgang S Rupprecht <wolfgang@wsrcc.com>                  ;;
  57. ;;      Created:  Wed Jan 30 15:51:48 EST 1991                               ;;
  58. ;;      Contents: Gnu compile.el with multiple process interface             ;;
  59. ;;                                                                           ;;
  60. ;;      Copyright (c) 1991 Wolfgang S Rupprecht.                             ;;
  61. ;;                                                                           ;;
  62. ;;      $Header$                                                             ;;
  63. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  64. ;; Run compiler as inferior of Emacs, and parse its error messages.
  65. ;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
  66.  
  67. ;; This file is part of GNU Emacs.
  68.  
  69. ;; GNU Emacs is distributed in the hope that it will be useful,
  70. ;; but WITHOUT ANY WARRANTY.  No author or distributor
  71. ;; accepts responsibility to anyone for the consequences of using it
  72. ;; or for whether it serves any particular purpose or works at all,
  73. ;; unless he says so in writing.  Refer to the GNU Emacs General Public
  74. ;; License for full details.
  75.  
  76. ;; Everyone is granted permission to copy, modify and redistribute
  77. ;; GNU Emacs, but only under the conditions described in the
  78. ;; GNU Emacs General Public License.   A copy of this license is
  79. ;; supposed to have been given to you along with GNU Emacs so you
  80. ;; can know your rights and responsibilities.  It should be in a
  81. ;; file named COPYING.  Among other things, the copyright notice
  82. ;; and this notice must be preserved on all copies.
  83.  
  84. (provide 'compile)
  85.  
  86. ;; make a more general purpose compilation interface.
  87. ;; 1. make compilation-process be buffer-local. (for buffer->process mapping)
  88. ;; 2. use the (process-buffer) for process->buffer mapping.
  89. ;; 3. make compilation-error-message be a buffer local variable.
  90.  
  91. ;; user preference configurations
  92.  
  93. (defvar compile-sets-error-buf t
  94.   "*A compile command will set the error buf.")
  95.  
  96. ;; end user configurations
  97.  
  98. (defvar compilation-process nil
  99.   "Process created by compile command, or nil if none exists now.
  100. Note that the process may have been \"deleted\" and still
  101. be the value of this variable.")
  102.  
  103. ;; this isn't used in any meaningful way - kept here for
  104. ;; reasons of minimum change.
  105.  
  106. (defvar compilation-error-list nil
  107.   "List of error message descriptors for visiting erring functions.
  108. Each error descriptor is a list of length two.
  109. Its car is a marker pointing to an error message.
  110. Its cadr is a marker pointing to the text of the line the message is about,
  111.   or nil if that is not interesting.
  112. The value may be t instead of a list;
  113. this means that the buffer of error messages should be reparsed
  114. the next time the list of errors is wanted.")
  115.  
  116. ;; not really used.
  117. (defvar compilation-parsing-end nil
  118.   "Position of end of buffer when last error messages parsed.")
  119.  
  120. ;; make this buffer local
  121. (defvar compilation-error-message nil
  122.   "Message to print when no more matches for compilation-error-regexp are found")
  123.  
  124. ;; The filename excludes colons to avoid confusion when error message
  125. ;; starts with digits.
  126. (defvar compilation-error-regexp
  127.   "\\([^ :\n]+\\(: *\\|, line \\|(\\)[0-9]+\\)\\|\\([0-9]+ *of *[^ \n]+\\)"
  128.   "Regular expression for filename/linenumber in error in compilation log.")
  129.  
  130. (defvar last-compilation-buffer "*compilation*")
  131.  
  132. (defun compile (command &optional buf)
  133.  
  134.   "NEW COMPILE:Compile the program including the current buffer.
  135. Default: run `make'.  Runs COMMAND, a shell command, in a separate
  136. process asynchronously with output going a buffer (*compilation* by
  137. default).  You can then use the command \\[next-error] to find the
  138. next error message and move to the source code that caused it.
  139.  
  140. Optional ARG is the buffer or name of the buffer to use for output. If
  141. interactive, C-u will cause command to prompt for filename.  Default
  142. is the last compilation buffer's name."
  143.  
  144.   (interactive (list (read-string "Compile command: " compile-command)
  145.                      (if current-prefix-arg
  146.                          (read-string "Compilation buffer: "
  147.                                       last-compilation-buffer))))
  148.   (setq compile-command command)
  149.   (if buf
  150.       (setq last-compilation-buffer buf)
  151.     (setq buf last-compilation-buffer))
  152.    (compile1 compile-command "No more errors" nil buf))
  153.  
  154. ; (defun grep (command)
  155. ;   "Run grep, with user-specified args, and collect output in a buffer.
  156. ; While grep runs asynchronously, you can use the \\[next-error] command
  157. ; to find the text that grep hits refer to."
  158. ;   (interactive "sRun grep (with args): ")
  159. ;   (compile1 (concat "grep -n " command " /dev/null")
  160. ;           "No more grep hits" "grep")))
  161.  
  162. (defun compile1 (command error-message &optional name-of-mode comp-buf)
  163.   "Multi-Buffer version of compile1"
  164.   (save-some-buffers)
  165.   (setq comp-buf (get-buffer-create (or comp-buf "*compilation*")))
  166.   (let ((cwd default-directory)         ; catch that slipery animal
  167.         (regexp compilation-error-regexp)
  168.         (comp-buf-name (buffer-name comp-buf))
  169.     (watch-flag (eq comp-buf (current-buffer))))
  170.     (save-excursion
  171.       (set-buffer comp-buf)
  172.       (setq default-directory cwd)      ; and restore...
  173.       (if compilation-process
  174.           (if (or (not (eq (process-status compilation-process) 'run))
  175.                   (yes-or-no-p
  176.                    "A compilation process is running in this buffer; kill it? "
  177.                    ))
  178.               (condition-case ()
  179.                   (let ((comp-proc compilation-process))
  180.                     (interrupt-process comp-proc)
  181.                     (sit-for 1)
  182.                     (delete-process comp-proc))
  183.                 (error nil))
  184.             (error "Cannot have two processes in one buffer!")))
  185.  
  186.       (if compile-sets-error-buf
  187.       (setq last-error-buf comp-buf-name))
  188.  
  189.       (fundamental-mode)
  190.       (buffer-flush-undo comp-buf)
  191.  
  192.       (setq mode-name (or name-of-mode "Compilation"))
  193.       ;; Make log buffer's mode line show process state
  194.       (setq mode-line-process '(": %s"))
  195.  
  196.       (make-local-variable 'compilation-process)
  197.       (setq compilation-process nil)
  198.  
  199.       (make-local-variable 'compilation-error-message)
  200.       (setq compilation-error-message error-message)
  201.  
  202.       (make-local-variable 'compilation-error-regexp)
  203.       (setq compilation-error-regexp regexp)
  204.  
  205.       (compilation-forget-errors)
  206.       (setq compilation-error-list t)
  207.  
  208.       (setq compilation-process
  209.             (start-process "compilation" comp-buf
  210.                            shell-file-name
  211.                            "-c" (concat "exec " command)))
  212.       ;; side effects: erase buffer, pop up buffer in other window 
  213.       (with-output-to-temp-buffer comp-buf-name
  214.         (princ mode-name)
  215.         (princ " started at ")
  216.         (princ (substring (current-time-string) 0 -5))
  217.         (terpri)
  218.         (princ "cd ")
  219.         (princ default-directory)
  220.         (terpri)
  221.         (princ command)
  222.         (terpri))
  223.       (set-process-sentinel compilation-process 'compilation-sentinel))
  224.     (if watch-flag (goto-char (point-max)))))
  225.  
  226. ;; Called when compilation process changes state.
  227.  
  228. (defun compilation-sentinel (proc msg)
  229.   (cond ((null (buffer-name (process-buffer proc)))
  230.          ;; buffer killed
  231.          (set-process-buffer proc nil))
  232.         ((memq (process-status proc) '(signal exit))
  233.          (let* ((obuf (current-buffer))
  234.                 omax opoint)
  235.            ;; save-excursion isn't the right thing if
  236.            ;;  process-buffer is current-buffer
  237.            (unwind-protect
  238.                (progn
  239.                  ;; Write something in *compilation* and hack its mode line,
  240.                  (set-buffer (process-buffer proc))
  241.                  (setq omax (point-max) opoint (point))
  242.                  (goto-char (point-max))
  243.                  (insert ?\n mode-name " " msg)
  244.                  (forward-char -1)
  245.                  (insert " at "
  246.                          (substring (current-time-string) 0 -5))
  247.                  (forward-char 1)
  248.                  (setq mode-line-process
  249.                        (concat ": "
  250.                                (symbol-name (process-status proc))))
  251.                  ;; If buffer and mode line will show that the process
  252.                  ;; is dead, we can delete it now.  Otherwise it
  253.                  ;; will stay around until M-x list-processes.
  254.                  (delete-process proc))
  255.              (setq compilation-process nil)
  256.              ;; Force mode line redisplay soon
  257.              (set-buffer-modified-p (buffer-modified-p)))
  258.            (if (and opoint (< opoint omax))
  259.                (goto-char opoint))
  260.            (set-buffer obuf)))))
  261.  
  262. (defun kill-compilation ()
  263.   "Kill the process made by the \\[compile] command."
  264.   (interactive)
  265.   (if compilation-process
  266.       (interrupt-process compilation-process)
  267.     (error "This buffer doesn't have a compilation process!")))
  268.  
  269. (defun kill-grep ()
  270.   "Kill the process made by the \\[grep] command."
  271.   (interactive)
  272.   (if compilation-process
  273.       (interrupt-process compilation-process)
  274.     (error "This buffer doesn't have a compilation process!")))
  275.  
  276. (defun next-error (&optional argp)
  277.   "Visit next compilation error message and corresponding source code.
  278. This operates on the output from the \\[compile] command.
  279. If all preparsed error messages have been processed,
  280. the error message buffer is checked for new ones.
  281. A non-nil argument (prefix arg, if interactive)
  282. means reparse the error message buffer and start at the first error."
  283.   (interactive "P")
  284.   (if (or (eq compilation-error-list t)
  285.           argp)
  286.       (progn (compilation-forget-errors)
  287.              (setq compilation-parsing-end 1)))
  288.   (if compilation-error-list
  289.       nil
  290.     (save-excursion
  291.       (switch-to-buffer "*compilation*")
  292.       (set-buffer-modified-p nil)
  293.       (compilation-parse-errors)))
  294.   (let ((next-error (car compilation-error-list)))
  295.     (if (null next-error)
  296.         (error (concat compilation-error-message
  297.                        (if (and compilation-process
  298.                                 (eq (process-status compilation-process)
  299.                                     'run))
  300.                            " yet" ""))))
  301.     (setq compilation-error-list (cdr compilation-error-list))
  302.     (if (null (car (cdr next-error)))
  303.         nil
  304.       (switch-to-buffer (marker-buffer (car (cdr next-error))))
  305.       (goto-char (car (cdr next-error)))
  306.       (set-marker (car (cdr next-error)) nil))
  307.     (let* ((pop-up-windows t)
  308.            (w (display-buffer (marker-buffer (car next-error)))))
  309.       (set-window-point w (car next-error))
  310.       (set-window-start w (car next-error)))
  311.     (set-marker (car next-error) nil)))
  312.  
  313. ;; Set compilation-error-list to nil, and
  314. ;; unchain the markers that point to the error messages and their text,
  315. ;; so that they no longer slow down gap motion.
  316. ;; This would happen anyway at the next garbage collection,
  317. ;; but it is better to do it right away.
  318. (defun compilation-forget-errors ()
  319.   (if (eq compilation-error-list t)
  320.       (setq compilation-error-list nil))
  321.   (while compilation-error-list
  322.     (let ((next-error (car compilation-error-list)))
  323.       (set-marker (car next-error) nil)
  324.       (if (car (cdr next-error))
  325.           (set-marker (car (cdr next-error)) nil)))
  326.     (setq compilation-error-list (cdr compilation-error-list))))
  327.  
  328. (defun compilation-parse-errors ()
  329.   "Parse the current buffer as error messages.
  330. This makes a list of error descriptors, compilation-error-list.
  331. For each source-file, line-number pair in the buffer,
  332. the source file is read in, and the text location is saved in compilation-error-list.
  333. The function next-error, assigned to \\[next-error], takes the next error off the list
  334. and visits its location."
  335.   (setq compilation-error-list nil)
  336.   (message "Parsing error messages...")
  337.   (let (text-buffer
  338.         last-filename last-linenum)
  339.     ;; Don't reparse messages already seen at last parse.
  340.     (goto-char compilation-parsing-end)
  341.     ;; Don't parse the first two lines as error messages.
  342.     ;; This matters for grep.
  343.     (if (bobp)
  344.         (forward-line 2))
  345.     (while (re-search-forward compilation-error-regexp nil t)
  346.       (let (linenum filename
  347.             error-marker text-marker)
  348.         ;; Extract file name and line number from error message.
  349.         (save-restriction
  350.           (narrow-to-region (match-beginning 0) (match-end 0))
  351.           (goto-char (point-max))
  352.           (skip-chars-backward "[0-9]")
  353.           ;; If it's a lint message, use the last file(linenum) on the line.
  354.           ;; Normally we use the first on the line.
  355.           (if (= (preceding-char) ?\()
  356.               (progn
  357.                 (narrow-to-region (point-min) (1+ (buffer-size)))
  358.                 (end-of-line)
  359.                 (re-search-backward compilation-error-regexp)
  360.                 (skip-chars-backward "^ \t\n")
  361.                 (narrow-to-region (point) (match-end 0))
  362.                 (goto-char (point-max))
  363.                 (skip-chars-backward "[0-9]")))
  364.           ;; Are we looking at a "filename-first" or "line-number-first" form?
  365.           (if (looking-at "[0-9]")
  366.               (progn
  367.                 (setq linenum (read (current-buffer)))
  368.                 (goto-char (point-min)))
  369.             ;; Line number at start, file name at end.
  370.             (progn
  371.               (goto-char (point-min))
  372.               (setq linenum (read (current-buffer)))
  373.               (goto-char (point-max))
  374.               (skip-chars-backward "^ \t\n")))
  375.           (setq filename (compilation-grab-filename)))
  376.         ;; Locate the erring file and line.
  377.         (if (and (equal filename last-filename)
  378.                  (= linenum last-linenum))
  379.             nil
  380.           (beginning-of-line 1)
  381.           (setq error-marker (point-marker))
  382.           ;; text-buffer gets the buffer containing this error's file.
  383.           (if (not (equal filename last-filename))
  384.               (setq text-buffer
  385.                     (and (file-exists-p (setq last-filename filename))
  386.                          (find-file-noselect filename))
  387.                     last-linenum 0))
  388.           (if text-buffer
  389.               ;; Go to that buffer and find the erring line.
  390.               (save-excursion
  391.                 (set-buffer text-buffer)
  392.                 (if (zerop last-linenum)
  393.                     (progn
  394.                       (goto-char 1)
  395.                       (setq last-linenum 1)))
  396.                 (forward-line (- linenum last-linenum))
  397.                 (setq last-linenum linenum)
  398.                 (setq text-marker (point-marker))
  399.                 (setq compilation-error-list
  400.                       (cons (list error-marker text-marker)
  401.                             compilation-error-list)))))
  402.         (forward-line 1)))
  403.     (setq compilation-parsing-end (point-max)))
  404.   (message "Parsing error messages...done")
  405.   (setq compilation-error-list (nreverse compilation-error-list)))
  406.  
  407. (defun compilation-grab-filename ()
  408.   "Return a string which is a filename, starting at point.
  409. Ignore quotes and parentheses around it, as well as trailing colons."
  410.   (if (eq (following-char) ?\")
  411.       (save-restriction
  412.         (narrow-to-region (point)
  413.                           (progn (forward-sexp 1) (point)))
  414.         (goto-char (point-min))
  415.         (read (current-buffer)))
  416.     (buffer-substring (point)
  417.                       (progn
  418.                         (skip-chars-forward "^ :,\n\t(")
  419.                         (point)))))
  420.  
  421. ;; (define-key ctl-x-map "`" 'next-error)
  422. (define-key ctl-x-map "`" 'wsr:next-error)
  423. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  424. ;;                                                                           ;;
  425. ;;      File:     compile.el                                                 ;;
  426. ;;      Author:   Wolfgang S. Rupprecht <wolfgang@wsrcc.com>                 ;;
  427. ;;      Created:  March 1987                                                 ;;
  428. ;;      Contents: I did significant hacking to the error parser              ;;
  429. ;;              for next-error.  The parser now has a table that             ;;
  430. ;;              it scans for applicable rexexp templates.  If                ;;
  431. ;;              one of them fits, it uses that one to parse the              ;;
  432. ;;              line. If it doesn't fit, the scanner tries the               ;;
  433. ;;              next template. If all templates fail, the line               ;;
  434. ;;              is deemed a useless line and discarded.                      ;;
  435. ;;                                                                           ;;
  436. ;;      Copyright (c) 1989, 1987 Wolfgang Rupprecht.                         ;;
  437. ;;                                                                           ;;
  438. ;;      $Header$                                                             ;;
  439. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  440.  
  441. ;; This file is not really part of GNU Emacs, but is (hopefully)
  442. ;; useful in conjunction with it.  It is meant as a patch to the
  443. ;; distributed GnuEmacs lisp file by the same name.
  444.  
  445. ;; GNU Emacs and this compile.el is distributed in the hope that it
  446. ;; will be useful, but WITHOUT ANY WARRANTY.  No author or distributor
  447. ;; accepts responsibility to anyone for the consequences of using it
  448. ;; or for whether it serves any particular purpose or works at all,
  449. ;; unless he says so in writing.  Refer to the GNU Emacs General
  450. ;; Public License for full details.
  451.  
  452. ;; Everyone is granted permission to copy, modify and redistribute GNU
  453. ;; Emacs, but only under the conditions described in the GNU Emacs
  454. ;; General Public License.  A copy of this license is supposed to have
  455. ;; been given to you along with GNU Emacs so you can know your rights
  456. ;; and responsibilities.  It should be in a file named COPYING.  Among
  457. ;; other things, the copyright notice and this notice must be
  458. ;; preserved on all copies.
  459.  
  460. ;; First we load the real lib.  The original load-path should be stored
  461. ;; in the variable old-load-path.
  462.  
  463. ;(let ((load-path old-load-path))
  464. ;  (require 'compile))
  465.  
  466. ;; Now we patch it.
  467.  
  468. (define-key ctl-x-map "`" 'wsr:next-error)
  469.  
  470. ;; let's hope that nobody is stupid enough to put a colon or
  471. ;; parenthesis in their filenames, (these regexps desperately need to
  472. ;; cue off of them) -wsr
  473.  
  474. ;; for forced updating of the defvar definitions
  475. ;; (defmacro defvar-f (name val doc) (list 'setq name val))
  476.  
  477. (defvar error-parsing-regexp-list
  478.   ;; rule 0: 4.3bsd grep, cc, lint(part1 warnings)
  479.   ;; /users/wolfgang/foo.c(8): warning: w may be used before set
  480.   '(("^\\([^:( \t\n]+\\)[:( \t]+\\([0-9]+\\)[:) \t]" 1 2)
  481.     ;; rule 1: 4.3bsd lint part2: inconsistant type warnings
  482.     ;; strcmp: variable # of args.      llib-lc(359)  ::  /users/wolfgang/foo.c(8)
  483.     ;; also sysV lint: from kamat@uceng.uc.edu
  484.     ;;     seekdir      llib-lc(345) :: uuq.c?(73)
  485.     ("^[^\n]*[ \t]+\\([^:( \t\n]+\\)[:(]+[ \t]*\\([0-9]+\\)[:) \t]+\\([^:?( \t\n]+\\)\\??[:(]+[ \t]*\\([0-9]+\\)[:) \t]+$"
  486.      3 4 1 2)
  487.  
  488. ;;;    ("[^\n]*[ \t:]+\\([^:( \t\n]+\\)[ \t]*[:(]+[ \t]*\\([0-9]+\\)[:) \t]*$"     1 2)
  489.     ;; rule 2: 4.3bsd lint part3: defined, but unused messages
  490.     ;; linthemorrhoids defined( /users/wolfgang/foo.c(4) ), but never used
  491.     ;; foo used( file.c(144) ), but not defined
  492.     ("[^\n]*\\(defined\\|used\\)[ \t(]+\\([^:( \t\n]+\\)[:( \t]+\\([0-9]+\\)[:) \t]+"
  493.      2 3)
  494.     ;; rule 3: 4.3bsd compiler
  495.     ;; "foo.c", line 18: cc_cardiac_arrest undefined
  496.     ("^[\* \t]*[Ll]ine[ \t]+\\([0-9]+\\)[ \t]+of[ \t]+\"\\([^\"\n]+\\)\":" 2 1)
  497.     ;; rule 4: apollo cc warnings, yuk -wsr
  498.     ("^[\* \t]*\"\\([^\"\n]+\\)\",?[ \t]+[Ll]ine[ \t]+\\([0-9]+\\):" 1 2)
  499.     ;; rule 5: as on a sun 3 under sunos 3.4
  500.     ;;(as) "spl.i", line 23:  Error:  syntax error.
  501.     ("^(.+)[ \t]+\"\\([^\"\n]+\\)\",[ \t]+line[ \t]+\\([0-9]+\\):" 1 2)
  502.     ;; rule 6: m88kcc
  503.     ;; "./foo.h" , line 128: redeclaration of bar
  504.     ;; note the extra space before the comma (after filename) : grotty
  505.     ("^\\((.+)[ \t]+\\)?\"\\([^\"\n]+\\)\" ?,[ \t]+line[ \t]+\\([0-9]+\\):"
  506.      2 3)
  507.     ;; rule 7: Make
  508.     ;; Make: line 20: syntax error.  Stop.
  509.     ;; Make: Must be a separator on rules line 84.  Stop.
  510.     ("^[\* \t]*[Mm]ake: [^\n]*[Ll]ine[ \t]+\\([0-9]+\\)[.:]"
  511.      scan-make 1)
  512.     ;; rule 8: /bin/sh 
  513.     ;; filename can only be parsed correctly if it is a full pathname, or
  514.     ;; is relative to this directory.
  515.     ;; ./binshscript: syntax error at line 5: `newline or ;' unexpected
  516.     ("^\\([^:\n]+\\):.*line[ \t]+\\([0-9]+\\):" 1 2)
  517.     ;; rule 9: sysV woes
  518.     ;;     rcmd         cico.c?(243)
  519.     ("^    [^: \t\n]+ +\t\\([^:?( \t\n]+\\)\\??(\\([0-9]+\\))$" 1 2)
  520.     ;; rule 10: sysV lint - "Reach out and confuse someone."
  521.     ;; cico.c
  522.     ;; ==============
  523.     ;; (88)  warning: alias unused in function main
  524.     ;; (656)  warning: main() returns random value to invocation environment
  525.     ;; cntrl.c:
  526.     ;;  
  527.     ;; uucpd.c
  528.     ;; ==============
  529.     ;; warning: argument unused in function:
  530.     ;;     (48)  argc in main
  531.     ;; warning: possible pointer alignment problem
  532.     ;;     (145)            (246)           (329)  
  533.     ;;     (367)        
  534.     ;; note: This regexp has to be incredibally weak.  There just isn't much
  535.     ;; to get a toe-hold on here.  Better keep this one on the end. -wsr
  536.     ("^[ \t]*(\\([0-9]+\\))[ \t]" scan-s5lint 1)
  537.     ;; rule 11: there is no rule 11
  538.     ;; (add other rules and explanations here)
  539.     )
  540.   "a list of lists consisting of:
  541. \((rexexp filename-match-index linenum-match-index)(...)(...))
  542. for parsing error messages")
  543.  
  544. (defun test-parse (pos)
  545.   "Test the line parsing code, attempts to parse the current line for
  546. filename and line number. Answer is returned in minibuffer."
  547.   (interactive "d")
  548.   (forward-line 0)
  549.   (let (filename linenum filename-2 linenum-2) ; set by compilation-parse-line
  550.     (let ((parserule (compilation-parse-line)))
  551.       (if parserule
  552.           (if filename-2
  553.               (message "Parses as: '%s(%d)' and '%s(%d)' [rule %d]"
  554.                        filename linenum
  555.                        filename-2 linenum-2 parserule)
  556.             (message "Parses as: '%s(%d)' [rule %d]"
  557.                      filename linenum parserule))
  558.         (message "Couldn't parse that line")))))
  559.  
  560. (defvar compilations-window-height 4 "*Height of compilations buffer window.")
  561.  
  562. ;; parse error msgs, find file or files, and position cursor on the
  563. ;; appropriate lines.
  564. ;; The "primary" file is always at the bottom of the screen.
  565. ;; The *compilations* buffer is always at the top, and reduced to
  566. ;;  a smaller height.
  567.  
  568. (defvar last-error-buf nil
  569.   "The last buffer that next error used.")
  570.  
  571. (defun wsr:next-error (&optional flag)
  572.   "This is the *new* NEXT ERROR: Visit next compilation error message
  573. and corresponding source code.  This operates on the output from the
  574. \\[compile] command.  This command uses the line after current point
  575. as the starting point of the next error search.
  576.  
  577. If optional FLAG is set (C-u for interactive), cause the current
  578. buffer to be the new compilation buffer."
  579.   (interactive "P")
  580.   (if flag
  581.       (setq last-error-buf (current-buffer)))
  582.   (pop-to-buffer (or last-error-buf last-compilation-buffer
  583.              "*compilation*"))
  584.   (let ((opoint (point))
  585.         (pwd default-directory)
  586.         filename linenum filename-2 linenum-2)
  587.     ;; note: compilation-parse-line will set the above 4 variables
  588.     ;; by side effect.
  589.     (while (and (zerop (forward-line 1))
  590.                 (null (compilation-parse-line))))
  591.     (if (null filename)
  592.     ;; this error will leave on in the compilation buffer.
  593.     ;; usually this is of benefit - one can now move the up
  594.     ;; point back up to bet back to the last error of interest.
  595.         (error (concat compilation-error-message
  596.                        (if (and compilation-process
  597.                                 (eq (process-status compilation-process)
  598.                                     'run))
  599.                            " yet" "")))
  600.       (recenter 0)
  601.       (if (file-exists-p filename)
  602.           (progn
  603.             (delete-other-windows)
  604.             (let ((wh (window-height)))
  605.               (find-file-other-window filename)
  606.               (shrink-window (- compilations-window-height (/ wh 2)))
  607.               )
  608.             (goto-line linenum)
  609.             (recenter (/ (window-height) 2))
  610.             (if filename-2              ; a two file match
  611.                 (let ((default-directory pwd)) ; get the pwd right!
  612.                   (if (file-exists-p filename-2)
  613.                       (progn
  614.                         (split-window-vertically nil)
  615.                         (find-file filename-2)
  616.                         (goto-line linenum-2)
  617.                         (recenter (/ (window-height) 2))
  618.                         ;; now back to file # 1
  619.                         (other-window 1)
  620.                         ;; needed if both windows are on the same file
  621.                         (recenter (/ (window-height) 2)))
  622.                     (message "Can't find file '%s(%d)'"
  623.                              filename-2 linenum-2)))))
  624.         ;; try filename-2 ... suggested by kamat
  625.         (if filename-2
  626.             (if (file-exists-p filename-2)
  627.                 (progn
  628.                   (message "Can't find file '%s(%d)'" filename linenum)
  629.                   (delete-other-windows)
  630.                   (let ((wh (window-height)))
  631.                     (find-file-other-window filename-2)
  632.                     (shrink-window (- compilations-window-height (/ wh 2))))
  633.                   (goto-line linenum-2)
  634.                   (recenter (/ (window-height) 2)))
  635.               (error "Can't find files '%s(%d)' or '%s(%d)'" 
  636.                      filename linenum filename-2 linenum-2))
  637.           (error "Can't find file '%s(%d)'" filename linenum))))))
  638.  
  639. (defun compilation-parse-line ()
  640.   "Parse this line, setq-ing filename and linenum."
  641.   (let ((parse-list error-parsing-regexp-list)
  642.         (rule-num 0))
  643.     (while parse-list
  644.       (let ((rule-list (car parse-list)))
  645.         (if (looking-at (car rule-list))
  646.             (let ((file-index (nth 1 rule-list))
  647.                   (line-index (nth 2 rule-list))
  648.                   (file-2-index (nth 3 rule-list))
  649.                   (line-2-index (nth 4 rule-list)))
  650.               (setq linenum (string-to-int
  651.                              (buffer-substring (match-beginning line-index)
  652.                                                (match-end line-index))))
  653.               (if file-2-index
  654.                   (progn
  655.                     (setq filename-2 (buffer-substring
  656.                                       (match-beginning file-2-index)
  657.                                       (match-end file-2-index)))
  658.                     (setq linenum-2 (string-to-int
  659.                                      (buffer-substring
  660.                                       (match-beginning line-2-index)
  661.                                       (match-end line-2-index))))))
  662.               (setq filename
  663.                     (cond ((integerp file-index)
  664.                            (buffer-substring (match-beginning file-index)
  665.                                              (match-end file-index)))
  666.                           ;; careful! this next funcall may mash
  667.                           ;; the match-data, so it must be done
  668.                           ;; after all the line numbers and names have been
  669.                           ;; extracted
  670.                           ((symbolp file-index) (funcall file-index))
  671.                           ((stringp file-index) file-index)
  672.                           (t (error "Parsing error: unknown action type: %s"
  673.                                     file-index))))
  674.               (setq parse-list nil))    ;we're done
  675.           (setq parse-list (cdr parse-list)
  676.                 rule-num (1+ rule-num)))))
  677.     (and linenum filename rule-num)))   ; return matching rule number
  678.  
  679. (defun scan-make ()
  680.   "Attempt to find the name of the Makefile used by this make run.
  681. This routine shouln't be used for anything drastic, since it just isn't
  682. that robust."
  683.   (cond ((save-excursion
  684.            (re-search-backward "make[^\n]+-f[ \t]+\\(\\sw\\|\\s_\\)+" nil t))
  685.          (buffer-substring (match-beginning 1)(match-end 1)))
  686.         ((file-exists-p "makefile") "makefile")
  687.         ((file-exists-p "Makefile") "Makefile")
  688.         (t nil)
  689.       ))
  690.  
  691. (defun scan-s5lint ()
  692.   "Attempt to find the name of the file that lint was griping about on
  693. this line.  This routine also has the side-effect of modifying the current
  694. buffer.  The current line will have the first gripe of a multi-gripe line 
  695. broken off onto a separate line."
  696.   (let (retval)
  697.     (if (save-excursion
  698.           (re-search-backward "^\\(\\sw\\|\\s_\\|\\s.\\)+\n======+$" nil t))
  699.         (progn
  700.           (setq retval (buffer-substring (match-beginning 1)(match-end 1)))
  701.           (save-excursion
  702.             (if (re-search-forward ")[ \t]*("
  703.                                    (save-excursion (end-of-line) (point)) t)
  704.                 (replace-match ")\n(")))))
  705.   retval))
  706.  
  707.  
  708. -- 
  709. Wolfgang Rupprecht    wolfgang@wsrcc.com (or) uunet!wsrcc!wolfgang
  710. Snail Mail Address:   Box 6524, Alexandria, VA 22306-0524
  711.