Passing a Command Line Argument and a textfile to a program - c

I have a Read and Reverse Coding assignment where I need to pass a Textfile and a character (-L, or -W), depending on whether the operator wants the textfile returned in reverse by lines or by words. (I should also note that the assignment requires that nothing is asked of the user during the code. It must be decided which variation is wanted in the command line.)
I don't need help with the code to reverse the lines or words, but do need help with understanding how to take in character and the textfile, then use them in the code. I've tried using the parameters (int argc, char *argv[]) on the main, but anytime I try to pass in just the -L the terminal either says Command not found or clang: error: argument to '-L' is missing (expected 1 value)
Also, when my teacher passes a textfile to a program he often uses a >. Can someone explain how to use this?
Ex. program.c > hello.txt
Then he would end up using that .txt in the program.

Consider this:
program -L < data.txt
or
program -W < data.txt
or
cat data.txt | program -L
The "-L" or "-W" will be in argv[1].
Good luck!

The idea of Passing a Command Line Arguement is the following
Argc: argument counter amount of "strings"(arguments) passed for execution.
Its always 1 or greater as the calling of the function is an argument.
Argv: argument vectors(pointers), is a pointer to each of the arguments received by the command line
Example of program call:
./myprogram -w
argc=2
argv will have two pointers to strings(char):
argv[0]= "./myprograms"
argv[1]= "-w"
Now with your problem
When excecuting a program via command line you have a lot of options amongst these:
1) One of these is to give the program input of a file(the file will be passed character by character to the standard input ending with an EOF or -1 -not an ascii character-)
These can be done by the follow way
./program.c < hello.txt
2)Redirect the output of the program to a file
./program.c > hello.txt
What you are looking to do is input a file while passing an argument this can be done the following way
./program.c < hello.txt -L
IMPORTANT: "< hello.txt" will NOT count as an argument so for this case the case the argc and argv will be the follow
argc=2
argv[0]="./program.c"
argv[1]="-L"
Hopes this helps comment if you need anymore help or something isn't clear. Good luck with your course!!!

Related

Passing file contents to a c executable doesn't seem to work

