Print using command line arguments - c

Im trying make a program print a specific output using a enviroment variable in the command line, but the program seems to be stuck on my first input.
Here's my code
#include <stdio.h>
#include <stdlib.h>
void print_data(char*select);
int main (int argc, char * argv[]){
int ret;
char *ch = NULL;
if( argc == 2)
{
ch = argv[1];
}
else
{
ch = getenv("V1");
}
void print_data(ch);
return 0;
}
void print_data(char* select){
if(select, "k")
{
printf("Value set to key\n");
}
else if(select, "l")
{
printf("Value set to last name\n");
}
else if (select, " ")
{
printf("Value set to %s\n", select);
}
}
My problem is that the program either only prints "Value set to key" or "Value set to last name".
How can I use the pointer in Print_data to check what command is entered in the command line?
Output:

if(select, "k") is almost certainly not doing what you want, but it is not entirely clear what it is that you want. That expression is equivalent to if(1), which is why you get the behavior you see. Perhaps you intend:
if( select[0] == 'k' ) ...
else if( select[0] == 'l' ) ...
else if( select[0] == ' ' ) ...
which would be better written:
switch( select[0] ) {
case 'k': ...;
...

Related

What is the easiest way to parse arguments from a file in C?

Consider a file ArgumentFile.txt
int a=100;
int b[3] = { 5, 2, 5 };
double c = 0.0014;
And the main code code.c
int main(int argc, char *argv[])
{
if (argc > 1) FILE *f = fopen(argv[1], "r");
ParseFile(f); // Set the parameters based on file
DoStuff(a,b,c); // Run the process based on the parsed arguments
}
A user could then pass arguments by doing
./CodeExecutable ArgumentFile.txt
Is there a standard solution to parse arguments from file? It would be an equivalent of getopt which parse arguments from command line?
You do not need an equivalent to getopt() you can use exactly getopt(). The getopt() function does not specifically process command line arguments; it will process any array of pointers to strings in the style of command line arguments.
#define MAX_ARGS 256
#define MAX_FILE_LEN 4096
int main(int argc, char *argv[])
{
if( argc > 1 )
{
FILE *f = fopen(argv[1], "r");
if( f != 0 )
{
char fargs[MAX_FILE_LEN] = "" ;
fread( fargs, 1, MAX_FILE_LEN, f ) ;
// Build fargv from file content
char* fargv[MAX_ARGS] ;
int fargc = 0 ;
fargv[fargc] = strtok( fargs, " \n\r" ) ;
while( fargc < MAX_ARGS && fargv[fargc] != 0 )
{
fargc++ ;
fargv[fargc] = strtok( 0, "\n\r" ) ;
}
// Process fargv using getopt()
while( (char c = getopt( fargc, fargv, "a:b:c:")) != -1 )
{
switch( c )
{
...
}
}
}
}
...
return 0 ;
}
It is probably better to dynamically allocate fargs using teh actual file length, but the above is illustrative only.
Your input file might then look like:
-a 100
-b 5,2,5
-c 0.0014
The getopt() loop will then have to process the arguments as necessary - using sscanf() for example.
switch( c )
{
case 'a' : sscanf( optarg, "%i", a ) ; break ;
case 'b' : sscanf( optarg, "%i,%i,%i", b[0], b[1], b[2] ) ; break ;
case 'c' : sscanf( optarg, "%f", c ) ; break ;
}
DoStuff( a, b, c ) ;
I use getopt(). Here is an example that allows for some more flexibility. This example demonstrates how th handle for optional optarg and multiple optargs.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
void usage(void)
{
printf("usage: \n"
"This example demonstrates how to add flexibility to the traditional linux getopt()\n"
"This help text is printed if the program is executed without arguments\n"
"or with an invalid argument configuration.\n"
"to view the help file run without arguments or with -h\n"
"Oterwise the program accepts two options: -d, -u\n"
"-d: can come with 0 or one option argument\n"
"-u: can come with one or more option arguments\n"
"try this to see the output:\n"
"./test -d aaa -u ccc 4 \"quoted multi token string\" -d -u\n");
}
int main(int argc, char **argv)
{
char data[101];
int opt;
memset(data, 0, 101);
while ((opt = getopt(argc, argv, "hd:u:t:")) != -1) {
switch (opt) {
case 'h':
usage();
return 0;
case 'd': // can accept 0 or 1 parameters
if (optarg[0] == '-') { //not an optarg of ours...
optind--;
printf("option: -d. no tokens (another option follows)\n");
break;
}
strncpy(data, optarg, 100);
printf("option: -d. tokens: %s\n", data);
break;
case 'u': //can accept one or more parameters ...
strncpy(data, optarg, 100);
printf("option: -u. tokens: %s", data);
//do we have more arguments for 'u'?
while( optind <= argc && argv[optind][0] != '-') {
strncpy(data, argv[optind], 100);
printf(", %s", data);
optind++;
}
printf(".\n");
break;
case ':': //this happens if we got an option which expects an arg without any optarg.
if(optopt == 'd') {//lets allow a '-d' without its optarg
printf("option: -d. no tokens\n");
break;
}
//otherwise fall through to the default handler
default: //covers ':' '?' for missing value, '-h' for help, etc.
printf("on error you get: opt=%c. optopt=%c opterr=%d\n", opt, optopt, opterr);
return 0;
}
}
return 0;
}
You can't do that using plain C code. You'll have to write platform specific assembly language code to handle that.
Your best option is to use the C proprocessor.
int main(int argc, char *argv[])
{
#include "myfile.txt"
// Do Stuff
}
Having said that, I don't know what you would gain by that instead of putting the contents of myfile.txt in main() directly.

Command Line Argument

I am having trouble figuring out how to make this code work. What is suppose to is depending on the arguments giving from the command line, it suppose to print out a greeting.
int main (int argc, char *argv[]) {
double testscore;
if (argc == 2) {
printf("Hello, Mr.%s.\n", argv[1]);
}
else if (argc == 3 && argc == testscore) {
testscore = atof(argv[2]);
printf("Hi, Mr.%s, your score is %.1f\n", argv[1], testscore);
}
else {
printf("My name is %s %s.\n", argv[1], argv[2]);
}
}
If someone puts only their last name, then the terminal will print out...
Hello, Mr. last_name
...because they only put in one argument. This works fine.
The part where I am stuck on is when the command line arguments given are == 3. If 3 arguments are given then either the terminal is suppose to print out...
Hi, Mr. last_name, your test score is test_score
...or...
My name is first_name last_name.
If I put in the command line arguments only the last name and test score (Smith 3.4) then it prints out (example using the last name Smith) then it prints out...
My name is Smith 3.4
However, it does work for putting in the first name and last name (John Smith). This gives...
My name is John Smith.
I do not want the answer, I just want what I am doing wrong and hints on how to fix it.
I do not want the answer, I just want what I am doing wrong and hints on how to fix it.
Problem 1: You are using testscore variable before it is being initialized.
Problem 2: You are not performing error handling with atof. I would suggest to use strtod(). You can perform some error handling with it to know that the third argument is a float or not. You can also create your own implementation of atof() which will convert and report error in conversion, if any.
Hint: Try to first check that the number of arguments passed to the c program. After that, try to convert third argument to float using strtod() or your own implementation. If it successfully converts, assign the result of float convrsion to test_score and print last_name and testscore. If not, then consider third argument as last_name and print first_name and last_name.
Your problem is with this line:
else if (argc == 3 && argc == testscore) {
In fact, when argc == 3, then you want to check if argv[2] is a numeric argument.
else if ( (argc==3) && (is_numeric_arg(argv[2])==1)) {
A possible implementation would be:
int is_numeric_arg(char* arg)
{
int isInt = 0;
int isFloat = 0;
int isChar = 0;
char* currChar;
int i = 0;
currChar = arg;
isInt = 1;
while (*currChar != '\0')
{
if(*currChar < '0' || *currChar > '9')
{
if(*currChar == '.' && isInt == 1)
{
isInt = 0;
isFloat = 1;
}
else
{
isInt = 0;
isChar = 1;
}
}
currChar++;
}
if (isChar == 1){ return 0; } // argument is a string
else { return 1; } // argument is a int or float
}
int main (int argc, char *argv[]) {
double testscore;
if (argc == 2) {
printf("Hello, Mr.%s.\n", argv[1]);
}
else if ( (argc==3) && (is_numeric_arg(argv[2])==1)) {
testscore = atof(argv[2]);
printf("Hi, Mr.%s, your score is %.1f\n", argv[1], testscore);
}
else {
printf("My name is %s %s.\n", argv[1], argv[2]);
}
}
I did not test the code and there is probably a better way to check that the argument from the command line is "numeric".
Got it the answer guys. To check it without using another function, it would be
....
else if ( argc==3 && sscanf(argv[2], "%f", testscore)
{
testscore = atof(argv[2]);
printf("Hi, Mr.%s, your score is %.1f\n", argv[1], testscore);
}
...

Prints new line after '\0' character in C

I'm currently doing an assignment where we are to recreate three switches of the cat command, -n/-T/-E. We are to compile and enter in two parameters, the switch and the file name. I store the textfile contents into a buffer.
int main(int argc, char *argv[]){
int index = 0;
int number = 1;
int fd, n, e, t;
n = e = t = 0;
char command[5];
char buffer[BUFFERSIZE];
strcpy(command, argv[1]);
fd = open(argv[2], O_RDONLY);
if( fd == -1)
{
perror(argv[2]);
exit(1);
}
read(fd, buffer,BUFFERSIZE);
if( !strcmp("cat", command)){
printf("%s\n", buffer);
}
else if( !strcmp("-n", command)){
n = 1;
}
else if( !strcmp("-E", command)){
e = 1;
}
else if( !strcmp("-T", command)){
t = 1;
}
else if( !strcmp("-nE", command) || !strcmp("-En", command)){
n = e = 1;
}
else if( !strcmp("-nT", command) || !strcmp("-Tn", command)){
n = t = 1;
}
else if( !strcmp("-ET", command) || !strcmp("-TE", command)){
t = e = 1;
}
else if( !strcmp("-nET", command) || !strcmp("-nTE", command) ||
!strcmp("-TnE", command) || !strcmp("-EnT", command) ||
!strcmp("-ETn", command) || !strcmp("-TEn", command)){
n = e = t = 1;
}
else{
printf("Invalid Switch Entry");
}
if(n){
printf("%d ", number++);
}
while(buffer[index++] != '\0' && ( n || e || t)){
if(buffer[index] == '\n' && e && n){
printf("$\n%d ", number++);
}
else if(buffer[index] == '\n' && e){
printf("$\n");
}
else if(buffer[index] == '\t' && t){
printf("^I");
}
else if(buffer[index] == '\n' && n){
printf("\n%d ", number++);
}
else {
printf("%c", buffer[index]);
}
}
printf("\n");
close(fd);
return 0;
}
Everything works perfectly except when I try to use the -n command. It adds an extra new line. I use a textfile that has
hello
hello
hello world!
instead of
1 hello
2 hello
3 hello world!
it will print out this:
1 hello
2 hello
3 hello world!
4
For some reason it adds the extra line after the world!
Am I missing something simple?
This might not fix your problem, but I don't see any code to put the terminating null character in buffer. Try:
// Reserve one character for the null terminator.
ssize_t n = read(fd, buffer, BUFFERSIZE-1);
if ( n == -1 )
{
// Deal with error.
printf("Unable to read the contents of the file.\n");
exit(1); //???
}
buffer[n] = '\0';
The three cat options that you implement have different "modes":
-T replaces a character (no tab is written);
-E prepends a character with additional output (the new-line character is still written);
-n prepends each line with additional output.
You can handle the first two modes directly. The third mode requires information from the character before: A new line starts at the start of the file and after a new-line character has been read. So you need a flag to keep track of that.
(Your code prints a line number after a new-line character is found. That means that you have to treat the first line explicitly and that you get one too many line umber at the end. After all, a file with n lines has n new-line characters and you print n + 1 line numbers.)
Other issues:
As R Sahu has pointed out, your input isn't null-terminated. You don't really need a null terminator here: read returns the number of bytes read or an error code. You can use that number as limit for index.
You incmenet index in the while condition, which means that you look at the character after the one you checked inside the loop, which might well be the null character. You will also miss the first character in the file.
In fact, you don't need a buffer here. When the file is larger than you buffer, you truncate it. You could call read in a loop until you read fewer bytes than BUFFERSIZE, but the simplest way in this case is to read one byte after the other and process it.
You use too many compound conditions. This isn't wrong per se, but it makes for complicated code. Your main loop reads like a big switch when there are in fact only a few special cases to treat.
The way you determine the flags is both too complicated and too restricted. You chack all combinations of flags, which is 6 for the case that all flags are given. What if you add another flag? Are you going to write 24 more strcmps? Look for the minus sign as first character and then at the letters one by one, setting flags and printing error messages as you go.
You don't need to copy argv[1] to command; you are only inspecting it. And you are introducing a source of error: If the second argument is longer than 4 characters, you will get undefined behaviour, very likely a crash.
If you don't give any options, the file name should be argv[1] instead of argv[2].
Putting this (sans the flag parsing) into practice:
FILE *f = fopen(argv[2], "r");
int newline = 1; // marker for line numbers
// Error checking
for (;;)
{
int c = fgetc(f); // read one character
if (c == EOF) break; // terminate loop on end of file
if (newline) {
if (n) printf("%5d ", number++);
newline = 0;
}
if (c == '\n') {
newline = 1;
if (e) putchar('$');
}
if (c == '\t' && t) {
putchar('^');
putchar('I');
} else {
putchar(c);
}
}
fclose(f);
Edit: If you are restricted to using the Unix open, close and read, you can still use the approach above. You need an additional loop that reads blocks of a certain size with read. The read function returns the value of the bytes read. If that is less than the number of bytes asked for, stop the loop.
The example below adds yet an additional loop that allows to concatenate several files.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define BUFFERSIZE 0x400
int main(int argc, char *argv[])
{
int n = 0;
int e = 0;
int t = 0;
int number = 0;
int first = 1;
while (first < argc && *argv[first] == '-') {
char *str = argv[first] + 1;
while (*str) {
switch (*str) {
case 'n': n = 1; break;
case 'E': e = 1; break;
case 'T': t = 1; break;
default: fprintf(stderr, "Unknown switch -%c.\n", *str);
exit(0);
}
str++;
}
first++;
}
while (first < argc) {
int fd = open(argv[first], O_RDONLY);
int newline = 1;
int bytes;
if (fd == -1) {
fprintf(stderr, "Could not open %s.\n", argv[first]);
exit(1);
}
do {
char buffer[BUFFERSIZE];
int i;
bytes = read(fd, buffer,BUFFERSIZE);
for (i = 0; i < bytes; i++) {
int c = buffer[i];
if (newline) {
if (n) printf("%5d ", number++);
newline = 0;
}
if (c == '\n') {
newline = 1;
if (e) putchar('$');
}
if (c == '\t' && t) {
putchar('^');
putchar('I');
} else {
putchar(c);
}
}
} while (bytes == BUFFERSIZE);
close(fd);
first++;
}
return 0;
}

need to get better code to read file into variables

Currently have this code (see below). It was working fine, but I needed to be able to manage empty lines, and also lines with comment. These comment lines are defined as : having "#" as the first character of a line. Initially, I would just loop 100 times, because I limit the storage into variable to 100 as well, but when skipping empty lines and remark lines, the simple counter to 100 doesn't work. Still, only the first 100 valid lines may be read, and stored into the "menu_choices" variable. Also, the length of each line should be limited to 100 characters (or, I have a variable of 100 characters, so 99+enter). I'll need to include that as well. I can't decide wheter I need an IF statement, or a while, or whatever.
int x;
char inputfile[512];
char menu_number[100];
char menu_choices[100][100];
printf("\nopening:%s\n",inputfile);
p_datafile=fopen(inputfile,"r");
x=1;
//for (x=1 ; x <= 100 ; x++ )
do
{
// read next line into variable
fgets(menu_choices[x],100,p_datafile);
if ( strcmp ( menu_choices[x] , "" ) == 0 ) break;
if ( strncmp(menu_choices[x],"#",1) )
{
printf("%d[lngth=%d]=%s",x,strlen(menu_choices[x]),menu_choices[x]);
x++;
}
else
{
printf("\n LINE WITH #");
}
sleep (1);
} while (1);
fclose(inputfile);
Can you improve the above code ?
To achieve what you describe, may be this could work.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int
main()
{
int lineCount;
char filename[512];
/* if you want to read 100 characters you need 1 extra for the termination 0 */
char menu_choices[100][100 + 1 /* termination 0 */];
int extraLines;
int lineLength;
FILE *p_datafile; // p_datafile was not declared...
int character;
int skipLine;
printf("enter filename please: ");
scanf("%511s", filename);
printf("\topening:%s\n", filename);
lineCount = 0;
p_datafile = fopen(filename, "r");
if (p_datafile == NULL)
return 0; // or perhaps return a value, since there is no context here I don't know
memset(menu_choices[0], 0, 101);
extraLines = 0;
lineLength = 0;
skipLine = 0;
while ((p_datafile != NULL) && ((character = getc(p_datafile)) != EOF))
{
if (character == '\n')
{
if ((lineLength > 0) && (skipLine == 0))
{
menu_choices[lineCount][lineLength] = 0;
lineCount += 1;
printf("valid line %d [length -> %d] -> %s\n", lineCount, lineLength, menu_choices[lineCount - 1]);
memset(menu_choices[lineCount], 0, 101);
}
else if (skipLine != 0)
{
fprintf(stderr, "line starts with #\n");
extraLines += 1;
}
else if (lineLength == 0)
{
fprintf(stderr, "line is empty\n");
extraLines += 1;
}
skipLine = 0;
lineLength = 0;
}
else if ((lineLength == 0) && (isspace(character) != 0))
{
/* Ignore spaces if non-space characters where not found yet. */
}
else
{
if ((lineLength == 0) && (character == '#'))
skipLine = 1; /* Ignore this line, it starts with */
else if (lineLength < 100)
{
menu_choices[lineCount][lineLength] = (char)character;
lineLength += 1;
}
}
}
fclose(p_datafile); // the FILE * not the filename
return 0;
}
I'm not very sure if i have understood your question, but it seems following points can help you to achieve your goal.
add a NULL check on p_datafile to check the success of fopen(). [assuming p_datafile is already defined as FILE *, which part you din't show us.]
instead of break; after if ( strcmp ( menu_choices[x] , "" ) == 0 ), use continue.
add a continue; after printf("\n LINE WITH #"); inside else block.
after if...else block, check if (x == 100), if true, break;
in fclose(), use p_datafile. It expects the file pointer, not the filename.
One answer was just before me but I'll post anyway. Bear in mind that fgets() reads the newline too, so I have tested for/ removed it. Also, your indexing: as far as possible use 0-based indexing, and make any adjustments between 0.. and 1.. for the human at the point of input and output.
#include <stdio.h>
#include <string.h>
int main()
{
int x, len;
char inputfile[512] = "lines.txt";
char menu_number[100];
char menu_choices[100][100];
FILE *p_datafile;
printf ("\nopening:%s\n",inputfile);
p_datafile=fopen (inputfile,"rt"); // it's a text file
if (p_datafile == NULL) {
printf ("Can't open file %s\n", inputfile);
exit (1);
}
x = 0; // get the array indexing right
while (x<100 && fgets(menu_choices[x], 100, p_datafile)) {
if (menu_choices[x][0] != '\n' && menu_choices[x][0] != '#') {
len = strlen (menu_choices[x]);
if (menu_choices[x][len-1] == '\n') // remove newline
menu_choices[x][len-1] = 0;
printf ("%s\n", menu_choices[x]);
// sleep (1);
x++;
}
}
fclose(p_datafile); // corrected mistake (don't use filename)
return 0;
}
Input file:
Line 1
Line 02
#not line 3
line three
Program output:
opening:lines.txt
Line 1
Line 02
line three

Reading a whole line before printing result

Ok firstly I'm a total amateur on programming and i wanted to try something. I want to make a C program which will read a line and then if the characters are accepted to print "ACCEPTED" or "REJECTED" if the characters are valid or not.
So I've used a while loop and some if-else if to add the viable characters. The viable characters are the letters of the alphabet ',' '.' '/' '[' ']'. The problem is that after i type the whole line, it prints ACCEPTED and REJECTED for every character on the line. How can i get the program to read the whole line first and then print the result?
#include <stdio.h>
int main(void) {
char c;
c=getchar();
while(c!=EOF) {
while (c!='\n') {
if (c>='a' && c<='z') {
printf("OK!\n");
}
else if(c==','|| c=='.' ||c=='/') {
printf("OK!\n");
}
else if(c==']'||c=='[') {
printf("OK!\n");
}
else {
printf("ERROR!\n");
}
c=getchar();
}
c=getchar();
}
}
Sorry, my original answer did not seem to relate to your question. Skim reading fail.
Thank you for posting the code, it helps a lot when it comes to answering your question correctly.
Ignoring style for now, I would change your code in this way to make it print OK only when you finish parsing the entire line and it is exactly what #ScottMermelstein said but with code.
#include <stdio.h>
int main(void) {
int c; // This needs to be an int otherwise you won't recognize EOF correctly
int is_ok;
c=getchar();
while(c!=EOF) {
is_ok = 1; // Let's assume all characters will be correct for each line.
while (c!='\n') { // So long as we are in this loop we are on a single line
if (c>='a' && c<='z') {
// Do nothing (leave for clarity for now)
}
else if(c==','|| c=='.' ||c=='/') {
// Do nothing (leave for clarity for now)
}
else if(c==']'||c=='[') {
// Do nothing (leave for clarity for now)
}
else {
is_ok = 0; // Set is_ok to false and get out of the loop
break;
}
c=getchar();
}
if (is_ok) // Only print our result after we finished processing the line.
{
printf("OK!\n");
} else
{
printf("ERROR!\n");
}
c=getchar();
}
return 0; // If you declare main to return int, you should return an int...
}
However, I would recommend modularizing your code a little more. This will come with time and practice but you can write things in a way that is much easier to understand if you hide things away in appropriately named functions.
#include <stdio.h>
int is_valid_char(int c)
{
return (isalpha(c) || c == ',' || c == '.' || c == '/' || c == '[' || c == ']');
}
int main(void) {
int c;
int is_valid_line;
c=getchar();
while(c!=EOF) {
is_valid_line = 1;
while (c!='\n') {
if (!is_valid_char(c)) {
is_valid_line = 0; // Set is_valid_line to false on first invalid char
break; // and get out of the loop
}
c=getchar();
}
if (is_valid_line) // Only print our result after we finished processing the line.
{
printf("OK!\n");
} else
{
printf("ERROR!\n");
}
c=getchar();
}
return 0;
}
You can use scanf and putting a space before the format specifier %c to ignore white-space.
char ch;
scanf(" %c", &ch);
This might be what you are looking for?
Read a line and process good/bad chars and print either OK or Error.
#include <stdio.h>
int main ( void )
{
char buff[1000];
char *p = buff ;
char c ;
int flgError= 0 ; // Assume no errors
gets( buff ) ;
printf("You entered '%s'\n", buff );
while ( *p ) // use pointer to scan through each char of line entered
{
c=*p++ ; // get char and point to next one
if ( // Your OK conditions
(c>='a' && c<='z')
|| (c>='A' && c<='Z') // probably want upper case letter to be OK
|| (c==','|| c=='.' ||c=='/')
|| (c==']'||c=='[')
|| (c=='\n' ) // assume linefeed OK
)
{
// nothing to do since these are OK
}
else
{
printf ("bad char=%c\n",c);
flgError = 1; // 1 or more bad chars
}
}
if ( flgError )
printf ( "Error\n" );
else
printf ( "OK\n" );
}

Resources