Command-line parsing: How to parse a string as an argument - c

I am attempting to parse a command line argument, which in turn will execute an associated case within a switch statement. When I parse an integer argument (as seen in the code below), the associated case executes correctly. When I attempt to parse a string such as "CPU", I do not get the correct output.
Functioning code (parsing an integer e.g. an argument of 4 gives athe correct output of hello):
#include <stdio.h>
int main(int argc, char *argv[]) {
char execution_mode = atoi (argv[1]);
switch (execution_mode)
{
case (4) :
printf("Hello");
getchar();
break;
case (8) :
printf("Goodbye");
getchar();
break;
default:
printf("Error! execution mode is not correct");
getchar();
break;
}
return 0;
}
My attempt at parsing a string e.g. the argumentCPU:
#include <stdio.h>
int main(int argc, char *argv[]) {
typedef enum MODE { CPU, OPENMP } MODE;
MODE execution_mode = (char)argv[1];
switch (execution_mode)
{
case (CPU) :
printf("Hello");
getchar();
break;
case (OPENMP) :
printf("Goodbye");
getchar();
break;
default:
printf("Error! execution mode is not correct");
getchar();
break;
}
return 0;
}

You cannot convert a string to an enumerate like this. What you're doing is just converting the pointer to the string to char. Which fails.
One alternative (besides comparing first argument with strcmp) to avoid this would be to give a character value to your enumerates:
typedef enum { CPU='C', OPENMP='O' } MODE;
and now you can pick the first letter of the first argument and convert it:
MODE execution_mode = (MODE)argv[1][0];
The letters must be of course all different. And check argc>1 to see if argv[1] is valid, of course
If you want full string match, you have no other choice than using strcmp:
const char *execution_mode = argv[1];
if (strcmp(execution_mode,"CPU")==0)
{
// do something
}
else if (strcmp(execution_mode,"OPENMP")==0)
{
// do something else
}

With the help of the users who have answered this question, I have found a working solution by using strcmp as seen below. I have also added some error checking to ensure enough arguments have been enterred on the command-line.
#include <stdio.h>
int main(int argc, char *argv[]) {
//Ensure there are enough arguments
if (argc < 2)
{
printf("Error: not enough arguments");
exit(1);
}
typedef enum MODE { CPU, OPENMP, CUDA, ALL } MODE;
MODE execution_mode = (MODE)argv[1];
//Compare string with command-line arguments
if (strcmp("CPU", execution_mode) == 0)
{
//selects CPU case
execution_mode = CPU;
}
else if (strcmp("OPENMP", execution_mode) == 0)
{
//selects OPENMP case
execution_mode = OPENMP;
}
else
{
printf("invalid arg");
}
//Switch statement
switch (execution_mode)
{
case (CPU) :
printf("CPU MODE SELECTED");
getchar();
break;
case (OPENMP) :
printf("OPENMP MODE SELECTED");
getchar();
break;
default:
printf("Error: execution mode is not correct");
getchar();
break;
}
return 0;
}

Related

Checking Char input from command line argument

I have to take an input from command line argument. If the argument is invalid it will print an error message and exit. But whatever argument I am giving it is always producing error message. Even if I give the right argument. I don't know whats wrong.
if (argv[1][0] !='a' || arg[1][0] !='m') {
printf("Error: Invalid arguments!\n");
exit(0);
}
arg[1][0] is not valid. use argv[1][0].
void printError(){
printf("Invalid Parameter\n");
exit(-1);
}
int main(int argc, char**argv){
if(argc < 2)
printError();
switch(argv[1][0]){
case 'a': // your code
break;
case 'm': // your code
break;
default:
printError();
}
return 0;
}

Segmentation fault in atoi command

I have the following code:
int main(int argc, char *argv[])
{
int value,direction=0;
char c;
printf ("go\n");
while((c = getopt(argc, argv, "wr:")) != -1) {
printf ("go\n");
printf("%c\n",c);
switch(c) {
case 'w':
printf ("go\n");
value=atoi(optarg);
printf ("go\n");
printf("The input value is %x",value);
direction=1; //1 for write
break;
case 'r':
direction=0; // 0 for read
break;
default:
printf("invalid option: %c\n", (char)c);
usage();
return -1;
}
}
}
Now when i run the program by writing
./spicode.out -w 25
I need to pick the 25 after w using optarg, but its producing a segmentation fault.
What am i doing wrong?
You should put colon between commandline options.
c = getopt(argc, argv, "w:r")
From gnu.org :
An option character in this string can be followed by a colon (‘:’) to
indicate that it takes a required argument
Therefore wr: becomes w:r

