Define custom command-line parameters in C? - c

I need to pass a 'key' as a parameter from terminal. It should run as ./a.out -k100101001
where 10011001 is the key and -k is the flag to specify it.
If I need to pass a filename along with the key it should run as ./a.out -k10011001 -iparameter.txt where parameter.txt is the filename and -i is the flag to specify that.
NOTE: I have several parameters to pass and parameter values are followed after the flag without space(-iparameter.txt), plus I don't know the order of the flags so doing something like this won't help.
int main(int argc, char **argv) {
if (argc == 2) {
if (!strcmp(argv[1], "-k")) something();
if (!strcmp(argv[1], "-i")) something();
}
Any suggestion for C? I'm using Ubuntu to run my program.
Thanks.

Using a loop through argv should do it.
int main(int argc, char *argv[])
{
int numArg;
for (numArg = 1; numArg < argc; numArg++)
{
if (argv[numArg][0] == '-')
{
switch (argv[numArg][1])
{
case 'k' : somethingAboutKey(argv[numArg] + 2); // The parameter's value is passed directly to the function
break;
case 'i' : somethingAboutFile(argv[numArg] + 2);
break;
}
}
}
}

Related

Implementing parsing with the ls command in C

I'm trying to implement the ls command in C with a few parameters like -a, -l... or -la, but I'm having issues with the parsing, when I use the input I get Segmentation Fault, this is an example of the -a parameter:
int comparator(char *av) {
int i = 0;
if (my_strcmp((av[i]), "-a") == 0)
return 0;
else
return 1;
}
int my_ls_a(char *path) {
int comp = comparator(path);
DIR *pdirec = opendir(".");
struct dirent *direc;
direc = readdir(pdirec);
while (direc != NULL || comp == 0) {
my_printf("%s ", direc->d_name);
direc = readdir(pdirec);
}
if ((path = readdir(pdirec)) == NULL)
my_printf("\n");
if (pdirec == NULL)
return (84);
closedir(pdirec);
return (0);
}
And this is my main:
int main(int ac, char *av[]) {
if (ac == 1)
my_ls_a(av[0]);
return 0;
}
I already have all the #include in a .h by the way.
When I only use the main function it works but not when I add the parameter -a.
It's probably better to use getopt() for parameter parsing instead of writing your own parser.
You have undefined behavior in the function comparator in my_strcmp((av[i]), "-a") because av is defined as a char * so you are passing a character where my_strcmp probably expects a pointer.
You should compile with -Wall -Werror to avoid such silly mistakes.
It is unclear why you pass only a single argument to my_ls_a. You should pass both ac and the argument array av and iterate on the arguments to parse the options.

How do I recall main using different arguments?

I have my program and it runs like I expected, however, I want to call it again but this time I want to use different arguments. How can I do that?
It seems I cant just use main(filename1,filename2)and then follow the same routine I did last before.
My main looks like this
int main(int argc,char* argv[])
{
if (argc<3)
{
printf("Error no filenames\n");
return -1;
}
char* filename=argv[1];
char* fileout=argv[2];
int count_Pharmacy;
int count_Surgicaly;
int count_General;
int count_Counselling;
char pick;
patient* Pharmacy_head=NULL;
patient* General_head=NULL;
patient* Surgical_head=NULL;
patient* Counselling_head=NULL;
dep* dep_head=NULL;
Counselling_head=get_patient(Pharmacy_head,filename,"Counselling");
Surgical_head=get_patient(Pharmacy_head,filename,"Surgical");
General_head=get_patient(Pharmacy_head,filename,"General");
Pharmacy_head=get_patient(Pharmacy_head,filename,"Pharmacy");
count_Pharmacy=count_patient(Pharmacy_head);
count_Surgicaly=count_patient(Surgical_head);
count_General=count_patient(General_head);
count_Counselling=count_patient(Counselling_head);
dep_head=make_deparments(dep_head,"Counselling","Dr. Willy",Counselling_head,count_Counselling);
dep_head=make_deparments(dep_head,"Surgical","Dr. Neo Cortex",Surgical_head,count_Surgicaly);
dep_head=make_deparments(dep_head,"General","Dr. Ann Imezechara",General_head,count_General);
dep_head=make_deparments(dep_head,"Pharmacy","Dr. Charles Xavier",Pharmacy_head,count_Pharmacy);
treatment(dep_head,fileout);
printf("The patients have been treated would you like to add another file?(Y/N)\n");
pick=fgetc(stdin);
if (pick=='y' || pick =='Y')
{
//this is where i would like to call main again but with diffrent arguments
}
else if(pick =='N' || pick=='n')
{
printf("Goodbye have a marvelous day\n");
}
else
{
printf("Thats not a valid input but ill take that as a no\n");
}
return 1;
}
The two arguments I called main with the first time are file names.
char * new_argv [4];
int new_argc = 3;
new_argv [0] = argv [0]; // program name
new_argv [1] = "file1";
new_argv [2] = "file2";
new_argv [3] = 0;
main (new_argc, new_argv);

Function Pointers not working in getopt

I have some code which tests the robustness of a variety of PRNGs, and I want to choose which PRNG is being tested using options.
I have a function pointer type: typedef double (*voidPRNG_ptr)(void);
I have a testing function: test_results* investigator_alloc(int N, voidPRNG_ptr RNGp)
Where test_results is a typedef'ed struct.
I have PRNG functions: double box_muller(void), double rejection(void), double RNG(void), etc...
The following code in main works FINE:
int main(int argc, char** argv){
int N = atoi(argv[1]);
voidPRNG_ptr PRNGp = &box_muller;
test_results* results = investigator_alloc(N, PRNGp);
return 0;
}
The box_muller function is used as the RNG, and data is as expected.
This also WORKS FINE:
int main(int argc, char** argv){
int N = atoi(argv[1]);
voidPRNG_ptr PRNGp = &box_muller;
PRNGp = &rejection;
test_results* results = investigator_alloc(N, PRNGp);
return 0;
}
The rejection method is used as the RNG, as expected.
However, this DOESN'T work:
int main(int argc, char **argv){
int opt;
int atest = 0;
voidPRNG_ptr PRNGp = &RNG; //set default
while((opt = getopt(argc, argv, "abur")) != -1){
if(opt == 'a') {
PRNGp = &normal_approx;
atest = 1;
}
else if(opt == 'b') PRNGp = &box_muller;
else if(opt == 'u') PRNGp = &RNG;
else if(opt == 'r') PRNGp = &rejection;
}
printf("\n %d\n",atest);
int N = atoi(argv[1]);
//PRNGp = &rejection;
//PRNGp = &normal_approx;
//PRNGp = &box_muller;
test_results *results = investigator_alloc(N,PRNGp);
return 0;
}
I know that getopt is working as atest is set to the right value depending on the option selected. But there must be something wrong with the function pointer as the data is blank.
Any ideas?
Thanks!
The issue is that you're applying atoi() to the first command-line argument, which is the option that tells your program which RNG to use. Since argv[1] is not numeric, you end up with N=0 and no data.
Change argv[1] to argv[optind] (see Using the getopt function).

C - argc changes with operation

for some reason my argc argument changes from 4 to 6 if instead of "a+bi + c+di" I write "a+bi * c+di" and I don't know why. What is happening and how can I solve it?
Thank you
#include <stdio.h>
#include <string.h>
#define FORMATLOG "Invalid Input. Required format: <a+bi> <operator> <c+di>"
#define INPUTLOG "Error: Trying to operate with different sets of numbers"
enum { true, false };
typedef struct {
double realp, imagp;
} Complex;
int checkIfComplex(char *exp) {
unsigned int i = 1;
if(exp[strlen(exp) - 1] == 'i')
while(exp[i] != '\0') {
if(exp[i] == '+' || exp[i] == '-')
return true;
i++;
}
return false;
}
Complex parseComplex(char *exp) {
Complex number;
sscanf(exp, "%lf + %lfi", &number.realp, &number.imagp);
return number;
}
int main(int argc, char **argv) {
printf("%d", argc);
if(argc != 4) {
puts(FORMATLOG);
return false;
}
if(argv[2][0] != '%')
if(checkIfComplex(argv[1]) || checkIfComplex(argv[3])) {
puts(INPUTLOG);
return false;
}
Complex result,
fterm = parseComplex(argv[1]),
sterm = parseComplex(argv[3]);
switch(argv[2][0]) {
case '+':
result.realp = fterm.realp + sterm.realp;
result.imagp = fterm.imagp + sterm.imagp;
break;
case '-':
result.realp = fterm.realp - sterm.realp;
result.imagp = fterm.imagp - sterm.imagp;
break;
case '*': case 'x':
result.realp = fterm.realp * sterm.realp;
result.imagp = fterm.realp * sterm.imagp
+ fterm.imagp * sterm.realp
- fterm.imagp * sterm.imagp;
default:
puts(FORMATLOG);
return false;
}
fprintf(stdout, ">> %g + %gi\n", result.realp, result.imagp);
return true;
}
It would appear that the '*' is being treated as a wild-card and expanded by the shell before being passed to you application. For example,
int main(int argc, char** argv)
{
int ndx;
printf("%d\n", argc);
for(ndx = 0; ndx < argc; ndx++)
{
printf("argument %d is %s\n", ndx, argv[ndx]);
}
return 0;
}
produces the following output (on a Ubuntu host, using gcc-4.8 as the compiler):
******#ubuntu:~/junk$ ./complex a+bi * c+di
6
argument 0 is ./complex
argument 1 is a+bi
argument 2 is complex
argument 3 is complex.c
argument 4 is complex.c~
argument 5 is c+di
I can see two solutions to your problem:
(1) escape the * like this:
xxxxxx#ubuntu:~/junk$ ./complex a+bi \* c+di
4
argument 0 is ./complex
argument 1 is a+bi
argument 2 is *
argument 3 is c+di
Problem here is that you are going to have to escape any symbol that has special significance, and it certainly doesn't seem natural to write *. Additionally, I'm not sure how portable this is going to be due to shells using different escape charaters.
(2) quote the entire expression like this:
xxxxxx#ubuntu:~/junk$ ./complex "a+bi * c+di"
2
argument 0 is ./complex
argument 1 is a+bi * c+di
At least here the user can write the expression in a normal form, they just have to remember to quote it. Additionally, this provides some protection against a user adding an additional space in the expression, vis a + bi * c+di. The problem here is that the use needs to remember to quote the expression and you need to do a bit more parsing to extract the two terms.

Segment fault iPhone executable

When I run my CLI program on my iphone i get a Segment fault: 11 error. I dunno what to do, I'm a noob at C.
int main (int argc, const char * argv[])
{
if (argc > 1 && (!strcmp(argv[1],"--help") || !strcmp(argv[1],"-h"))) {
printf("#### redhai 1.2 ####\n");
printf("-j Jailbreak\n");
printf("-i Device info\n");
printf("-a About\n");
printf("*END OF HELP*\n");
printf("####################\n");
return 0;
}else if (!strcmp(argv[1],"-j")) {
printf("Coding the jailbreak portion!\n");
return 0;
}
return 0;
}
You are accessing argv[1] without first checking if it exists. You need to first check if argc > 1.
} else if (argc > 1 && !strcmp(argv[1],"-j")) {
// ^^^^^^^^^^^^
The problem is in the logic. It is possible that you pass NULL to strcmp in case argc is less or equal to 1. To fix it, re-order the checks like this:
int main (int argc, const char * argv[])
{
if (argc > 1) {
if (!strcmp(argv[1],"--help") || !strcmp(argv[1],"-h")) {
printf("#### redhai 1.2 ####\n");
printf("-j Jailbreak\n");
printf("-i Device info\n");
printf("-a About\n");
printf("*END OF HELP*\n");
printf("####################\n");
} else if (!strcmp(argv[1],"-j")) {
printf("Coding the jailbreak portion!\n");
}
}
return 0;
}

Resources