Emacs call-process stumbles upon supplied args content - process

I'm puzzled by unexpected behavior of a call-process call.
Here's a little function:
(defun work-in-progress()
"run ledger report and output result in current buffer.
The intention is to run following command (works perfectly from shell):
`ledger -U csv --sort date --file ledger-file child`
where ledger-file is a known and defined variable.
The problem is that the command fails with:
`Error: Illegal option -`
"
(interactive)
(cd ledger-dir)
(setq child "peter")
(setq parms "-U csv --sort date --file")
(setq prog "ledger") ; should be found via path variable or so
(call-process prog nil t t parms ledger-file child)
)
I've played around with the sequence of the ledger command options, but emacs always seems to complain about the first option or all options in the parms variable:
e.g.
(setq parms "--sort date -U csv --file")
results in
Error: Illegal option --sort date -U csv --file
iso
Error: Illegal option -
The ledger cli program isn't fussy about arguments sequence, both described option sequences work perfectly well when calling ledger at the command line.
This truly puzzles me. The documentation reads
call-process program &optional infile destination display &rest args
and infile is set to nil, destination as well as display are t, so why doesn'it grok the content of args variable?
Any help, correction and/or suggestion would be sincerely appreciated!

The tail of the list should be a sequence of strings, each corresponding to one argument.
(setq parms '("-U" "csv" "--sort" "date" "--file"))
(setq prog "ledger")
(apply #'call-process prog nil t t (append parms '(ledger-file child)))
You need apply to make the result of append into a continuation of the static list of arguments to call-process.
I had to guess what ledger-file and child are; if they are not strings, you need to convert them to strings.
To briefly recapitulate how the shell parses arguments, the command line
echo foo "bar $baz" 'quux $baz'
gets turned into the string array
'("echo" "foo" "bar <<value of baz>>" "quux $baz")
(to use a Lispy notation) and passed as arguments to execlp.

The solution is to pass each parameter as a separate string:
(defun work-in-progress()
"run ledger report and output result in current buffer. "
(interactive)
(cd ledger-dir)
(setq child "peter")
(setq prog "ledger") ; should be found via path variable or so
(call-process prog nil t t "--sort" "date" "-U" "csv" "--file" ledger-file child)
)

Related

Running command in perl6, commands that work in shell produce failure when run inside perl6

I'm trying to run a series of shell commands with Perl6 to the variable $cmd, which look like
databricks jobs run-now --job-id 35 --notebook-params '{"directory": "s3://bucket", "output": "s3://bucket/extension", "sampleID_to_canonical_id_map": "s3://somefile.csv"}'
Splitting the command by everything after notebook-params
my $cmd0 = 'databricks jobs run-now --job-id 35 --notebook-params ';
my $args = "'{\"directory\": \"$in-dir\", \"output\": \"$out-dir\",
\"sampleID_to_canonical_id_map\": \"$map\"}'"; my $run = run $cmd0,
$args, :err, :out;
Fails. No answer given either by Databricks or the shell. Stdout and stderr are empty.
Splitting the entire command by white space
my #cmd = $cmd.split(/\s+/);
my $run = run $cmd, :err, :out
Error: Got unexpected extra arguments ("s3://bucket", "output":
"s3://bucket/extension",
"sampleID_to_canonical_id_map":
"s3://somefile.csv"}'
Submitting the command as a string
my $cmd = "$cmd0\"$in-dir\", \"output\": \"$out-dir\", \"sampleID_to_canonical_id_map\": \"$map\"}'";
again, stdout and stderr are empty. Exit code 1.
this is something about how run can only accept arrays, and not strings (I'm curious why)
If I copy and paste the command that was given to Perl6's run, it works when given from the shell. It doesn't work when given through perl6. This isn't good, because I have to execute this command hundreds of times.
Perhaps Perl6's shell https://docs.perl6.org/routine/shell would be better? I didn't use that, because the manual suggests that run is safer. I want to capture both stdout and stderr inside a Proc class
EDIT: I've gotten this running with shell but have encountered other problems not related to what I originally posted. I'm not sure if this qualifies as being answered then. I just decided to use backticks with perl5. Yes, backticks are deprecated, but they get the job done.
I'm trying to run a series of shell commands
To run shell commands, call the shell routine. It passes the positional argument you provide it, coerced to a single string, to the shell of the system you're running the P6 program on.
For running commands without involving a shell, call the run routine. The first positional argument is coerced to a string and passed to the operating system as the filename of the program you want run. The remaining arguments are concatenated together with a space in between each argument to form a single string that is passed as a command line to the program being run.
my $cmd0 = 'databricks jobs run-now --job-id 35 --notebook-params ';
That's wrong for both shell and run:
shell only accepts one argument and $cmd0 is incomplete.
The first argument for run is a string interpreted by the OS as the filename of a program to be run and $cmd0 isn't a filename.
So in both cases you'll get either no result or nonsense results.
Your other two experiments are also invalid in their own ways as you discovered.
this is something about how run can only accept arrays, and not strings (I'm curious why)
run can accept a single argument. It would be passed to the OS as the name of the program to be run.
It can accept two arguments. The first would be the program name, the second the command line passed to the program.
It can accept three or more arguments. The first would be the program name, the rest would be concatenated to form the command line passed to the program. (There are cases where this is more convenient coding wise than the two argument form.)
run can also accept a single array. The first element would the program name and the rest the command line passed to it. (There are cases where this is more convenient.)
I just decided to use backticks with perl5. Yes, backticks are deprecated, but they get the job done.
Backticks are subject to code injection and shell interpolation attacks and errors. But yes, if they work, they work.
P6 has direct equivalents of most P5 features. This includes backticks. P6 has two variants:
The safer P6 alternative to backticks is qx. The qx quoting construct calls the shell but does not interpolate P6 variables so it has the same sort of level of danger as using shell with a single quoted string.
The qqx variant is the direct equivalent of P5 backticks or using shell with a double quoted string so it suffers from the same security dangers.
Two mistakes:
the simplistic split cuts up the last, single parameter into multiple arguments
you are passing $cmd to run, not #cmd
use strict;
my #cmd = ('/tmp/dummy.sh', '--param1', 'param2 with spaces');
my $run = run #cmd, :err, :out;
print(#cmd ~ "\n");
print("EXIT_CODE:\t" ~ $run.exitcode ~ "\n");
print("STDOUT:\t" ~ $run.out.slurp ~ "\n");
print("STDERR:\t" ~ $run.err.slurp ~ "\n");
output:
$ cat /tmp/dummy.sh
#!/bin/bash
echo "prog: '$0'"
echo "arg1: '$1'"
echo "arg2: '$2'"
exit 0
$ perl6 dummy.pl
/tmp/dummy.sh --param1 param2 with spaces
EXIT_CODE: 0
STDOUT: prog: '/tmp/dummy.sh'
arg1: '--param1'
arg2: 'param2 with spaces'
STDERR:
If you can avoid generating $cmd as single string, I would generate it into #cmd directly. Otherwise you'll have to implement complex split operation that handles quoting.

Opening and closing AUTOCAD files using SCR Scripting

I have recently started writing scripts for AUTOCAD.
I want to do the following:
Suppose,I place my script in the current location.
In current location,I have several folders. Each folder in turn contain many folders,which again contain some drawing files (of type .DWG and .DWT).
I want to loop through each of the folder and get a list containing only .DWT files.
Now,I want to loop through each of the .DWT file and open the file in AUTOCAD, change the value of the parameter "DELOBJ" to 1 (say) and finally save,close the document.
Can we do it with normal SCR Scripting (or) can we do it using LISP Command?
I would be really glad,if someone can help me in this context
Thanks in advance.
Today I don't have enought time to prepare full sample (sorry) but let's start with:
Get the list of all *.DWT files. You may do it like this:
(defun CMD::Dir ( pattern / Shell Dirinf Outbuf CmdVal)
(setq cmd (strcat "%comspec% /C dir /S /B " pattern ) )
(print cmd )
(setq Shell (vlax-get-or-create-object "Wscript.Shell"))
(setq Dirinf(vlax-invoke-method Shell 'Exec cmd ))
(setq Outbuf(vlax-get-property Dirinf 'StdOut ))
( while (= :vlax-false (vlax-get-property Outbuf 'AtEndOfStream ) )
(setq CmdVal (append CmdVal (list (vlax-invoke-method Outbuf 'ReadLine ) ) ) )
)
(vlax-release-object Shell)
CmdVal
)
(setq files (CMD::Dir "**YourPath**\\*.dwt" ) )
then using (foreach file files .. ) open each drawing, and set value of DELOBJ. But remember, that LISP context is only in active drawing, so You can't use (setvar 'DELOBJ 1)
Probably you may to do it by vlax. but this is the time, when I can not help You now. When I have sample I will update.
The 'DELOBJ' Systemvariable is saved in the registry, so it has nothing to do with any documents... (indeed, some Sysvars are saved in Documents, but if you only need focus on this...)
refer:
ADSK Knowledge Network
So you set it once per profile (a simple .reg file would be enough)
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\SOFTWARE\Autodesk\AutoCAD\[Release]\[Product]\Profiles\[Profile]]
"Delobj"=dword:00000001
You would be able to pull the value from registry with this code.
(vl-registry-read (strcat "HKEY_CURRENT_USER\\" (vlax-product-key) "\\Profiles\\" (vla-get-ActiveProfile (vla-get-profiles (vla-get-preferences (vlax-get-Acad-Object)))) "\\General") "Delobj")
Check if its not 1 and then use vl-registry-write

Real standard input in Racket

It seems that Racket is incapable of reading a string from STDIN.
$ racket
Welcome to Racket v6.4.
-> (define (s) (read-line))
OK, s is an alias for a call to read-line.
-> (printf "You entered: ~a\n" s)
You entered:
Failure: The string is printed, but Racket does not wait for keypress / STDIN / EOF / EOL.
-> (define n (read))
a
-> n
'a
Failure: This makes a call to read and waits for EOF / EOL, then assigns to n, but n is assigned the symbol 'a not the string literal a.
-> (read-line)
""
Failure: calling read-line doesn't wait for STDIN, just returns the empty string.
-> (read-string 5)
asdasdasdasd
"\nasda"
; sdasdasd: undefined;
; cannot reference undefined identifier
; [,bt for context]
Failure: only reads 5 bytes of STDIN, and apparently evals the rest of it... ?
-> (read-string 500000)
asdasd
asdasdaas
a
asdasd
asdasd
asdasd
Failure: doesn't return until exactly 500000 bytes have been read, and doesn't return on EOL.
Somewhat like Python's input() which returns a string when EOL is found, or Factor's readln which does the same, how can I read raw data from the current-input-port?
This is just a limitation of the Racket's REPL's input handling. If you write a standalone program it will work fine.
Here's a quote from the mailing list that explains the problem:
A known limitation. The REPL implemented by plain `racket' does not
separate the input stream for REPL expressions from the program's
input stream.
More details: https://groups.google.com/d/msg/racket-users/0TTsA9-3HDs/9_mMWsgKFOMJ

How to store a result to a variable in HP OpenVMS DCL?

I want to save the output of a program to a variable.
I use the following approach ,but fail.
$ PIPE RUN TEST | DEFINE/JOB VALUE #SYS$PIPE
$ x = f$logical("VALUE")
I got an error:%DCL-W-MAXPARM, too many parameters - reenter command with fewer parameters
\WORLD\
reference :
How to assign the output of a program to a variable in a DCL com script on VMS?
The usual way to do this is to write the output to a file and read from the file and put that into a DCL symbol (or logical). Although not obvious, you can do this with the PIPE command was well:
$ pipe r 2words
hello world
$ pipe r 2words |(read sys$pipe line ; line=""""+line+"""" ; def/job value &line )
$ sh log value
"VALUE" = "hello world" (LNM$JOB_85AB4440)
$
IF you are able to change the program, add some code to it to write the required values into symbols or logicals (see LIB$ routines)
If you can modify the program, using LIB$SET_SYMBOL in the program defines a DCL symbol (what you are calling a variable) for DCL. That's the cleanest way to do this. If it really needs to be a logical, then there are system calls that define logicals.

Xcode evaluating expressions while debugging

I am working on an iPhone app. I am a full-time Java developer and I am used to using Eclipse where I can put a breakpoint in and stop the process. Then, I can type in any expression that I want and Eclipse will evaluate it using the values from that point in the process.
Is there a way to do that in Xcode? I want to be able to stop at a breakpoint and then enter some code to evaluate it. The gdb console will let me do po (print-object), but it is really limited. Any help?
In XCode 4.0 this is sort of hidden in the GUI. When you're at a breakpoint you can probably see the Variables View inside the Debug Area; it's the pane which shows local variables and such. Right-click on the Variables View and select "Add Expression..."
I realize this is an old thread but it's still a top Google hit so I thought it worth answering.
My practice:
po [NSUserDefaults standardUserDefaults]
displays: <NSUserDefaults: 0x6143040>
po [[NSUserDefaults standardUserDefaults] stringForKey:#"Currency"]
displays: "CHF"
Use the "expression" command in the debugger. Using it is relatively simple. Just type the command expression and press enter. You will then be prompted enter an expression. Here is an example
(lldb) expression
Enter expressions, then terminate with an empty line to evaluate:
2+2
(int) $2 = 4
I also attached the help info for the expression command below. Hope this helps.
Evaluate a C/ObjC/C++ expression in the current program context, using user
defined variables and variables currently in scope. This command takes
'raw' input (no need to quote stuff).
Syntax: expression --
Command Options Usage:
expression [-f ] [-G ] [-a ] [-d ] [-t ] [-u ] --
expression [-o] [-a ] [-d ] [-t ] [-u ] --
expression
-G <gdb-format> ( --gdb-format <gdb-format> )
Specify a format using a GDB format specifier string.
-a <boolean> ( --all-threads <boolean> )
Should we run all threads if the execution doesn't complete on one
thread.
-d <boolean> ( --dynamic-value <boolean> )
Upcast the value resulting from the expression to its dynamic type
if available.
-f <format> ( --format <format> )
Specify a format to be used for display.
-o ( --object-description )
Print the object description of the value resulting from the
expression.
-t <unsigned-integer> ( --timeout <unsigned-integer> )
Timeout value for running the expression.
-u <boolean> ( --unwind-on-error <boolean> )
Clean up program state if the expression causes a crash, breakpoint
hit or signal.
Timeouts:
If the expression can be evaluated statically (without runnning code) then it will be.
Otherwise, by default the expression will run on the current thread with a short timeout:
currently .25 seconds. If it doesn't return in that time, the evaluation will be interrupted
and resumed with all threads running. You can use the -a option to disable retrying on all
threads. You can use the -t option to set a shorter timeout.
User defined variables:
You can define your own variables for convenience or to be used in subsequent expressions.
You define them the same way you would define variables in C. If the first character of
your user defined variable is a $, then the variable's value will be available in future
expressions, otherwise it will just be available in the current expression.
Examples:
expr my_struct->a = my_array[3]
expr -f bin -- (index * 8) + 5
expr unsigned int $foo = 5
expr char c[] = "foo"; c[0]
IMPORTANT NOTE: Because this command takes 'raw' input, if you use any
command options you must use ' -- ' between the end of the command options
and the beginning of the raw input.
Not answering question about Xcode, but JetBrains' AppCode does this in the standard IDE way most of us know from other platforms.