switch case for parsing options

I am writing a simple program which takes the arguments form the user and process them.
I have the arguments in the argv which is two dimensional array. But when i ran the program, i get the garbage value and the segmentation fault error. I have tried with using argc as terminating condition and it works. But i want to do it using the pointer only.
What am doing wrong with pointer here.
#include<stdio.h>
int main( int argc, char *argv[])
{
while (++(*argv))
{
if ( **argv == '-' )
{
switch (*argv[1])
{
default:
printf("Unknown option -%c\n\n", (*argv)[1]);
break;
case 'h':
printf("\n option h is found");
break;
case 'v':
printf("option V is found");
break;
case 'd':
printf("\n option d is found");
break;
}
}
printf("\n outside while : %s", *argv);
}
}
program run as:
./a.out -h -v -d
Thank you
If you want to iterate through program arguments looking for the terminating null pointer, your outer cycle should be
while (*++argv)
not the
while (++*argv) // <- incorrect!
that you have in your code.
Your switch expression is written incorrectly. While your intent is clear, your implementation ignores operator precedence.
This
switch (*argv[1]) { // <- incorrect!
should actually be
switch ((*argv)[1]) {
The previous if
if (**argv == '-')
is fine, but since it is equivalent to
if ((*argv)[0] == '-') // <- better
maybe you should rewrite it that way as well, just for consistency with switch.
Your ultimate problem is operator precedence. Don't try to be clever when it's unnecessary. The * operator does not work as you think it does. I've rewritten your code using [0] instead, and now it works:
#include <stdio.h>
int main(int argc, char *argv[])
{
while ((++argv)[0])
{
if (argv[0][0] == '-' )
{
switch (argv[0][1]) {
default:
printf("Unknown option -%c\n\n", argv[0][1]);
break;
case 'h':
printf("\n option h is found");
break;
case 'v':
printf("option V is found");
break;
case 'd':
printf("\n option d is found");
break;
}
}
printf("\n outside while : %s", argv[0]);
}
}
argv is an array of strings. argv[0] is the program name which in your case is a.out. Your options start from argv[1]. So you need to iterate argv from 1 to argc-1 to get the options.
Also see here: Parsing Program Arguments

Build a char converter program with argv[]

I am supposed to build a program that takes argv[1] and according to it transforms the characters into lower case or upper case.However I am stuck cuz C cant compare a pointer with a string.Any ideas on how to compare a pointer and a string,i dont want to compare them character by character.
Here is the code
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main (int argc,char *argv[])
{
char c;
if(argc!=2)
printf("Wrong use of program \n");
printf("The Format is Lower or Upper \n");
return -1;
if ((strcmp(argv[1],"Lower"))==0)
{
while((c=getchar())!=EOF)
{
printf("-");
putchar(tolower(c));
printf("\n");
}
}
if ((strcmp(argv[1],"Upper"))==0)
{
while((c=getchar())!=EOF)
{
printf("-");
putchar(toupper(c));
printf("\n");
}
}
if ((strcmp(argv[1],"Lower"))!=0 && ((strcmp(argv[1],"Upper"))!=0))
{
printf("Wrong use of program \n");
printf("The Format is Lower or Upper \n");
return -1;
}
return 0;
}
What you want to do is use the function strcmp or stricmp (for case insensitive).
Firstly, use strcmp which will return 0 if the char arrays match.
if (!strcmp(argv[1], "Lower"))
{
Secondly if more than one statement applies to an if condition, the statements must be encased in {}.
if (argc != 2)
{
printf("Wrong use of program \n");
printf("The Format is Lower or Upper \n");
return -1;
}

how to create an interactive menu in C that moves from one function into another without redrawing the menu

My goal is to produce a program that will take a file as input and "encode" the text within by shifting the characters ahead 3 (so 'a' would be come 'd'). It should produce an output file with the encoded text. The menu is to take user input and execute the function that is assigned to the number selected.
I'm early on at creating this program, but running short on time and am struggling with how to structure it. Currently, I have the menu displaying, but when a sub function is called, it displays but then the menu overwrites it and I can't figure out why. Any help would be appreciated. Here is the code I have so far...
#include <stdio.h>
#define INPUT_FILE 1 //define statements
#define OUTPUT_FILE 2
#define NUM_TO_SHIFT 3
#define ENCODE 4
#define QUIT 0
int menu(); //function prototypes
int input();
int output();
int shift();
int encode();
void quit();
int main()
{
int choice; // main variables
char user_filename[100];
choice = menu(); // get user's first selection
while(choice != QUIT) //execute so long as choice is not equal to QUIT
{
switch(choice)
{
case INPUT_FILE:
printf("Enter the filename of the file to encode:\n");
printf("(hit the Enter key when done)\n");
gets(user_filename);
break;
case OUTPUT_FILE: output();
break;
case NUM_TO_SHIFT: shift();
break;
case ENCODE: encode();
break;
case QUIT: quit();
break;
default: printf("Oops! An invalid choice slipped through. ");
printf("Please try again.\n");
}
choice = menu(); /* get user's subsequent selections */
}
printf("Bye bye!\n");
return 0;
}
int menu(void)
{
int option;
printf("Text Encoder Service\n\n");
printf("1.\tEnter name of input file (currently 'Secret.txt')\n");
printf("2.\tEnter name of output file (currently not set)\n");
printf("3.\tEnter number of characters data should be shifted (currently +7)\n");
printf("4.\tEncode the text\n\n");
printf("0.\tQuit\n\n");
printf("Make your selection: ");
while( (scanf(" %d", &option) != 1) /* non-numeric input */
|| (option < 0) /* number too small */
|| (option > 4)) /* number too large */
{
fflush(stdin); /* clear bad data from buffer */
printf("That selection isn't valid. Please try again.\n\n");
printf("Your choice? ");
}
return option;
}
int input()
{
}
int output()
{
return 2;
}
int shift()
{
return 3;
}
int encode()
{
return 4;
}
void quit()
{
printf("Quiting...Bye!");
exit(0);
}
You shouldn't use gets(user_filename) to get the file name since gets() reads up to a \n and stops reading. Your scanf for the menu option does not read the \n at the end of the line when the user types in the menu option. Essentially, you're making gets read a string without words in it. The line you want to read is actually the next line. Using scanf instead of gets will fix it.
Otherwise, your program is working as expected - it's just that your functions don't do anything yet that your menu is "overwriting" the submenus. See http://ideone.com/F2pEs for an implementation with scanf instead of gets.
use getchar(); soon after the gets(user_filename); it will wait to get the character
gets(user_filename);
getchar();
break;
As in this question which Stackoverflow has highlighted as a match, you need to clear out the buffer to remove the newline that's waiting in there.
Add this code after reading a valid menu option:
do
{
c = getchar();
} while (c != EOF && c != '\n');
where c is a char declared up by option. This loops over remaining characters in the input stream until EOF (End Of File) or a newline character is reached, meaning they don't affect your call to gets(). Note that gets() is considered insecure because it doesn't protect against buffer overflow, a user could easily enter more than 100 characters (inc. newline) and start writing into memory that shouldn't be touched by their input. You would do well to lookup the secure equivalent when you see compiler warnings around function calls like this, typically they take a second parameter which is the maximum size of the buffer being read into.
Well, this answer is way late but having come across it, I can't help but write something.
Let's get straight to it. You will have an array of menus, with the array elements being the options you want in your menu. Then while in a truthy condition, loop through the elements of the array, selecting the option you want.
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
//function prototypes
int input();
int output();
int shift();
int encode();
void quit();
int main(){
int menus_on = 1;
const char *menus[5] = {"Input","Output","Shift","Encode","Quit"};
while(menus_on){
int menu,*temp;
for(int i =0;i<6;i++){
printf("%d: %s\n",i,menus[i]);
}
printf("Select menu\n");
scanf("%d",temp);
menu = *temp;
printf("Selected menu::%d\n",menu);
switch(menu){
case 0:
input();
break;
case 1:
output();
break;
case 2:
shift();
break;
case 3:
encode();
break;
case 4:
quit();
break;
default:
printf("Invalid selection\n");
break;
}
}
return 0;
}
int input() {
return 0;
}
int encode () {
return 0;
}

Resources