I need a hand in terms of processing command line argument (on Windows) in C.
Suppose I have the following situation
C:\Users\USER\Desktop> my_executable arg1 ' "A>200 && B<300 (just some conditions" '
In this case argc = 5
and
C:\Users\USER\Desktop> my_executable arg1 '"A>200 && B<300 (just some conditions"'
In this case argc = 3
Depending on users, the argv and argc will be different.
How can I write the code such that the condition and arg1 can be stored correctly :)
Required:
arg1 is stored into a char pointer
condition is also stored into a char pointer
Thanks
Don't use single quotes as argument quotes on Windows unless you want to implement your own argument parser. ^ can be used to escape " and itself and a few other things. To embed " in arguments use "".
If you really need to, call GetCommandLineW and parse yourself. GetCommandLineW returns a string that consists of the executable image name possibly enclosed in double quotes, followed by an optional space and the arguments exactly as given to CreateProcess (which means that ^ processing has already taken place).
Related
My program takes an arbitrary number of words from the user and stores them in a double pointer **stringArr. These values are then concatenated into a string which is then passed into a bash script I have.
The problem I have is that the bash script doesn't echo the command I want it to, and I am unsure why.
string = malloc(N * sizeof(char));
for (int j = 0; j < N; j++) {
strcat(string, stringArr[j]);
strcat(string, " ");
}
puts("\n\nYour input sorted in alphabetical order:");
if (fork() == 0) {
execl("./sortString.sh", "sortString.sh", string, NULL);
}
#!/bin/bash
for NAME in "$#"
do
VAR=$VAR" "$NAME
done
echo $VAR | tr ’ ’ ’\n’ | sort | tr ’\n’ ’ ’
Is there something I am missing?
Note: the bash script is in the same directory as the program; the program works in regards to taking user input and it putting into the string string.
If you want to try out the bash script, an example of string I have passed through is: "one two three " (there is a space after 'three').
You cannot use the exec() family of functions to execute a shell script directly; they require the name of a proper executable. If you check the return value of your execl() call, I'm sure you'll see an error (-1), and errno will probably have been set to ENOEXEC.
You could try using system() instead, but it is generally frowned upon because you'd need to build a full (single) command string, and making sure that everything is properly escaped and such is error-prone.
Instead, I'd recommend that you give "/bin/sh" or "/bin/bash" as the first argument to exec(). Then, the args to sh would need to be the path of your script, and then the args that your script will use.
(this is what your shell does automatically when you run a script; it reads the #! line, and executes "/bin/bash your-script your-args...")
Your string allocation is too small. You're allocating space for N chars, but you're strcating N spaces into it, plus whatever is in your stringArr (which I assume is not full of empty strings).
Even then, you will have just one big string of args, but exec() wants them separated. Think of it like if you point quotes around all the args in bash; you get just one big argument, which contains spaces.
After you fix that (so that you have an array of strings rather than just one big one), you will run into problems with execl(). It takes the arguments separately, but you're trying to send one big array of them. You'll want execv() instead, which accepts an array of strings for the argument list. Remember that the first string in that list must be your script path.
Are you sure this wouldn't be easier to do with qsort()?
I'm having some trouble reading a line of the code, and understanding what constitutes an argument in the context of this line of code. This is saved in a file called argv0.c
#include <cs50.h>
#include <stdio.h>
int main(int argc, string argv[])
{
if (argc == 2)
{
printf("hello, %s\n", argv[1]);
}
else
{
printf("hello, world\n");
}
}
I compile the code as follows:
make argv0
./argv0
following which I am prompted for an input. Herein lies the issue:
if I type in "Dion Lim" in the terminal, is Dion Lim considered an argument? If so, is it two arguments?
Why is it that if I type in "Dion Lim" in the terminal, I get "Hello, World", but if I type in "Dion" i get "Hello,Dion"
Q1) Yes, they are two arguments.
Q2) Because argc consider the name of executable it's the first parameter. So:
./argv0 Dion Lim // argc == 3
./argv0 Diom // argc == 2
./argv0 // argc == 1
You can get more detail here.
if I type in "Dion Lim" in the terminal, is Dion Lim considered an
argument? If so, is it two arguments?
It depends on how your shell handles it of course, but usually "Dion Lim" would be one argument while Dion Lim (without the quotation marks) would be two arguments. The space delimits the arguments, and with the quotes you can work around that if you want space in your input (sometimes you can also escape the space, like Dion\ Lim).
Why is it that if I type in "Dion Lim" in the terminal, I get "Hello,
World", but if I type in "Dion" i get "Hello,Dion"
The argc parameter tells you how many arguments you have (I think of it as standing for "argument count"). The program's name also counts as an argument, so if you only pass Dion, then argc will be 2 already. If you pass Dion Lim, it will be 3.
To see the number of arguments check the value argc (arguments count). There is always at least one input argument, which is the program name.
So with./argv0 Dion Lim there are three input arguments.
If you are wondering make compiles the program using Makefile so if look in the directory you from which you are running make you will find a file named Makefile containing the compilation instructions.
According to the C Standard (5.1.2.2.1 Program startup)
— If the value of argc is greater than zero, the string pointed to
by argv[0] represents the program name; argv[0][0] shall be the null
character if the program name is not available from the host
environment. If the value of argc is greater than one, the strings
pointed to by argv[1] through argv[argc-1] represent the program
parameters.
So if you "manually" supply the argument Dion then argc will be exactly equal to 2. The first program parameter will be the program name (as it is followed from the quote) and the second program parameter will be the word Dion.
If you will type Dion Lim then the host system considers them as two program parameters and together with the program name argc will be equal to 3.
However if you enclose the input Dion Lim in parentheses like "Dion Lim" then the system will consider the input as one parameter and your program will output
hello Dion Lim
I'm trying to see if * is passed in as a parameter in argv, but I'm not sure how to begin testing for it. When I did a
printf("%s\n", argv[1]);
The code prints out 1. I tested and ran
./a.out \*
To escape the input, which did work and printed "*", but I want t be able to pass in * without escaping from the user end and be able to see that * is passed. I can't just test for
if (strcmp(argv[1], "1") == 0)
Because that'd be testing if I passed in 1 like
./a.out 1
How should I do this??
This is nothing to do with c. Its your shell processing its line before running your program. You don't specify your os, but you will need to escape the arguments whatever
The shell is responsible for command line preprocessing before it runs a program. * is knowns as a wildcard. It is not the only wildcard, there are also ?, [, { and substitutons of $. You can escape preprocessing wildcards by prefixing them with \ or enclosing parameters in quotations '
./a.out '*'
I can't just test for
if (argv[1] == "1")
Because that'd be testing if I passed in 1 like
./a.out 1
You can not test it either. argv[1] == "1" does not compare strings, it compares pointers and the comparison always is false.
I am writing an option parser for a bash-like shell I develop.
Nevertheless, to be compatible with bash options, I must read some options which begin with a '+', like this:
./42sh +O autocd [...]
(The manual page says these options will passed to the builtin shopt which sets the values of settings).
The problem is that getopt_long() function only returns the options which begin with a - or --, if they are not alone. If they are, bash counsider them respectively as an alias for standard input and a end of options marker.
How I could get this type of options with getopt_long() ? Have I to parse these options by myself ?
EDIT : according to the #jxh response and the man 3 getopt page, I discovered that getopt and getopt_long arranges the **argv parameters array to move all arguments that don't seem to be valid options - from their point of view - at the end. So, I wrote the following code after the usual code which gets the normal options (all suggestions and remarks greatly appreciated):
EDIT2 : fixed memory leak due to strdup() at each iteration of the loop.
for(; optind < argc; ++optind)
{
const char *argv_copy = strdup(argv[optind]);
if (argv_copy[0] == '+' && argv_copy[1] == 'O')
{
/* A deactivation parameter have been just found ! */
if (handle_shopt_options(shell_options,
argv[optind + 1],
DISABLE) == EXIT_FAILURE)
{
usage(argv[optind]);
free_shell_options(shell_options);
shell_options = NULL;
}
++optind;
}
free(argv_copy);
argv_copy = NULL;
}
Some explanations:
optind is the argv index which tells us which argument will be parsed at the next pass. Since we parsed all the getopt() point-of-view valid arguments, and since getopt() moves all the non-options at the end, we will parse all remaining arguments, included the ones which interest us.
argv[argc] == NULL : this trick is used to know where is the end of the arguments list, so it is useless to parse the argument when optind == argc.
I am not comfortable to play directly with the current argv value, so I preferred to copy it in a new string, but I am probably wrong, to be verfied.
Some remarks:
getopt_long() will be available only if _GNU_SOURCE macro is defined.
strdup() will be available only if macro _XOPEN_SOURCE >= 500 or macro _POSIX_C_SOURCE >= 200809L.
As you have noted in your research, you cannot use getopt_long to parse options that begin with +.
As a workaround, you can scan argv[] yourself, and then create a new argument vector that substitutes --plus- in front of every argument you think is a + style option in the original argv[]. This new array should be parseable by getopt_long.
I am reading the book Windows System Programming. In the second chapter, there is a program Cat.c , It implements the cat command of linux. The code is http://pastebin.com/wwQFp599
On the 20th line, a function is called
iFirstFile = Options (argc, argv, _T("s"), &dashS, NULL);
Code for Option is http://pastebin.com/QegxxFpn
Now, the parameters for option is
(int argc, LPCTSTR argv [], LPCTSTR OptStr, ...)
1) What is this "..."? Do it mean we can supply it unlimited number of arguments of type LPCTSTR ?
2)If I execute the program as cat -s a.txt
a) What will be the argc and why?
b) What will be the argv and why?
c) What is _T("s")? Why _T is used here?
d) Why &dashS is used? It is address of a boolean most probably. But I can't understand the logic behind use of this.
e) Why they have passed NULL as last parameter?
I have Basic knowledge of C programming and these things are really confusing. So kindly explain.
You have two different kinds of "variable" lists of arguments here.
First, you have the arguments passed to the program on the command line, clearly a person could invoke the program from the command line with many arguments
cat file1 file2 file3
and so on. The main() of C programs have since the early days of C given access to the command line arguments in the variables argc and argv, argc is the count of how many arguments (3 + the name of the pogram itself in my example above) and argv is the array of the arguments (actually an array of pointers to strings) So in this case we can access argv[0], argv[1], arv[2] and argv[3], knowing to stop there because argc tells us there are four arguments.
So in your example argc will be 3, argv[0] will point to "cat", argv[1] to "-s" and argv[2] to "a.txt".
Next the function you are looking at itself takes an indefinate number of arguments as indicated by the elipses - the ...
You need to read about variable arguments. This is a language feature that was not in the earliest C language, and is considered to be a little bit advanced, hence some of your books either may not cover it, or leave until late in the book. The key point here though is that we interpretting the variable list we need to know when we have reached the end of the variable list, we don't have an "argc" equivalent. So we put a "this is the last one, stop here" value in the function call, that's the NULL you ask about.
1) "..." is a variable argument list as username Cornstalks pointed out. It allows functions like printf() to have a variable number of arguments but their type and number of arguments have to be specified in one of the arguments (like the formatting string for printf()). See *va_list.h* or stdarg.h.
2) a) argc is the number of arguments specified at the command line.
b) argv is the argument array, it's an array of strings.
c) The _T() is a macro, I know it as TEXT(). Basically it allows programmers to use either ASCII strings or Unicode strings at build time without having to modify the entire code. If the UNICODE macro is defined the string specified as argument to the _T() macro becomes L"string", else it becomes "string". That's why some functions have an A or a W as a last letter. For example, OutputDebugString defaults to OutputDebugStringW if UNICODE is defined and OutputDebugStringA if UNICODE is not defined. The functions that have A as a last letter in their name only accept ASCII strings while W only accepts Unicode strings. There's also a type defined for this purpose, TCHAR defaults either to CHAR or WCHAR, and there's also another entry point, i.e. _tmain().
d) &variable means the address of a variable. It is used to pass along to a function the location in the memory of the variable contents so that if the function modifies the value of the variable, the variable is modified everywhere else where it is used.
e) You'll have to look at the function prototype.
It seems to me that you have been misled to believe that starting Windows Programming is the way to go if you want to learn to program. The C and C++ programming languages are OS independent by default and you should learn the independent part first. I recommend "C Programming : A modern approach".