0

I'm trying to do something seemingly simple: create an Emacs function to create a TAGS file for me. There are simple instructions for doing this here

(defun create-tags (dir-name)
 "Create tags file."
 (interactive "DDirectory: ")
 (eshell-command 
  (format "find %s -type f -name \"*.[ch]\" | etags -" dir-name)))

The problem is I need "cpp" files instead of "c". That means my find command has to change to this:

find %s -type f -iname "*.cpp" -or -iname "*.h"

That works great on the command line. The problem I'm having is that eshell doesn't seem to like that at all. When I execute this function, I keep getting: File not found - "*.h": Invalid argument.

The answer to this question suggests that proper use of shell-quote-argument might fix these kinds of issues, but I haven't been able to hack out a solution that works. For instance, this produces the same error:

(format "find %s -type f -iname %s -or -iname %s | etags -"
   dir-name
   (shell-quote-argument "*.cpp")
   (shell-quote-argument "*.h"))
T.E.D.
  • 44,016
  • 10
  • 73
  • 134
  • Using a better [ctags](https://ctags.io/) may be the easiest solution. – sds May 10 '17 at 22:13
  • did you try using the regular `shell-command` instead of `eshell-command`? – sds May 10 '17 at 22:16
  • @sds - Just tried `shell-command`. Exact same result. – T.E.D. May 11 '17 at 15:42
  • just tried `(shell-command (format "find %s -type f -iname %s -or -iname %s | etags -" "~/src/emacs/trunk" (shell-quote-argument "*.cpp") (shell-quote-argument "*.h")))` and it worked just fine. – sds May 11 '17 at 15:51
  • @sds - Hmmm. Perhaps emacs version is important? Mine is 20.0.50.1. – T.E.D. May 11 '17 at 16:04
  • 2
    possibly - my emacs is 26.0.50. Yours (20.0.50) is probably a typo. I don't believe you are using a _development_ version from 20 years ago. – sds May 11 '17 at 16:12
  • @sds - Err...yes. Sorry. **25**.0.50.1. I hate upgrading when things mostly work, but I'm not quite *that* downrev. :-) – T.E.D. May 19 '17 at 14:56
  • I don't think 25 could be a problem. However, I urge you to upgrade to an official release. It makes no sense to try to figure out what the problem is until you do. – sds May 19 '17 at 17:22
  • @sds - Uck. I hate upgrading. Never know what in my .emacs is going to quit working, or what new bugs await me. Still, if I must... – T.E.D. May 19 '17 at 17:51
  • You'll surely need to protect your path parameter if it contains spaces, a solution might be: `find \"%s\" ...`. – Daniele May 31 '17 at 17:11
  • @sds - Just tried your shell-command again with GNU Emacs 25.1.1 (x86_64-w64-mingw32), and got the same result: `File not found - "*.h"` – T.E.D. May 31 '17 at 18:05
  • @Daniele - Worth a shot! Tried that and got `'""C:' is not recognized as an internal or external command, operable program or batch file.` Removing the quotes around the file names and leaving them around the wildcards got me `File not found - ""*.cpp` – T.E.D. May 31 '17 at 18:13
  • 1
    @T.E.D. are you running find in Windows? – Daniele May 31 '17 at 18:39
  • @Daniele - Yes. I think you're beginning to think along the lines I am (perhaps my find command is the issue). When I try the equivalent command in bash, it works fine. But I'm not sure that's the same find. – T.E.D. May 31 '17 at 18:42

2 Answers2

1

You're trying to use the posix syntax with the Windows find command. This is wrong for two reasons:

  • Surely you cannot hope that it supports a syntax from a different OS.
  • Windows find acts like grep, use dir instead.

Hope it'll help you.

Daniele
  • 310
  • 3
  • 15
  • Just figured it out (and posted the answer). However, all the info in here turned out to be exactly what was wrong, and what needed doing, and it was your prompting in the comments that helped get me here, so I'm accepting it. – T.E.D. May 31 '17 at 19:34
1

With much help from sds and Daniele in the comments, I was finally able to figure out the issue.

There were two issues with what I was doing:

  1. I was using a bash solution with an ms-dos command shell. The DOS "find" is a totally different command than the Unix find, so it makes perfect sense that it was complaining about its parameters.
  2. The usual quoting issues. My etags exe had a space in its path. I tried fixing this with shell-quote-argument, but with the MS-DOS shell all that does is put escaped quotes around the argument. You still have to manually escape any backslashes, and the DOS shell requires those in its file paths.

For those interested, the working command under Windows is:

(defun create-tags (dir-name)
  "Create tags file."
  (interactive "DDirectory: ")
  (shell-command
   (format "cd %s & dir /b /s *.h *.cpp | %s -"
       dir-name
       (shell-quote-argument "C:\\Program Files\\Emacs\\emacs-25.0\\bin\\etags.exe"))))

The only quirk is that when Emacs prompts you for a directory, you have to make sure to give it one the DOS shell can handle. ~/dirname will not work. There's probably a fix for that, for someone with better emacs-fu than I care to devote to the issue.

T.E.D.
  • 44,016
  • 10
  • 73
  • 134
  • Also note that setting emacs' default shell to a better one would probably do the trick too. However, I need it to be the Dos shell, because that's what vcvars.bat uses, which I need for my VisualStudio compiles, so doing that wasn't an option. – T.E.D. May 31 '17 at 19:36
  • Also helpful in figuring it out was [this question](https://stackoverflow.com/questions/10738219/how-to-use-shell-magic-to-create-a-recursive-etags-using-gnu-etags) which had the DOS shell solution. – T.E.D. May 31 '17 at 19:46
  • @Daniele - I look at it as like vi on Unix. Sure, it sucks, but every machine of that OS has it. You need to know at least enough of it to use it in a pinch until you can get something better installed. :-) – T.E.D. May 31 '17 at 19:49