Dynamic file stream handling in C with freopen - c

I am trying to write a program that ideally accepts arguments that specify both a source file (to read from) and a destination file (to write to).
The program replaces specified characters in source file, with other specified characters, then writes the output to the destination file.
There are 3 special cases I want to handle, though:
Only a source file to read from is provided.
Desired Behavior: Display the result of replacing the text to the standard output (terminal)
Only a destination file to write to is provided.
Desired Behavior: Read from standard input, replacing desired letters and writing result to destination file name provided.
Neither the source file nor the destination file are provided.
Desired Behavior: Read from the standard in, replace characters, write to standard out.
I believe the way to do this is using freopen(), but I cannot wrap my head around the logic of when the file gets opened or how freopen() 3rd argument (stream) works.
What is the traditional way of handling this problem? Is freopen() even the function I am looking for to do this? Or is there some great lesser known function made for situations like these?
Some pseudo code would be really appreciated.

The third argument is which of the standard file streams you want to replace with a file.
So the logic will be something like:
const char *input_file = NULL;
const char *output_file = NULL;
// parse arguments, setting the above variables to the appropriate arguments if supplied
if (input_file) {
freopen(input_file, "r", stdin);
}
if (output_file) {
freopen(output_file, "w", stdout);
}
Then the rest of the program uses stdin and stdout normally.

The traditional (unixoid) way is to use only stdin and stdout.
If you want to provide an input file, use input redirection:
your_program < input_file
If you want to provide an output file, use output redirection:
your_program > output_file
If you want to provide an input file and an output file, use both ways of redirection:
your_program < input_file > output_file
And you could even add your program to a chain of commands, using pipes:
run_before | your_program | run_after
This gives you a maximum of flexibility.
It is still possible to provide options to your program.

Related

how to get the file name in C program, that i had given in input redirection?

steps:
Let's say I have a C program inputFileName.c
I run inputFileName with input redirection such as ./inputFileName < file
How can I print the name of the file in my C program that I have typed in the terminal as an input redirection file?
The input redirection is a function of the shell. Your inputFileName executable see this as standard input. Depending on the exact operating system, you may be able to use system-specific functions to get the information you want, but there is not a standard means of doing so.
Input redirection can be achieved not only with the '<' symbol, but also with '|'.
program < filename
is equivalent to
cat filename | program
From there, one could go to
cat file1 file2 file3 | program
You begin to see why the initial 'stdin' for an executable cannot and does not have a "filename" associated with it.
If input comes from a pipe, there can't be an associated filename. Also if the file has been deleted or moved before closing the file descriptor, there is no associated filename. A file can have multiple names. In that case there are multiple filenames.
Given that, the "associated filename" of a file descriptor doesn't really make much sense. And even if you could get that info, using the filename in any way might make race conditions an issue.
The linux kernel does try to track an associated filename if a file descriptor was created by opening a file. But the keyword here is "tries".
If you are running Linux, you can find the filenname for standard input as a symlink under "/proc/self/fd/0". Just remember that you should not rely on that name for anything more than debug or display purposes.

Redirecting file contents into another program in C

Making a basic shell and I need to handle file redirection. Specifically I am stumped on how I can feed data into a program like sort for example from a file.
Something on the command line would look like this:
$ sort < test.txt
How do I accomplish this kind of functionality in my own mini shell made in C?
I thought that maybe sort read from stdin but I guess I can't really write the contents of a file to stdin due to the read only aspect so I'm wondering how I actually get this data into something like sort for example? I am currently using forks and then using execvp() to execute programs.
You need to use freopen.
It works similarly to fopen. The first argument is the filename, the second argument is the mode, and the third argument is the file pointer to redirect. The return value is the new file pointer. So if you want to redirect stdin:
FILE *fp = freopen("input.txt", "r", stdin);
It returns a NULL pointer on failure, just like fopen.

Can I pass text file as an argument in a main function in C?

I am wondering if I could pass file as an argument in a main function? I mean not a name of the file but file itself.
Not unless something external (e.g. a bash script) reads in the file and adds it as an argument. If there is a binary 0 in the file, that would be interpreted as the end of string.
You can achieve something similar using input redirection, where the contents of a file is redirected to stdin, e.g.
myprogram < myTextFile
You would then be able to read the contents of the file by reading from stdin.
You could, as long as there's no 0 bytes in the file.
Also, you shouldn't.
If you want to know how to do that, it depends on the operating system.

Write an entire program to a file in C

