Hello I'm new with C and I'm trying to start this lab where the command syntax is to first list any command line flags then list one or more file names.
I'm having trouble organizing how I want to scan the input arguments and differentiating them between flags and file names.
I thought of doing a loop to see if the argument is a flag or file name. But I'm unsure how to begin implementing it. Since the first 4 arguments can be potential flags in any order then anything after is the file name. But it is also possible for no flags to be given and just start with filenames. I don't know at all how to initalize this loop to go through each argument 1 by 1. Can anyone help please?
Example of possible command line arguments:
wc fcopy.c head.c (no flags given just file names)
wc -l -c -w -L fcopy.c head.c a.exe (flags given and multiple files)
wc -l -w -c -L fcopy.c (flags given and 1 file name)
Reading command line args one by one is pretty simple:
int main( int argc, // Number of strings in array argv char *argv[])
The two basic args to a C function are argc (int number of args), and argv (an array of strings for the args)
The first string is always the name of the program that is running, after that is the args that were passed over the command line.
if(argc > 1)
for( count = 1 count < argc; count++ )
printf("%s", argv[count]);
Will display to the screen each of the arguments passed in past the name of the calling program.
I assume your flags are passed with a "-" as the first character? If so, you can check the contents of the first character in each string for a '-' to tell if its a flag or not.
You can use getopt()
Check these questions:
Parsing command-line arguments?
Handling command line options before and after an argument in C
Argument-parsing helpers for C/UNIX
Getopt shift optarg
Check out getopt, it allows you to parse command line arguments and their flags:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main (int argc, char **argv)
{
int aflag = 0;
int bflag = 0;
char *cvalue = NULL;
int index;
int c;
opterr = 0;
while ( (c = getopt (argc, argv, "abc:")) != -1 )
switch (c) {
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c':
cvalue = optarg;
break;
case '?':
if (optopt == 'c')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
default:
abort ();
}
printf ("aflag = %d, bflag = %d, cvalue = %s\n",
aflag, bflag, cvalue);
for (index = optind; index < argc; index++)
printf ("Non-option argument %s\n", argv[index]);
return 0;
}
Example of Parsing Arguments with getopt
Also see http://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html
Related
I noticed during debugging that the optarg variable of GNU's getopt remained zero (i.e. address 0x0) during debugging. But when optarg is used as right-hand operand of assignment or passed as argument to a parameter, the expected value is applied. The example from GNU:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main (int argc, char **argv)
{
int aflag = 0;
int bflag = 0;
char *cvalue = NULL;
int index;
int c;
opterr = 0;
while ((c = getopt (argc, argv, "abc:")) != -1)
switch (c)
{
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c': # b 26
cvalue = optarg; # gdb stops right before executing this line
break;
case '?':
if (optopt == 'c')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
default:
abort ();
}
printf ("aflag = %d, bflag = %d, cvalue = %s\n",
aflag, bflag, cvalue);
for (index = optind; index < argc; index++)
printf ("Non-option argument %s\n", argv[index]);
return 0;
}
Usage
$ gcc -o getopt getopt.c -g # debugging ON, optimizations OFF
$ gdb getopt
(gdb) b 26 # set breakpoint
(gdb) r -cfoo
(gdb) p optarg
$1 = 0x0 # no "foo"?
(gdb) n # executes cvalue = optarg
(gdb) p cvalue
$2 = 0x7fffffffea99 "foo" # here it is, please don't expect to get the same memory-address
Why optarg doesn't contain the character string "foo" at line 26? What do I miss here?
More bewildering, I figured out it doesn't contain "foo" even after the line has been executed. I've put a glance at the original source and didn't notice something like a compiler optimization. I'm using GCC 11.1.0 on Archlinux, x86_64.
Thank you
PaulMcKenzie seems right. It is probably this old bug 8588 within GDB. GDB struggles handling the GOT (Global-Offset-Table) right which is a part of PIC (Position-Independent-Code].
Workaround
p (char*)'optarg#GLIBC_2.2.5'
We reference here the variable optarg and the version symbol of the GLIBC. The version 2.2.5 is the baseline which already includes provides GNU getopt and therefore the newer ones don't apply.
Thank you
This is my first post on this site so please forgive any formatting errors.
I am coding a small program to get simple information from a file like amount of words, sorting it etc. However I started simply by using getopt since I want to use the command line to parse my commands. This is what I have so far.
#include <stdio.h>
#include <stdlib.h>
int value = 0;
int main(int argc, char **argv) {
extern char *optarg;
extern int optind;
int c, err = 0;
int cflag = 0, sflag = 0, fflag = 0;
char *substring;
// usage from instructions in case of error
static char usage[] = "usage: mywords [-cs] [-f substring] filename";
// only f flag requires additional input
while ((c = getopt(argc, argv, "csf:")) != -1)
switch (c) {
case 'c':
cflag = 1;
break;
case 's':
sflag = 1;
break;
case 'f':
fflag = 1;
printf("Before assigning to substring\n");
substring = optarg;
printf("After\n");
break;
case '?':
err = 1;
break;
}
if (fflag = 1) {
printf("%c ", &substring);
}
}
I will then input something like this to the command line after I run my makefile (which runs successfully with no errors):
mywords -f test
and ideally the output would be
test
The printf statements I have in the fflag are simple test prints to see if I was even reaching there. Thank you for your help in advance.
EDIT
It was fixed. David Collins had the right answer. Thank you so much everyone
I have noticed three issues in you code. (There may be other small issues but addressing the following should get you up and running I think.)
Testing for equality
You should use if (fflag == 1) instead of if (fflag = 1).
Pointer de-referencing
If you want to retrieve the value of the character pointed to by substring, you would use *substring instead of &substring.
But you probably don't want to do this. See below.
printf() format specifiers
When printing a string / character array, use the %s specifier instead of %c. (%c is for single characters). So you should have
if (fflag == 1) {
printf("%s ", substring);
}
Or - more simply - just
if (fflag) {
puts(substring)
}
since any non-zero value evaluates to true in C (and you initialize fflag to zero at the start of your program).
I am working on trying to take in command line arguments. If I want to have multiple optional command line arguments how would I go about doing that? For example you can run the program in the following ways:
(a is required every instance but -b -c -d can be given optionally and in any order)
./myprogram -a
./myprogram -a -c -d
./myprogram -a -d -b
I know that getopt()'s third argument is options. I can set these options to be "abc" but will the way I have my switch case set up causes the loop to break at each option.
The order doesn't matter so far as getopt() is concerned. All that matters is your third argument to getopt() (ie: it's format string) is correct:
The follow format strings are all equivalent:
"c:ba"
"c:ab"
"ac:b"
"abc:"
In your particular case, the format string just needs to be something like "abcd", and the switch() statement is properly populated.
The following minimal example¹ will help.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main (int argc, char **argv)
{
int aflag = 0;
int bflag = 0;
char *cvalue = NULL;
int index;
int c;
opterr = 0;
while ((c = getopt (argc, argv, "abc:")) != -1)
{
switch (c)
{
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c':
cvalue = optarg;
break;
case '?':
if (optopt == 'c')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
default:
abort ();
}
}
printf ("aflag = %d, bflag = %d, cvalue = %s\n",
aflag, bflag, cvalue);
for (index = optind; index < argc; index++)
printf ("Non-option argument %s\n", argv[index]);
return 0;
}
¹Example taken from the GNU manual
I wrote (copied and pasted from Google and simplified) a C program to use getopt to print out the values of the arguments passed in from the Unix command line.
From Unix command line:
./myprog -a 0 -b 1 -c 2
My C code is:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int i;
while ((i = getopt(argc, argv, "abc")) != -1) {
switch (i) {
case 'a':
printf("A = %s\n", optarg);
break;
case 'b':
printf("B = %s\n", optarg);
break;
case 'c':
printf("C = %s\n", optarg);
break;
default:
break;
}
}
return 0;
}
I want to program to print out each of the values passed e.g.
A = 0
B = 1
C = 2
However it is not printing out anything at all.
You forget about ":" after any option with argument. If you will change one line
while ((i = getopt(argc, argv, "a:b:c:")) != -1) {
you will get working variant.
Read properly man 3 getopt, it said about third argument of getopt that
… optstring is a string containing the legitimate option characters. If such a character is followed by a colon, the option requires an argument, so
getopt() places a pointer to the following text in the same argv-element, or the text of the following argv-element, in optarg. Two colons mean an option
takes an optional arg; if there is text in the current argv-element (i.e., in the same word as the option name itself, for example, "-oarg"), then it is
returned in optarg, otherwise optarg is set to zero. …
I need to use getopt to parse the following command:
./center -n name –cp Anumber –i Anumber –t Anumber –s Anumber -fc nameOfaFile
All of them can be given out in any order.
So its clear i have to use getOpt.
So i have been investigation and this is what i have so far
void check_parameters (int argc, char** argv) {
int opt;
while((opt = getopt(argc, argv, "n:cp:i:c:fc:")) != -1) {
printf("give me opt %c \n", opt)
swicth(opt){
case 'n' :
//do something
case 'cp' :
//do something
case 'i' :
//do something
}
}
}
I do know for a fact that the 3 parameter: the OptString is where i tell getOpt what are the char of the options it should expect
Also in optarg is where the argument is
its not working!
when i printf( "give me opt %c", opt ) its giving me the numbers, not the char!
for this reason it does not work. it does not check the parameters correctly
Edit:
After doing man 3 getopt
the return value of getopt is: If an option was successfully found, then getopt() returns the option character. If all command-line options have been parsed, then getopt() returns -1.
it returns the option character? it always return integer 1. always! i don't understand how getopt works. how does the switch compare to characters?!
First of all, this:
case 'cp':
...makes no sense. You can't represent two characters with a char or int. Besides, if running your program with -cp 101, getopt will treat it as -c p 101, for a completely different result. If you want to use long options, use getopt_long instead and the appropriate calling syntax, per example: ./a.out -n 42 --cp 101.
Now, here's a working example of getopt() in action:
#include <stdio.h>
#include <getopt.h>
int main(int argc, char* argv[]) {
int opt;
while((opt = getopt(argc, argv, "n:cp:i:c:fc:")) != -1) {
switch (opt){
case 'n':
printf("n was %s\n", optarg);
break;
case 'i':
printf("i was %s\n", optarg);
break;
}
}
return 0;
}
getopt handles only single-character option names, not things like -cp or -fc (which it interprets as multiple option flags in a single string: -c -p, -f -c). If you want to stick to the syntax you defined, then it's easier to just roll your own:
// first check whether argc is odd, then:
for (i = 1; i < argc; i += 2) {
if (strcmp(argv[i], "n") == 0) {
name = argv[i+1];
} else if (strcmp(argv[i], "cp") == 0) {
// etc. etc.
}
}