views:

99

answers:

1

I'm attempting to run P4V commands directly from xemacs. After pulling in the p4.el to emacs I've written the following:

(defun p4v-command (cmd)
  (get-buffer-create p4-output-buffer-name);; We do these two lines
  (kill-buffer p4-output-buffer-name)      ;; to ensure no duplicates
  (call-process "p4v" nil (get-buffer-create p4-output-buffer-name) nil
                "-p" (p4-get-p4-port)
                "-u" "UserName"
                "-c" (p4-current-client)
                "-cmd" (shell-quote-argument (concat cmd " " (buffer-name))))
  (display-buffer p4-output-buffer-name))

I'm trying to get the following for shell command (when cmd equals prevdiff):

p4v -p port -u user -c client -cmd "prevdiff file.txt"

However, when I execute the above function with prevdiff I get the following error

P4V: unrecognized argument '"prevdiff' for '-cmd' option.

So it seems that the call-process is splitting the quoted string "prevdiff file.txt" into individual arguments and P4V is processing only the first one.

This doesn't seem to happen for other commands I have tried with call-process so I'm not sure if it is a lisp problem or something to do with P4V.

Does anyone know how to resolve this?

+3  A: 

call-process definitely doesn't concatenate its arguments; it passes them through to the program directly. To see this is the case, type M-: and evaluate the following expression:

(call-process "/bin/ls" nil "*scratch*" nil "avg ba")

where "avg" and "ba" are files in the current directory. I get the following message inserted into my scratch buffer:

/bin/ls: cannot access avg ba: No such file or directory

If call-process had re-parsed the arguments, it would have split "avg ba" into two separate arguments --- but the error message shows that it didn't.

Instead, the problem is with shell-quote-argument. When I evaluate the call you mention in the scratch buffer, I get the following:

(shell-quote-argument "prevdiff file.txt")
"prevdiff\\ file.txt"

In other words, the command p4v actually receives is what you'd enter in the shell as:

p4v -p port -u user -c client -cmd '"prevdiff file.txt"'

This is why p4v is complaining about "prevdiff.

So what I think you want instead is:

"-cmd" (concat cmd " " (shell-quote-argument (buffer-name))))

(but check my parens, of course).

Jim Blandy
Thanks Jim! Worked a treat.
Jeremy Simon
This isn't quite right: when you get `"prevdiff\\ file.text"` and then pass it to `call-process` the quotes don't get sent to the process (they're part of the elisp string syntax, not part of the string). I think what's happening is that @Jim Blandy and I are on unixy systems whereas @Jeremy Simon is on Windows, where `shell-quote-argument` will return `"\"prevdiff file.txt\""`. This would explain the `p4v` error.
Mike Dinsdale
Yes, Mike, you're right. I misread what was in the *scratch* buffer. Jeremy, I'm glad my mistake and the difference in OS cancelled out!
Jim Blandy
From the Emacs Lisp manual: ;; This example shows the behavior on MS-DOS and MS-Windows. (shell-quote-argument "foo > bar") => "\"foo > bar\""And there are the extra quotes.
Jim Blandy