how to check if there's a string in the command line - c

I have this command line:> write_strings "Hello World!" a.txt b.txt dir/a.txt.
all the elements (command, string, file names) go into an array of char pointer. how can I take an element and check if it's a string or a file name?
I don't mean the exact code lines, buts just need the idea. the program should return an error if there's no string.

You can use an API such as stat or access to check if the file pointed to by a path exists. There is no fundamental distinction between filepaths and regular strings when they are passed to your process.
If you're using the standard main(int argc, char *argv[]) convention, you can loop through argv, checking each one to see if it's a file via one of the previously-mentioned system calls.

Every string that can be passed on a command line is a potential pathname, since the only restriction in both cases is that there can't be any NULs.
A program with a command line syntax in which a specific argument might or might not be used as a pathname (depending on some vague definition of "filename-ish strings" or even a file existence test) is a bad design. Each argument should have a meaning defined by its order in the argument list, or by being associated with an option like -m msg or -o outputfile.
A well-behaved unix program will let the user create a file called Hello world! if he wants.

not regarding how meaningful the program might or might not be - you can compare the single characters of your char *argv[] by looping through them via argv[i][j]. If every string includes a ".txt" you do not have a string, which is not a filename in your context

Related

Strange behavior of argv when passing string containing "!!!!"

I have written a small program that takes some input parameters from *argv[] and prints them. In almost all use cases my code works perfectly fine. A problem only arises when I use more than one exclamation mark at the end of the string I want to pass as an argument ...
This works:
./program -m "Hello, world!"
This does NOT work:
./program -m "Hello, world!!!!"
^^ If I do this, the program output is either twice that string, or the command I entered previous to ./program.
However, what I absolutely don't understand: The following, oddly enough, DOES work:
./program -m 'Hello, world!!!!'
^^ The output is exactly ...
Hello, world!!!!
... just as desired.
So, my questions are:
Why does this strange behavior occur when using multiple exclamation marks in a string?
As far as I know, in C you use "" for strings and '' for single chars. So why do I get the desired result when using '', but not when using "" as I should (in my understanding)?
Is there a mistake in my code or what do I need to change to be able to enter any string (no matter if, what, and how many punctuation marks are used) and get exactly that string printed?
The relevant parts of my code:
// this is a simplified example that, in essence, does the same
// as my (significantly longer) code
int main(int argc, char* argv[]) {
char *msg = (char *)calloc(1024, sizeof(char));
printf("%s", strcat(msg, argv[2])); // argv[1] is "-m"
free(msg);
}
I already tried copying the content of argv[2] into a char* buffer first and appending a '\0' to it, which didn't change anything.
This is not related to your code but to the shell that starts it.
In most shells, !! is shorthand for the last command that was run. When you use double quotes, the shell allows for history expansion (along with variable substitution, etc.) within the string, so when you put !! inside of a double-quoted string it substitutes the last command run.
What this means for your program is that all this happens before your program is executed, so there's not much the program can do except check if the string that is passed in is valid.
In contrast, when you use single quotes the shell does not do any substitutions and the string is passed to the program unmodified.
So you need to use single quotes to pass this string. Your users would need to know this if they don't want any substitution to happen. The alternative is to create a wrapper shell script that prompts the user for the string to pass in, then the script would subsequently call your program with the proper arguments.
The shell does expansion in double-quoted strings. And if you read the Bash manual page (assuming you use Bash, which is the default on most Linux distributions) then if you look at the History Expansion section you will see that !! means
Refer to the previous command.
So !!!! in your double-quoted string will expand to the previous command, twice.
Such expansion is not made for single-quoted strings.
So the problem is not within your program, it's due to the environment (the shell) calling your program.
In addition to the supplied answers, you should remember that echo is your shell friend. If you prefix your command with "echo ", you will see what shell is actually sending to your script.
echo ./program -m "Hello, world!!!!"
This would have showed you some strangeness and might have helped steer you in the right direction.

How to pass a filename when executing a C program