I have this c executable called testFile file containing this code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]){
printf("Number of arguments : %d\n Arguments : ", argc);
for(int i = 0; i<argc-1;i++){
printf("%s\t", argv[i]);
}
}
and along with it a file called test1 containing just the number 1 (echo 1 > test1)
When I call this line on the command line (zsh) :
./test < test1
the output I get is this :
Number of arguments : 1
Arguments : ./testFile
Shouldn't this show 2 arguments ? Along with the character 1 ? I want to find a way to make this 1 appear in the arguments list, is it possible ? Or is it just the way my shell handles arguments passed like that ? (I find it weird as cat < test1 prints 1)
You're conflating standard input with command arguments.
main's argc and argv are used for passing command line arguments.
here, for example, the shell invokes echo with 1 command line argument (the 1 character), and with its standard output attached to a newly opened and truncated file test.
echo 1 > test1
here, the shell running test with 0 arguments and its standard input attached to a newly opened test1 file.
./test < test1
If you want to turn the contents of ./test1 into command line parameters for test, you can do it with xargs.
xargs test < test1
unrelated to your question:
for(int i = 0; i<argc+1;i++){
The condition for that should be i<argc. Like all arrays in C and just about every other language, the minimum valid index of argv is 0 and the maximum valid index is 1 less than its length. As commenters pointed out, argv[argc] is required to be NULL, so technically, argc is one less than the length of argv.
If you want the contents of test1 to be available in argv, you can do:
./test $(cat test1)
Note that this is very different than:
./test "$(cat test1)"
which is also different from:
./test '$(cat test1)'. # Does not do at all what you want!
The first option will present each "word" of the file as a distinct argument, while the second will present the contents of the file as a single argument. The single quotes version doesn't look inside the file at all, and is merely included here to give you something to experiment with.
argv[0] is always the name of the executable itself. With your way of invoking the command, you did not pass any command at all. You would have to invoke it from zsh as ./testFile test1 if you want your program to see the name of the data file, or ./testFile $(<test1) if you want it to see the content of the data file.

Provide input parameters to C code from Linux shell

The concept of my code is like:
#include <stdio.h>
int main(int argc, char *argv[])
{
int num;
FILE *fp;
getint("num",&num); /* This line is pseudo-code. The first argument is key for argument, the second is the variable storing the input value */
fp = inputfile("input"); /* This line is pseudo-code. The argument is key for argument, fp stores the return file pointer */
...
...
exit(0);
}
Usually, after compiling the code and generating the executable main, in the command line we write this to run the code:
./main num=1 input="data.bin"
However, if there's too many arguments, type in the command line each time we run the code is not convenient. So I'm thinking about writing the arguments and run in Linux shell. At first I wrote this:
#! /bin/sh
num = 1
input="data.bin"
./main $(num) $(input)
But error returns:
bash: adj: command not found
bash: input: command not found
bash: adj: command not found
bash: input: command not found
Can anybody help to see and fix it.
There are three main problems with your code:
You can't use spaces around the = when assigning values
You have to use ${var} and not $(var) when expanding values.
The way your code is written, you are passing the string 1 instead of your required string num=1 as the parameter.
Use an array instead:
#!/bin/bash
parameters=(
num=1
input="data.bin"
)
./main "${parameters[#]}"
num=1 is here just an array element string with an equals sign in it, and is not related to shell variable assignments.

Redirecting output of a C program as input of another program in Linux command shell

I wrote a program p1.c which takes input from the linux command shell (Using- char n=argv[1]). I want the character output of p1.c to be taken as input of program p2.c . How can I do this? I used the command
./p2.out < ./p1.out T > output.txt. It doesn't seem to work as 'T' is taken as input for p2.out and its output is written in output.txt.
Use pipeline: ./p1.out T | ./p2.out

Handling command line flags in C/C++

I am looking for a very simple explanation/tutorial on what flags are. I understand that flags work indicate a command what to do. For example:
rm -Rf test
I know that the rm command will remove the test folder and that the -Rf flags will force the command to erase not just the folder but the files in it.
But, where are the flags read/compiled??? What handles the flags? Can I, for example, write my own C/C++ program and designate different flags so that the program does different things? I hope I am asking the right questions. If not, please let me know.
At the C level, command line arguments to a program appear in the parameters to the main function. For instance, if you compile this program:
#include <stdio.h>
int main(int argc, char **argv)
{
int i;
for (i = 0; i < argc; i++)
printf("argv[%d] = %s\n", i, argv[i]);
return 0;
}
and invoke it with the same arguments as your example 'rm' command, you get this:
$ ./a.out -Rf test
argv[0] = ./a.out
argv[1] = -Rf
argv[2] = test
As you can see, the first entry in argv is the name of the program itself, and the rest of the array entries are the command line arguments.
The operating system does not care at all what the arguments are; it is up to your program to interpret them. However, there are conventions for how they work, of which the following are the most important:
Arguments are divided into options and non-options. Options start with a dash, non-options don't.
Options, as the name implies, are supposed to be optional. If your program requires some command-line arguments to do anything at all useful, those arguments should be non-options (i.e. they should not start with a dash).
Options can be further divided into short options, which are a single dash followed by a single letter (-r, -f), and long options, which are two dashes followed by one or more dash-separated words (--recursive, --frobnicate-the-gourds). Short options can be glommed together into one argument (-rf) as long as none of them takes arguments (see below).
Options may themselves take arguments.
The argument to a short option -x is either the remainder of the argv entry, or if there is no further text in that entry, the very next argv entry whether or not it starts with a dash.
The argument to a long option is set off with an equals sign: --output=outputfile.txt.
If at all possible, the relative ordering of distinct options (with their arguments) should have no observable effect.
The special option -- means "do not treat anything after this point on the command line as an option, even if it looks like one." This is so, for instance, you can remove a file named '-f' by typing rm -- -f.
The special option - means "read standard input".
There are a number of short option letters reserved by convention: the most important are
-v = be verbose
-q = be quiet
-h = print some help text
-o file = output to file
-f = force (don't prompt for confirmation of dangerous actions, just do them)
There are a bunch of libraries for helping you parse command line arguments. The most portable, but also the most limited, of these is getopt, which is built into the C library on most systems nowadays. I recommend you read all of the documentation for GNU argp even if you don't want to use that particular one, because it'll further educate you in the conventions.
It's also worth mentioning that wildcard expansion (rm -rf *) is done before your program is ever invoked. If you ran the above sample program as ./a.out * in a directory containing only the binary and its source code you would get
argv[0] = ./a.out
argv[1] = a.out
argv[2] = test.c
This simple program should demonstrate the arguments passed to the program (including the program name itself.)
Parsing, interpreting and using those arguments is up to the programmer (you), although there are libraries available to help:
int main(int argc, char* argv[])
{
int i;
for(i=0; i<argc; ++i)
{ printf("Argument %d : %s\n", i, argv[i]);
}
return 0;
}
If you compile this program into a.out, and run it as:
prompt$> ./a.out ParamOne ParamTwo -rf x.c
You should see output:
Argument 0 : a.out
Argument 1 : ParamOne
Argument 2 : ParamTwo
Argument 3 : -rf
Argument 4 : x.c
Actually you can write your own C++ programm which accepts commandline parameters like this:
int main(int argc, char* argv[]){}
The variable argc will contain the number of parameters, while the char* will contain the parameters itself.
You can dispatch the parameters like this:
for (int i = 1; i < argc; i++)
{
if (i + 1 != argc)
{
if (strcmp(argv[i], "-filename") == 0) // This is your parameter name
{
char* filename = argv[i + 1]; // The next value in the array is your value
i++; // Move to the next flag
}
}
}
In your own C program you can process command line options in any way you see fit.
Command line parameters in C come in the parameters of the main(int argc, char *argv[]) method as strings.
And if you'd like to process command line parameters in a way similar to most UNIX commands, the function you're probably looking for is getopt()
Good luck!
The easiest thing is to write your main() like so:
int main(int argc, char* argv[]) { ...
Then inside that main you decide what happens to the command line arguments or "flags". You find them in argv and their number is argc.
flags are arguments passed into the main entry point of the program. For example, in a C++ program you can have
int main(int arc, char* argv[]){
return 0;
}
your arc is the # of arguments passed in, and the pointer gives u the list of actual arguments. so for
rm -Rf test
argc would be 3, and the argv array would contain your arguments. Notice argc >= 1 because the program name itself counts (rm). -RF is your 2nd parameter and test is your third.
So whenever you are typing commands in unix, you essentially are executing programs and passing them parameters that they operate on.
If you are really REALLY interested in the unix OS, you should look up forks and how they work. This can get pretty confusing to a newcomer though, so only if you are really interested in OS and how programs are executed.
GNU libc, which is very likely available on your system, has a library for this called getopt that can be used to parse the options in a sensible fashion. There are examples to get you started in the documentation linked below.
http://www.gnu.org/software/libc/manual/html_node/Getopt.html#Getopt

How to get the entire string reported by __LINE__

Is it possible to get the entire string on line reported through LINE macro.
Sample code:
#include <stdio.h>
#define LOG(lvl) pLog(lvl, __LINE__, __FILE__)
pLog(const char *str, int line, const char *file)
{
printf("Line [%u]: File [%s]", line, file);
}
int main ()
{
LOG("Hello"
"world");
return 0;
}
The output is: Line [13]: File [macro.c]
Now in a large code base i want to search this file and print the string "Hello world" present at line reported (in this case it is 13)
One way i was thinking is to search for this file first generate the output file with gcc -E do grep for pLog and save their string then grep for LOG in actual code file and save line number match the line number with the line number present in result and then do matching of index and print the string.
As string can be distributed across multiple lines (as in code Hello is in one line and world is in another line) so also need to take care of that.
Is there anyother best and fast way of doing it or gcc provide some option to convert back line and file to actual code
This is very easy to do with Clang. The following command dumps Abstract Syntax Tree (AST) for the file test.c to the file out:
clang -cc1 -ast-dump test.c > out
Looking at the AST in the generated file you can easily find the information you need:
(StringLiteral 0x1376cd8 <line:12:9, line:13:13> 'char [11]' lvalue "Helloworld")))
Clang gives start of the first token of the string (line:12:9), start of the last token of the string (line:13:13) and the full string ("Helloworld").
You can either parse the AST dump or use Clang API to get the same information. If this is not a one time task, I'd go for API since the AST dump format is more likely to change in the future.
All this of course make sense only if you have a reason not to print the string in pLog itself.

Resources