I'm quite new to C programming, but I'm starting to get the hang of it.
For a school assignment, I have written a code in C to play Blackjack.
One of the requirements for the assignment, is that is has to have an option that saves the entire output (everything that's shown in cmd when the program is build and run).
I can't find how to do this anywhere.
Is there a way to write the entire output into a file?
Thanks in advance!
There are 3 ways to achieve what you want.
Use a file. This is the way I recommend. You will need the functions fopen to open a file and enter link description here to print the data in the file. I suggest you read the documentation of the functions in the links and look at the examples.
Redirect stdout to a file using freopen. This basically puts everything that you see now in the console in a file, by adding just one line.
Redirect the output of the program in a file. This is more a shell thing than a C programming technique, but I think it is worth mentioning. In an *NIX environment, the command ./a.out > file.txt will redirect the output of a.out to a file called file.txt in a similar manner freopen does.
You can pipe the stdout and stderr to a file when you build and run. For example, on Linux using the bash shell you can do try this (where the "build_script" is what you use to build and the "a.exe" is the program name):
$ ./build_script >& build_out.txt
$ ./a.exe >& run_out.txt &
The ">&" tells bash to pipe both stdout and stderr to the file. The final "&" in the second line tells bash to run the program in the background. It's hard to tell if this answer will suit your purposes since it's not clear exactly how the game is played from what you have posted. E.g., if you need to use stdin/stdout to play the game then maybe piping the "a.exe" stdout to a file might not work...
I'm assuming simple output redirection is not an option:
$ app > file.txt
Probably, you are using printf to print data to console. Instead of printf, you can use fprintf. fprintf can write data to an arbitrary file, just like printf does to the standard output (which is also a file), in this case the console.
You must first open the file where you will write the output. The command fopen will do this for you:
// this will open or create the file as text to write data.
FILE *f = fopen("my-file.txt", "w");
With the f variable (which you should check for NULL in case of error), you can pass it to fprintf to write data:
fprintf(f, "my super string: %s", string);
Note that despite the first argument being a FILE*, everything else behaves like printf. Actually you can think of printf as a wrapper where the first argument of the fprintf is always stdout.
Do not forget to close your file after you write data!
fclose(f);
This can be done once, after all the data is written to file.
Check the man pages for more info about these commands.
There are more complex (not that much actually) ways of accomplishing this, like using freopen, but I'm leaving this out of the answer. If you need more, update your answer.
EDIT
In your comment, you said you must save or not the output to a file at the end of the program. Well, the file management stuff above you still be usefull. The changes are the following:
You must store the output somewhere in order to decide whether to write to a file or not at the end of the program. Probably you are doing some data formatting with printf. You will have to change your calls from printf to snprintf. This command will write your data to a string, just as printf does prior to output it to the stdout, but it will skip the print-to-output- part.
Then, store the buffer at a list of strings and at the end of the program you write this list to the file or not.
This has some complications: you need a list of strings (a dynamically allocated array of arrays will be enough, actually); how big must your buffer be?
snprintf will return the size required to print the passed data to the buffer, no matter if the buffer is larger or smaller then the given one. But, if it is smaller, you will have to increase its size (reallocating it) and call again snprintf:
char *buffer = malloc(sizeof(char) * 41); // 40 chars + \0!
int size;
if ( size = snprintf(buffer, 41, "your format here", args) > 40 ) {
buffer = realloc(buffer, sizeof(char) * (size + 1));
snprintf(buffer, size + 1, "your format here", args);
}
// now your buffer have the correct data!
// print it to stdout!
puts(buffer);
// store it at the string list.
// execise!
Is left as an exercise wrapping this piece of code in a command to avoid repeat it everywhere you print anything. Also, it is an exercise to create the list of strings.
When you decide to write data to file, instead of use fprintf you can use fputs, as data is already formatted.
I don't know if there is an easier way. I think not.

C:copying multiple files into one

I am stuck/struggling with a problem I am trying in C(Linux) using API calls(only) to copy multiple input files via command line into one output file. I have searched the Internet for answers but none seem to solve.
My program allows me to specify multiple input files and one output file via the command line. For example:
./archiver file1.txt file2 file3 file4 outputfile
I read these parameters using argc/argv. For some reason when I do ls -l, ./archiver and outputfile have the same number of bytes, thus meaning none of my input files have been copied to my outputfile, just whatever was in memory (when I do cat outputfile it shows a bunch of these )
None of the contents from my input files are in my output files.
Please could you help me as after those bunch of "" I don't know what to do I have tried reading up on malloc() etc. but I don't know how to implement that or if thats even relevant here.
Any help is appreciated, thanks for your time.
file_desc_in = open(argv[i],O_RDONLY,0);
//NEED a loop to copy multiple files in...
while (!eof) {
bytes_read = read(file_desc_in, &buffer, sizeof(buffersize));
if (bytes_read > 1)
bytes_written = write(file_desc_out, &i, bytes_read);
else {
eof=1;
}
I haven't included the errors but I do have them. Thanks for replying immediately.
It'd help to see your code. There's not a lot here to go on, but I'm going to take a wild guess. I suspect you're copying the file specified by argv[0] (your program) and not getting the rest. I don't think I can do any better with what you've given.
You say you are only using API calls. What API are you talking about? The POSIX API? The standard C file I/O API?
If you are just combining input files, you don't really need to write a C program to do it. Since you are running Linux, try using the shell command cat input1 input2 input3 > output.
If you must write a C program to do it, start simple. Before you actually do any file I/O, make sure that you can interpret the input arguments correctly. Have your program simply read in the command-line input and print out something like this:
Input files: file1.txt file2.txt file2.txt
Output files: outputfile.txt
That way, you can verify that your CLI parsing code works correctly before you start worrying about file I/O. It's much easier to debug things one piece at a time.
Your outer loop needs to open each filename, and close it at the end of the loop. You close the output file at the very end, after all the input files are read.
You should also learn the difference between open, read, write and fopen, fread, fwrite.

Resources