bug#81530: Problems with both replace-match and substring

Sean MacLennan <[email protected]> Sat, 1 Aug 2026 01:46:53 -0400
Newsgroups gmane.emacs.bugs
Message-ID <20260801014653.18ecb1e1@zonker>
I am having problems with a function to pretty print filenames. It
basically just removes the current directory, or removes the home
directory if it can.

It works great in testing, but does not work in place. I have tried
with a fairly new (updated Thursday) 32.0.50 and the stock 29.3 from
Ubuntu. And, yes, I tried -Q in both cases.

I have attached a test program and a sample text file in the correct
format. Put the sample file somewhere in a directory under your home
directory. The program massages the file to produce something that will
work for your setup.

If I run it with out-of-place, it works. I have two examples in the
program. But if I run it as part of the "real" code, it gives me an
`Args out of range: 0,10`, which is the length of my home directory.

The code shows substring, I also tried replace-match. I have no idea
what I am doing wrong. I am not doing anything complex. Really just
converting a coverity output file into something that works with
`next-error`.

You can set do-pretty to nil if you want to see that it works without
the pretty-print-fname function.

If you need any more information or want me to try something I can.

Cheers, Sean
cov.el (text/x-emacs-lisp, 2 KB)
;; -*- lexical-binding: nil; -*-

(defvar do-pretty t)

(defun pretty-print-fname (base fname)
  (if (eq (string-match base fname) 0)
      (setq fname (substring fname (match-end 0)))
    (if (string-match abbreviated-home-dir fname)
	(setq fname (substring fname (match-end 0)))))
  fname)

(defun parse-output (dir)
  (with-current-buffer (get-buffer-create "*cov*")
    (setq buffer-read-only nil)
    (erase-buffer)
    (buffer-disable-undo)
    (setq default-directory dir)

    (insert-file-contents "defects.csv")

    ;; Now massage to look like compiler output
    (let (rule type fname line)
      (goto-char (point-min))
      (while (re-search-forward
	      "^\\([^,]+\\),\\([^,]+\\),\\([^,]+\\),\\([^,]+\\),\\(.+\\)$"
	      nil t)
	(setq rule (match-string 1)
	      type (match-string 2)
	      fname (match-string 3)
	      line (match-string 4))
	(when do-pretty
	  (setq fname (pretty-print-fname dir fname)))
	(replace-match (concat fname ":" line ": error: " type " " rule))))))

;; For debugging
(defun do-parse-output (dir)
  (interactive "DDir: ")
  ;; Normalize dir
  (setq dir (expand-file-name
	     (file-name-as-directory dir)))

  ;; This is so it will match your home directory
  (let ((home (getenv "HOME")))
    ;; Prove it works standalone
    (message "Remove base %s"
	     (pretty-print-fname
	      "/home/nobody/work/boards/utils/"
	      "/home/nobody/work/boards/utils/ipaddr/ipaddr.c"))
    (message "Use home    %s"
	     (pretty-print-fname
	      (concat home "/work/boards/utils/")
	      (concat home "/work/boards/important/ipaddr/ipaddr.c")))

    (with-temp-buffer
      (setq default-directory dir)
      (insert-file-contents "defects.csv.orig")
      ;; Make the first half home
      (dotimes (i 4)
	(search-forward "/home/nobody")
	(replace-match home))
      ;; Make the rest base
      (while (search-forward "/home/nobody/work/boards/" nil t)
	(replace-match dir))
      (write-file "defects.csv")))

  ;; Now try it in place
  (parse-output dir)
  (message "Done"))
defects.csv.orig (application/octet-stream, 928 B) - not displayed