I'm trying to scan the command line for certain letters, symbols and values. I want to scan for "-w", a number, and "-s". I got a response in my last question, I was told to use getopt() and after a little bit of Googling, I think I might get it, but I'm not sure.
This is what I think I'm doing:
int c = 0;
int b = argv[2];
while((c = getopt(argc, argv, "-w", "-s", b))
I think I'm scanning argc for "-w", "-s" and the argv[2] value (which is the number). But I do not know if I am using it correctly?
Your while loop should be
while ((c = getopt(argc, argv, "w:s:"))
: the colon means it needs an argument. now convert optarg to an integer or whatever you wanted.
int number = 0;
int sflag = 0;
int opt;
while ((opt = getopt(argc, argv, "w:s")) != -1)
{
switch (opt)
{
case 's':
sflag = 1;
break;
case 'w':
number = atoi(optarg);
break;
default:
/* Report usage and exit? */
break;
}
}
The conversion on the number is lazy; you can do more a more careful job calling a function that calls strtol(), for instance. You might need to have a wflag variable that you set analogously to the sflag variable so that you can distinguish -w 0 from 'no -w option specified on the command line'.
Related
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).
Hi I am working on a Program in a book. The Program is working almost as it is supposed to, except for one mistake. Every time I try to use the "-l" case I get a Segmentation Fault. Any Ideas?
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char *lieferung = "";
int knusprig = 0;
int zahl = 0;
char ch;
while ((ch = getopt(argc, argv, "l : k")) != EOF){
switch (ch) {
case 'l':
lieferung = optarg;
break;
case 'k':
knusprig = 1;
break;
default:
fprintf(stderr, "Unbekannte Option: '%s'\n", optarg);
return 1;
}
}
argc -= optind;
argv += optind;
if (knusprig)
puts("Knuspriger Rand.");
if (lieferung[0])
printf("Zu liefern: %s.\n", lieferung);
puts("Zutaten:");
for (zahl = 0; zahl < argc; zahl++)
puts(argv[zahl]);
return 0;
}
Thanks in advance.
The third argument get getopt shouldn't contain any spaces. Because there are spaces, it reads this argument as "-l takes no argument, -(space) takes an argument, -(space) takes no argument, and -k takes no argument.
Since getopt doesn't expect -l to pass an argument, optarg is set to NULL, which you then subsequently assign to lieferung. You then dereference that variable, resulting in the segfault.
Git rid of the spaces in the format string:
while ((ch = getopt(argc, argv, "l:k")) != EOF){
I think the format is incorrect. Replace "l : k" with "l:k".
I have an assignment in C that requires options to be read in for different forms of a program. Before I start on that, though, I want to make sure that the getopt portion is working fine. However, the program keeps dropping the last parameter and I don't know why. Whenever I enter the last char, the program goes to the default value that kills the program. Any help is appreciated!
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
int main(int argc, char **argv)
{
int sFlag = 0;
int lFlag = 0;
int dFlag = 0;
int rFlag = 0;
int c;
opterr = 0;
while ((c = getopt (argc, argv, "slr:")) != -1)
{
switch(c)
{
case 's':
sFlag = 1;
break;
case 'l':
lFlag = 1;
break;
case 'r':
rFlag = 1;
break;
default:
printf("unknown parameter introduced");
exit(-1);
break;
}
}
printf("s = %i, l = %i, d = %i, r = %i", sFlag, lFlag, dFlag, rFlag);
return 1;
}
The colon symbol after r in "slr:" tells getopt() to wait for a mandatory argument which follows -r.
Examples:
getopt(argc, argv, "slr:") can parse ./project -s -l -r r_arg (or ./project -r r_arg -s etc.)
getopt(argc, argv, "s:lr:") can parse ./project -s s_arg -l -r r_arg
getopt(argc, argv, "s:lr:") can also parse ./project -s -l -r r_arg with no error, but the program works differently from user's expectation. This is because getopt() expects -s to be followed by its argument, however it looks like, so the next argument -l is consumed and will not hit your switch(c).
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.
}
}
I want the put a sub-option in a string so that I can use it as a file name for reading a file:
char *nvalue = NULL;
char *dvalue = NULL;
char *input = NULL;
char inputfilename[] = "\"";
int ar;
int main(int argc, char *argv[])
{
while ((ar = getopt(argc, argv, "hn:d:i:")) != -1)
switch (ar)
{
case 'h':
printf("something");
break; /* added */
case 'n':
nvalue = optarg;
if (isdigit(nvalue))
stop = atoi(nvalue);
else
printf("something\n");
break; /* added */
case 'd':
dvalue = optarg;
if (!strcmp(dvalue, "FCFS") || !strcmp(dvalue, "SSTF") ||
!strcmp(dvalue, "C-SCAN") || !strcmp(dvalue, "LOOK"))
;
else
printf("Invalid type of disk scheduling policy entered.\n");
break; /* added */
case 'i':
input = optarg;
strcpy(inputfilename, optarg);
printf("Filename :%s\n", inputfilename);
break;
}
/* ... */
}
So on the command line if I input:
./foobar -i hello
then I should be able to read the file with:
FILE *file = fopen(inputfilename, "r" );
any suggestions? answers?
thanks!
There are a number of problems with your code. I'm ignoring the absence of header files (assuming your code uses the correct ones so all functions have a prototype in scope before use). I'm also reformatting your code ruthlessly but without further comment.
char *nvalue = NULL;
char *dvalue = NULL;
char *input = NULL;
char inputfilename[] = "\"";
This allocated an array of two bytes as inputfilename. I hate to think what's going to happen when you use it.
int ar;
There is every reason why this variable should be local to the main function and no reason visible for it to be a global variable. Unless you have a header declaring them, the other variables should also be static - assuming that you need to access their values outside of main() without a convenient way to pass them as locals. Avoid global variables whenever possible.
int main(int argc, char *argv[])
{
while ((ar = getopt(argc, argv, "hn:d:i:")) != -1)
{
switch (ar)
{
case 'h':
printf("something");
Oops; no break, so the code drops through to the case 'n': code. C is not Pascal.
case 'n':
nvalue = optarg;
if (isdigit(nvalue))
stop = atoi(nvalue);
You haven't shown a declaration for stop. Unless you really need the string, you can do without nvalue, avoiding a global variable, which is always desirable.
else
printf("something\n");
Another missing break; I'm not going to point it out again.
case 'd':
dvalue = optarg;
if (strcmp(dvalue, "FCFS") == 0 ||
strcmp(dvalue, "SSTF") == 0 ||
strcmp(dvalue, "C-SCAN") == 0 ||
strcmp(dvalue, "LOOK" == 0)
{
I'd suggest a comment such as /* Nothing - dvalue is OK */. Or inverting the condition using De Morgan's theorem:
if (strcmp(dvalue, "FCFS") != 0 &&
strcmp(dvalue, "SSTF") != 0 &&
strcmp(dvalue, "C-SCAN") != 0 &&
strcmp(dvalue, "LOOK" != 0)
You might even decide to encapsulate that test into a function which tests the value against each element of an array of codes.
}
else
printf("Invalid type of disk scheduling policy entered.\n");
It would be courteous to provide a list of the acceptable values - which suddenly becomes another reason for having an array of valid values which you can use to generate the list. Very often, error messages should be reported on stderr (using fprintf()) rather than stdout.
case 'i':
input = optarg;
This assignment is sufficient.
strcpy(inputfilename, optarg);
Unless the user types a single-character file name, you've just overflowed the inputfilename array. You really didn't need to make a copy of the argument unless you're going to modify the name (for example, to add or change the extension on the name).
//strcat(inputfilename,"\"");
printf("Filename :%s\n", inputfilename);
}
You didn't include a default clause. Since ar will be assigned the value ? when the user-provided option is not recognized, this is normally your cue to provide a simple usage message and exit.