I am trying to not hardcode the name of the input file in my C program. I have all of the other components working when I hardcode the filename. But would like to be able to pass it a string filename.
I am trying to execute compile a file called Matrix.c and name its executable matrix.
So, in terminal, when I get to my working directory.
gcc -g Matrix.c -o matrix
then when I compile
./matrix
It doesn't have a filename passed to it so I am gonna check for that and have the user input a filename to load.
However, when someone passes the filename, should it be passed as:
./matrix filename.txt
or
./matrix < filename.txt
With the latter option, I can't seem to get the name of the argument passed to the function from argv[1] — it's just "(Null)".
I know this is very simplistic question. But am I just completely off my rocker? Is it something to do with me running on OS X El Capitan. I know I've used the '<' convention before.
The issue is how the shell works, mainly. When you use:
./matrix filename.txt
then the program is given two arguments — the program name and the file name. When you use:
./matrix < filename.txt
then the program is given just one argument — the program name — and the shell arranges for its standard input to come from the file (and the file name is not passed to your program).
Either can be made to work; you just have to decide which you want to support. What should happen if the user types ./matrix file1.txt file2.txt file3.txt? One version of conventional behaviour would be to process each file in turn, writing each set of results to standard output. There are plenty of alternative behaviours — most of them have been used by someone at some time or another. Reading from standard input when there is no file name specified is a common mode of operation (think cat and grep and …).
Arguments to a command are in argv[1 .. argc-1].
The redirect from '<' sends the contents of the file to the program's stdin.
A third way to get the filename would be to print "Enter filename: " and then read the string typed by the user.

Passing/Using Terminal Arguments with C

So the purpose of my program is to simulate a chat- one text file contains responses (call it r.txt) and I write my messages to another (call it m.txt). What I'm looking to do is write code for it in a c file using xcode, then call the program in my command terminal (I'm using Mac OSX). My question is- how does one pass multiple arguments to a C program using the terminal?
I see that in main theres 2 variables, int argc and const char* argv[]. So then does C use the array to account for multiple command line arguments? Cause essentially I'd do something like "$(name of the program), file_name_1, file_name_2." How would I reference these in my C file?
The main function is: int main(int argc, const char *argv[]).
The first one argc is the number of elements in the array argv. The first element argv[0] is the name of the program. After that you have the strings of each given parameters.
The command line (shell) separated the parameters (by default) with spaces. So myprog foo bar will result to argv[0]="myprog" argv[1]="foo" argv[2]="bar" (and here argc=3).
Several spaces are not taken in count. If you parameters contain spaces you have to use quotes (i.e. myprog "arg with spaces" other "many if wanted".

Open and edit external file which has variable name in C

Quick question, since I only managed to find answers on the googlemobil regarding C++: Is there any way to open and edit files in C, where the file has a variable name?
Let's make it a bit clearer: I have a prompt, which checks if the user gives a filename or not. If no filename has been entered, the program automatically opens a client.conf file I created in the same directory; now this was the easy part of the if-else statement.
However, IF a name has been given, how do I make my program create a file givenInput.conf in the same directory, and send data to it? I suppose the r/w interaction would be the same as with the first case of the if-statement, using fopen(), however fopen() uses as first parameter const char *restrict filename, and I am trying to make something for chars that are NOT constants...
In C++ there is a way to bypass this by creating a separate (empty) array, pasting the input and then just adding the string suffix to it; also, it uses a C++ specific function (whom name I forgot, sorry ^^) to parse the variable filename....
Any ideas how to manage this in regular, plain good'ol C? I'm new to the C programming language, please be gentle for a newbie ;)
You can send in a non-constant string where a constant string is expected and there is no need for a cast. So just open the file using a string you have constructed in whatever manner suits you best:
char filename[1024];
getFilenameSomehow(filename, 1024);
fopen(filename, "w");
You may not, however, send in a constant string where a non-constant string is expected.
const char *myConst = "May not be changed";
memset(myConst, 'X', strlen(myConst)); // Error! You may not modify a const string.
You can cast your variable to const char *
char file_var_name[100];
scanf("%99s", file_var_name);
fopen((const char *) file_var_name, "r");
You can read the input using command line arguments to main() i.e. using argc and argv . Read this for more details
Use strcat (present in string.h) to concatenate ".conf" at the end of filename.
Read here about strcat.

Determine if a file contains a certain string

I am looking for a way to determine if a certain file contains a certain string. It can be a system call or a C function, it doesn't matter.
I tried with grep, but it doesnt return anything
//name is the directory entry name
char grepcmd[150];
strcpy(grepcmd,"grep -c hello ");
strcat(grepcmd, name);
int status = system(grepcmd);
You are doing well. status should be zero if your given file with name name contains hello string. Otherwise it should be nonzero value.
If you're up for system calls, then just mmap() the file and call something like strnstr(). (You won't be able to call the real strnstr() since it will stop at any \0 in your file, so you'll have to write your own.)

Resources