C++ program parsing arguments - c++

I want to make a program to be called from the command line like this:
myprogram.exe -F/-T FILE/TEXT -W FILE.WAV -P FILE.PHO -A
They are 3 parts:
myprogram.exe
-F OR -T and the File or text
-W FILE -P FILE and -A (At least one, up to 3, in any order (or not, if it's complicated))
So it can be:
myprogram.exe -T "Text Text, test text" -A
or:
myprogram.exe -F FILENAME -A
or:
myprogram.exe -F FILENAME -P FILENAME -W FILENAME
etc.
-A is one function (needs the text or the file)
-W writes a WAV file with the info from the text/file
-P does something similar to -W
What is the best way to handle it? Analyzing argv[x] one by one, and deciding with ifs? Something easier?
I am new to programming and using VS2008.

You can parse them manually or use Boost.Program_options.

Analyizing argv[x] one by one
That's what I would do. Maybe maintain a counter of the current element ...
unsigned int cur = 0;
if (argc <= 1) {
.. error
}
if (!strncmp(argv[cur],"-T",2)) {
.. process
++cur;
}
...
for (;cur < argc;++cur) {
if (!strncmp(argv[cur],"-F",2)) {
.. process
}
else if ...
}
There are some command line parers out there. Unix has getopt, for example.

I'd use getopt if you can: it's simple enough. It'll handle combined options too (like in ls -lt instead of ls -l -t) and it handles options with arguments as well, and the order in which they appear also doesn't matter. All this makes it "standard" to people used to command line arguments (normally order of options is irrelevant, except when giving contradictory options...).

this is already done by others, so I wouldn't spend all your time on it if I were you.
Look at Boost's ProgramOptions for example.

Related

/bin/sh: 1: Syntax error: "(" unexpected after running Makefile [duplicate]

I often find Bash syntax very helpful, e.g. process substitution like in diff <(sort file1) <(sort file2).
Is it possible to use such Bash commands in a Makefile? I'm thinking of something like this:
file-differences:
diff <(sort file1) <(sort file2) > $#
In my GNU Make 3.80 this will give an error since it uses the shell instead of bash to execute the commands.
From the GNU Make documentation,
5.3.2 Choosing the Shell
------------------------
The program used as the shell is taken from the variable `SHELL'. If
this variable is not set in your makefile, the program `/bin/sh' is
used as the shell.
So put SHELL := /bin/bash at the top of your makefile, and you should be good to go.
BTW: You can also do this for one target, at least for GNU Make. Each target can have its own variable assignments, like this:
all: a b
a:
#echo "a is $$0"
b: SHELL:=/bin/bash # HERE: this is setting the shell for b only
b:
#echo "b is $$0"
That'll print:
a is /bin/sh
b is /bin/bash
See "Target-specific Variable Values" in the documentation for more details. That line can go anywhere in the Makefile, it doesn't have to be immediately before the target.
You can call bash directly, use the -c flag:
bash -c "diff <(sort file1) <(sort file2) > $#"
Of course, you may not be able to redirect to the variable $#, but when I tried to do this, I got -bash: $#: ambiguous redirect as an error message, so you may want to look into that before you get too into this (though I'm using bash 3.2.something, so maybe yours works differently).
One way that also works is putting it this way in the first line of the your target:
your-target: $(eval SHELL:=/bin/bash)
#echo "here shell is $$0"
If portability is important you may not want to depend on a specific shell in your Makefile. Not all environments have bash available.
You can call bash directly within your Makefile instead of using the default shell:
bash -c "ls -al"
instead of:
ls -al
There is a way to do this without explicitly setting your SHELL variable to point to bash. This can be useful if you have many makefiles since SHELL isn't inherited by subsequent makefiles or taken from the environment. You also need to be sure that anyone who compiles your code configures their system this way.
If you run sudo dpkg-reconfigure dash and answer 'no' to the prompt, your system will not use dash as the default shell. It will then point to bash (at least in Ubuntu). Note that using dash as your system shell is a bit more efficient though.
It's not a direct answer to the question, makeit is limited Makefile replacement with bash syntax and it can be useful in some cases (I'm the author)
rules can be defined as bash-functions
auto-completion feature
Basic idea is to have while loop in the end of the script:
while [ $# != 0 ]; do
if [ "$(type -t $1)" == 'function' ]; then
$1
else
exit 1
fi
shift
done
https://asciinema.org/a/435159

Procedure for using gdb to examine output and error messages returned by a called program

I've got a program written in C++ which has a function that looks similar to this:
std::string cmd = "curl -s http://x.x.x.x/latest/meta-data/public-hostname";
std::vector<std::string> output;
runCmd(cmd, output);
If the curl command fails the program silently ignores it. I need to be able to examine what's happening when the program gets to this point: I'd like to look at the output generated by curl, including error message and return code.
How do I do this with gdb? Please walk me through the steps of running the program with gdb so I can see what's happening with curl. It's a fairly large program. I am only interested in this particular function call, I want to ignore everything else up to that point.
i should note that I don't have the environment to compile the code. All I've got is the binary.
Not sure gdb will help you much as you spawn a sub process.
I would suggest changing the code to
std::string cmd = "curl -s http://x.x.x.x/latest/meta-data/public-hostname 2>/tmp/error | tee /tmp/output";
so that /tmp/erro and /tmp/output gives you what happened;
EDIT:
as compilation os not possible, you may use this trick:
create a script named curl containing:
#!/bin/bash
/usr/bin/curl $# 2>/tmp/error | tee /tmp/output
(don't forget to change permission to +x)
then, when executing your program just do:
PATH=.:$PATH ./yout_binary
assuming your script is in .
then the program will use your 'fake' curl
I would use strace for this task, rather then gdb:
strace -f -s 1024 -o log ./program
Here -f mean to trace child processes as well. You need it because this line of code runCmd(cmd, output); most likely does fork() to run child process.
-s 1024 specifies maximum string size to print. By default it is 32 which is often too short.
Once you save the output to log file, you should easealy find something like curl -s in it. This is where the child process starts. You can see what it writes to stderr or stdout in lines like write(2, "... or write(1, ".... At the end of the process execution you will see it's exit code, for example 1 exit code:
exit_group(1) = ?

gvim Regular expression in command Line

I want to apply some gvim regular expression to a file in command line. I understand that we have to use command gvim -c '<regexp>' $filename. But I open the file visually that user can see, is there any way to implement in the background, I mean without opening the file visually?
regards
keerthan
Alternatives
Unless you really need special Vim capabilities, you're probably better off using non-interactive tools like sed, awk, or Perl / Python / Ruby / your favorite scripting language here.
That said, you can use Vim (the terminal version, not GUI-only GVIM) non-interactively:
Silent Batch Mode
For very simple text processing (i.e. using Vim like an enhanced 'sed' or 'awk', maybe just benefitting from the enhanced regular expressions in a :substitute command), use Ex-mode.
REM Windows
call vim -N -u NONE -n -i NONE -es -S "commands.ex" "filespec"
Note: silent batch mode (:help -s-ex) messes up the Windows console, so you may have to do a cls to clean up after the Vim run.
# Unix
vim -T dumb --noplugin -n -i NONE -es -S "commands.ex" "filespec"
Attention: Vim will hang waiting for input if the "commands.ex" file doesn't exist; better check beforehand for its existence! Alternatively, Vim can read the commands from stdin. You can also fill a new buffer with text read from stdin, and read commands from stderr if you use the - argument.
Full Automation
For more advanced processing involving multiple windows, and real automation of Vim (where you might interact with the user or leave Vim running to let the user take over), use:
vim -N -u NONE -n -c "set nomore" -S "commands.vim" "filespec"
Here's a summary of the used arguments:
-T dumb Avoids errors in case the terminal detection goes wrong.
-N -u NONE Do not load vimrc and plugins, alternatively:
--noplugin Do not load plugins.
-n No swapfile.
-i NONE Ignore the |viminfo| file (to avoid disturbing the
user's settings).
-es Ex mode + silent batch mode -s-ex
Attention: Must be given in that order!
-S ... Source script.
-c 'set nomore' Suppress the more-prompt when the screen is filled
with messages or output to avoid blocking.
To modify the file using a regular expression, write it and quit immediately, you could use something like vim -c <command> -c x <file>. From a technical point of view, it is possible to suppress output by redirecting the standard streams and run this in the background – if that is what you want.

Using grep with execl()

A little context for my project: We have an arbitrary number of files that need a separate process for each file then need to search using an exec() call to find every time a specific KEY is used. I know how to use grep from the command line using this command:
grep -o KEY FILENAME.txt | wc -l > OUTPUT.txt
But I cannot figure out how to do this in c++. I found a thread on here that gave me this line.
execl("/bin/grep","grep",pattern,filename,NULL);
It compiles and runs so I think it works but the problem is I need to output the number of times the pattern occurred to a file and I tried the line below but expectedly it didn't work. It gave this error "grep: out.txt: No such file or directory"
execl("/bin/grep", "grep",pattern,fileName,output,NULL);
Here are the directions of this part of my project.
You can do this by means of the
system call exec() , providing it with the path to the executable of the shell (typically, /bin/sh )
and, as arguments of /bin/sh , the string -c and the string corresponding to the search command
( grep -o ... ).
Some guidance here would be much appreciated!
For the actual execution as you would do on command line would be:
execl("/bin/sh", "/bin/sh", "-c", "grep -o KEY FILENAME.txt | wc -l > OUTPUT.txt")
This will mean that the shell would take the line grep -o KEY FILENAME.txt | wc -l > OUTPUT.txt, interpret it and run it. Note that this will include wild card expansion and all what the shell does.
Then of course if you wan't to continue after it has completed you will have to fork first because execl does not return if it's successful at starting the program (ie bash).

Kill command line process and restart if STDOUT changes to what I'm looking for?

I have a question - I'm running a process from the command line that has some problem and poops out every few hours or so. While I'm looking into the issue, I'd like to spawn the process from something that monitors STOUT for certain string/regex and kills and restarts the process if it outputs something that indicates that it's broken.
I know I could do this the vanilla way by rolling my own Python/Ruby script but I was wondering if there's any nifty tools I can use to make this a bit cleaner? This is on Windows but I have cygwin in case the answer involves a unix command line process.
program | grep CRASH_STRING | xargs -l 1 sh -c 'killall program && program'
Well, that will do it once. I'm not sure how to make that work in a loop. I thought about it some more, and it can probably be done by redirecting stdout to a named pipe. But the shell script will probably end up more unwieldy than writing a watchdog in a scripting language.
But the idea with a pipe is something like this:
mkfifo /tmp/fifo
program > /tmp/fifo&
while :
do
grep "CRASH_STRING" /tmp/fifo | xargs -l 1 sh -c 'killall program && program > /tmp/fifo&'
done