It's possible to make a code that recognizes whether a file was passed like:
program.out < file.dat
I search an answer for this because I want to write code to do something like this:
int main (int argc, char *argv[])
{
char filename[50];
if ( argc > 1 )
{
strcpy (filename, argv[1]);
}
else if ( SOMETHING )
{
/* copy the stdin into fin (?) */
}
FILE *fin;
fin = fopen (filename, "r");
/* ... */
fclose(fin);
}
return 0;
}
In which SOMETHING evaluates to 1 if the file was passed with <, and 0 otherwise.
If it's possible, I am looking for a solution working in standard C.
We cannot detect this in ISO C (that is, without resorting to platform extensions, like getting the file descriptor using fileno on POSIX and then running some tests on it by obtaining attributes with fstat and so forth.)
The stdin stream is required by ISO C to be line buffered if it is connected to an interactive device. This doesn't help us, however, since there are no portable functions to inquire about the buffering mode of a FILE *: there are only "setters", no "getters". The GNU C library has a __flbf (FILE *stream) which reports whether or not a stream is line-buffered, but it is an obvious extension, declared in a <stdio_ext.h> header.
If your program must work with a file, and not with standard input from an interactive device, then a good solution is to make the argument to the program mandatory. Make it require a filename argument and always open that file. Then you're sure you have the file.
You can also make the argument optional, and if it is missing, then open a default file, ignoring stdin.
You can also use freopen to make stdin point to a file. Then code which works with stdin implicitly will take input from that file:
Pseudo-code:
name = "some default"
if we have an argument
name = that argument
if (freopen(name, mode, stdin) == 0)
handle error
else
stdin is now a file; process it
If you really must support the program < file situation, while flagging the program situation (interactive input) as invalid, you need the aforementioned platform-specific hacks.
If you're OK with a Unix-specific solution, you can use isatty():
FILE *fin;
int need_to_close;
if (isatty(fileno(STDIN))) { // I/O not redirected
fin = fopen("file.dat", "r");
need_to_close = 1;
} else {
fin = stdin;
need_to_close = 0;
}
/* ... */
if (need_to_close) {
fclose(fin);
}
May be this answer can help:
It says,
On a Posix system, you can test whether or not cin comes from a
terminal or is redirected using isatty
#include <unistd.h>
if (isatty(STDIN_FILENO)) {
// not redirected
} else {
// redirected
}
Related
I have the following code to find the release of the Linux distribution that I am using.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
return print_osinfo();
}
int print_osinfo()
{
FILE *fp;
extern FILE* popen();
char buffer[128];
int index = 0;
memset(buffer,0,sizeof(buffer));
fp = popen("/etc/centos-release", "r");
if(!fp)
{
pclose(fp);
fp = popen("/etc/redhat-release", "r");
if(!fp)
{
pclose(fp);
return 1;
}
}
while(fgets(buffer, sizeof(buffer), fp)!= NULL)
{
printf("%s\n",buffer);
}
pclose(fp);
return 0;
}
If I run the above code on Ubuntu 14.04 I get the following error.
sh: 1: /etc/centos-release: not found
I fail to understand why it is not trying to open redhat-release and then return -1. Also, is there a way to prevent the above error from being displayed on the screen?
popen is a function more suited for accessing the output of a subprocess than for simply accessing the contents of a file. For that, you should use fopen. fopen takes a file path and a mode as arguments, so all you would need to do is replace your popens with fopens and it should work perfectly.
If you really want to use popen, it takes a shell command as it's first argument, not a filename. Try popen("cat /etc/centos-release","r"); instead.
Now, you might be a bit confused, because both of these functions return a FILE pointer. fopen returns a pointer to the file you passed as an argument. popen, however, returns a pipe pointing to the output of the command you passed to it, which C sees as a FILE pointer. This is because, in C, all i/o is file access; C's only connection to the outside world is through files. So, in order to pass the output of some shell command, popen creates what C sees as a FILE in memory, containing the output of said shell command. Since it is rather absurd to run a whole other program (the shell command) just to do what fopen does perfectly well, it makes far more sense to just use fopen to read from files that already exist on disk.
Why does fprintf give different results in the following example programs?
Example 1:
int main(){
FILE *f;
char buf[512];
char name[128] = {"filename"};
f = fopen(name, "w");
fprintf(f, "asdas\n");
fprintf(f, "asdas\n");
while(1){}
return 0;
}
If I terminate this program using CTRL+C, I get an empty file named filename.
However, using
Example 2:
int main(){
FILE *f;
char buf[512];
char name[128] = {"wpa_supplicant.conf"};
f = fopen(name,"w");
while(1){
fprintf(f, "asdas\n");
}
return 0;
}
If I terminate this program using CTRL+C, I get file named filename, and it contains many lines with the string asdas.
Why are the strings not written to the file in the first example, but they are written to the file in the second example?
In the second case, there are enough fprintf calls for the internal buffers to be flushed to disk.
With the first program, if you put a fflush(f) before the while loop, the strings will be written to the file.
#include <stdio.h>
int main(void) {
FILE *f = fopen("filename", "w");
if (!f) {
perror("Failed to open 'filename' for writing");
exit(EXIT_FAILURE);
}
fprintf(f, "asdas\n");
fprintf(f, "asdas\n");
if ( fflush(f) != 0 ) {
perror("Flushing output failed");
exit(EXIT_FAILURE);
}
while(1){}
return 0;
}
Output:
C:\...\Temp> cl file.c
Microsoft (R) C/C++ Optimizing Compiler Version 18.00.31101 for x64
...
/out:file.exe
C:\...\Temp> file
^C
C:\...\Temp> type filename
asdas
asdas
Keep in mind:
Upon successful completion, fflush() shall return 0; otherwise, it shall set the error indicator for the stream, return EOF, and set errno to indicate the error.
As mentioned in the answer by #SinanÜnür this is indeed an issue with the buffering of data in internal buffers. You need to flush manually in the first case to get that data actually written into the file.
However, FWIW, I just want to add here, you see this behavior because of the abnormal termination of the program by a signal (generated by CTRL+C).
If your program would have ended normally, (for example, by calling exit(), after a large-enough but controlled while() loop), then both the cases would have shown the same behavior, as in that scenario, all the open streams would have been flushed automatically.
The exit() function shall then flush all open streams with unwritten buffered data and close all open streams. Finally, the process shall be terminated ...
Basically what I want to do is have a program with int main(argc, *argv[]) and instead of writing chars into command line, I want to have my program read those words from a file. How could I accomplish this? Is there a special command in Linux for that?
You can use standard redirect operations in a *nix shell to pass files as input:
./myprogram < inputfile.txt
This statement executes your program (myprogram) and pumps the data inside of inputfile.txt to your program
You can also redirect the output of program to a file in a similar fashion:
./myprogram > outputfile.txt
Instead of doing
for(int i = 1; i < argc; i++)
{
insert(&trie, argv[i]);
}
you could doing something like
FILE *input;
char *line;
....
while (fscanf(input, "%ms", &line) != EOF) {
insert(&trie, line);
/* If you make a copy of line in `insert()`, you should
* free `line` at here; if you do not, free it later. */
free(line);
}
Use redirection
yourprogram < youtextfile
will offer the content of yourtextfile as standard input (stdin) to yourprogram. Likewise
yourprogram > yourothertextfile
will send everything the program writes to standard output (stdout) to yourothertextfile
You'll notice when reading man pages that most system calls have a version that works directly with stdin or stdout
For example consider the printf family:
printf ("hello world\n");
is a shorter version of
fprintf (stdout,"hello world\n");
and the same goes for scanf and stdin.
This is only the most basic usage of redirection, which in my opinion is one of the key aspects of "the unix way of doing things". As such, you'll find lots of articles and tutorials that show examples that are a lot more advanced than what I wrote here. Have a look at this Linux Documentation Project page on redirection to get started.
EDIT: getting fed input via redirection ior interactively "looks" the same to the program, so it will react the same to redirected input as it does to console input. This means that if your program expects data line-wise (eg because it uses gets() to read lines), the input text file should be organized in lines.
By default, every program you execute on POSIX-compliant systems has three file descriptors open (see <unistd.h> for the macros' definition): the standard input (STDOUT_FILENO), the standard output (STDOUT_FILENO), and the error output (STDERR_FILENO), which is tied to the console.
Since you said you want read lines, I believe the ssize_t getline(char **lineptr, size_t *n, FILE *stream) function can do the job. It takes a stream (FILE pointer) as a third argument, so you must either use fopen(3) to open a file, or a combination of open(2) and fdopen(3).
Getting inspiration from man 3 getline, here is a program demonstrating what you want:
#define _GNU_SOURCE
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *fp;
size_t len;
char *line;
ssize_t bytes_read;
len = 0;
line = NULL;
if (argc > 1)
{
fp = fopen(argv[1], "r");
if (fp == NULL)
{
perror(*argv);
exit(EXIT_FAILURE);
}
}
else
fp = stdin;
while ((bytes_read = getline(&line, &len, fp)) != -1)
printf("[%2zi] %s", bytes_read, line);
free(line);
exit(EXIT_SUCCESS);
}
Without arguments, this program reads lines from the standard input: you can either feed it lines like echo "This is a line of 31 characters" | ./a.out or execute it directly and write your input from there (finish with ^D).
With a file as an argument, it will output every line from the file, and then exit.
You can have your executable read its arguments on the command line and use xargs, the special Linux command for passing the contents of a file to a command as arguments.
An alternative to xargs is parallel.
Depending on command-line arguments, I'm setting a file pointer to point either towards a specified file or stdin (for the purpose of piping). I then pass this pointer around to a number of different functions to read from the file. Here is the function for getting the file pointer:
FILE *getFile(int argc, char *argv[]) {
FILE *myFile = NULL;
if (argc == 2) {
myFile = fopen(argv[1], "r");
if (myFile == NULL)
fprintf(stderr, "File \"%s\" not found\n", argv[1]);
}
else
myFile = stdin;
return myFile;
}
When it's pointing to stdin, fseek does not seem to work. By that, I mean I use it and then use fgetc and I get unexpected results. Is this expected behavior, and if so, how do I move to different locations in the stream?
For example:
int main(int argc, char *argv[]) {
FILE *myFile = getFile(argc, argv); // assume pointer is set to stdin
int x = fgetc(myFile); // expected result
int y = fgetc(myFile); // expected result
int z = fgetc(myFile); // expected result
int foo = bar(myFile); // unexpected result
return 0;
}
int bar(FILE *myFile) {
fseek(myFile, 4, 0);
return fgetc(myFile);
}
Yes, it's perfectly normal that fseek won't work on stdin -- it'll normally only work on a disk file, or something reasonably similar.
Though it's really a POSIX thing, you can typically use if (isatty(fileno(myFile))) to get at least a pretty good idea of whether seeking will work in a particular file. In some cases, isatty and/or fileno will have a leading underscore (e.g., IIRC the versions provided with Microsoft's compilers do).
Fseek() is based on lseek(), and the lseek man page discusses possible errors, including:
[ESPIPE] Fildes is associated with a pipe, socket, or FIFO.
If stdin is connected to a pseudo tty, I believe it will have socket behavior.
Here is the relevant entry in the ANSI standard concerning the fseek function:
For a text stream, either offset shall be zero, or offset shall be a value returned by an earlier successful call to the ftell function on a stream associated with the same file and whence shall be SEEK_SET
So, possible but with some limitations
#include <stdio.h>
int main() {
printf("This goes to screen\n");
freopen("out.txt", "a", stdout);
printf("This goes to out.txt");
freopen("/dev/stdout", "a", stdout);
printf("This should go to screen too, but doesn't\n");
return 0;
}
I call freopen to redirect the stdout to out.txt then I print something on the file, now I want to redirect it back to the screen, but freopen("/dev/stdout", "a", stdout); doesn't work. Is there any way to do that using ANSI C or POSIX system calls?
I can't think of a way to do this in a cross-platform manner, but on GNU/Linux systems (and maybe other POSIX-compliant ones, too) you can freopen ("/dev/tty", "a", stdout). Is this what you were trying to do?
Unfortunately, there doesn't seem to be a good way:
http://c-faq.com/stdio/undofreopen.html
The best recommendation is not to use freopen in this circumstance.
Generally speaking, you can't. You have closed the file, which could've been pipe or whatever. It's not reopenable. You might have saved stdout value, then assign some fopen to it and then close it and copy the old value back. Example:
FILE *o = stdout;
stdout=fopen("/tmp/crap.txt","a");
printf("Oh no!\n");
fclose(stdout);
stdout = o;
Mike Weller suggested below in comments that stdout might not always be writable. In this case something like that might help:
int o = dup(fileno(stdout));
freopen("/tmp/crap.txt","a",stdout);
printf("Oh no!\n");
dup2(o,fileno(stdout));
close(o);
Another edit: if you're using it to redirect output from the child process like your comment elsewhere suggest, you can redirect it after the fork.
Use fdopen() and dup() as well as freopen().
int old_stdout = dup(1); // Preserve original file descriptor for stdout.
FILE *fp1 = freopen("out.txt", "w", stdout); // Open new stdout
...write to stdout... // Use new stdout
FILE *fp2 = fdopen(old_stdout, "w"); // Open old stdout as a stream
...Now, how to get stdout to refer to fp2?
...Under glibc, I believe you can use:
fclose(stdout); // Equivalent to fclose(fp1);
stdout = fp2; // Assign fp2 to stdout
// *stdout = *fp2; // Works on Solaris and MacOS X, might work elsewhere.
close(old_stdout); // Close the file descriptor so pipes work sanely
I'm not sure whether you can do the assignment reliably elsewhere.
Dubious code that does actually work
The code below worked on Solaris 10 and MacOS X 10.6.2 - but I'm not confident that it is reliable. The structure assignment may or may not work with Linux glibc.
#include <stdio.h>
#include <unistd.h>
int main(void)
{
printf("This goes to screen\n");
int old_stdout = dup(1); // Consider dup(STDOUT_FILENO) or dup(fileno(stdout))
FILE *fp1 = freopen("out.txt", "a", stdout);
printf("This goes to out.txt\n");
fclose(stdout);
FILE *fp2 = fdopen(old_stdout, "w");
*stdout = *fp2; // Unreliable!
printf("This should go to screen too, but doesn't\n");
return 0;
}
You can't say you weren't warned — this is playing with fire!
If you're on a system with the /dev/fd file system, you could create the name of the file implied by the file descriptor returned from dup() with sprintf(buffer, "/dev/fd/%d", old_stdout) and then use freopen() with that name. This would be a lot more reliable than the assignment used in this code.
The better solutions either make the code use 'fprintf(fp, ...)' everywhere, or use a cover function that allows you set your own default file pointer:
mprintf.c
#include "mprintf.h"
#include <stdarg.h>
static FILE *default_fp = 0;
void set_default_stream(FILE *fp)
{
default_fp = fp;
}
int mprintf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (default_fp == 0)
default_fp = stdout;
int rv = vfprintf(default_fp, fmt, args);
va_end(args);
return(rv);
}
mprintf.h
#ifndef MPRINTF_H_INCLUDED
#define MPRINTF_H_INCLUDED
#include <stdio.h>
extern void set_default_stream(FILE *fp);
extern int mprintf(const char *fmt, ...);
#endif
Clearly, you can create an mvprintf() and other functions as needed.
Example use of mprintf()
Then, in place of the original code, you can use:
#include "mprintf.h"
int main()
{
mprintf("This goes to screen\n");
FILE *fp1 = fopen("out.txt", "w");
set_default_stream(fp1);
mprintf("This goes to out.txt\n");
fclose(fp1);
set_default_stream(stdout);
mprintf("This should go to screen too, but doesn't\n");
return 0;
}
(Warning: untested code - confidence level too high. Also, all code written assuming you use a C99 compiler, primarily because I declare variables when I first need them, not at the beginning of the function.)
Caution:
Note that if the original program is invoked as ./original_program > file or ./original_program | grep something (with redirected output) or is run from a cron job, then opening /dev/tty is not usually appropriate as a way to reopen standard output because the original standard output was not the terminal.
Also, note that if the redirection of standard output is used prior to forking and execing a child program and the original standard output is reinstated in the parent, then the sequence of operations is wrong. You should fork and then adjust the I/O of the child (only), without modifying the parent's I/O at all.
On Windows, you can open "CONOUT$".
freopen("test.txt", "w", stdout);
printf("this goes to test.txt");
freopen("CONOUT$", "w", stdout);
printf("this goes to the console\n");
This probably doesn't work if stdout is redirected to start with.
The following code (SwapIOB) is used in Testbenches that want to store
the stdout stream for comparison to an expected results file.
Background: File streams are managed using an _IOB structure that is stored in an array of 20 _IOB entries. This includes stdout stream. The IOBs are stored in an array. When a file is created the application code gets a ptr to an element in that array. The application code then passes that ptr to the OS for processing I/O calls. Thus, the OS does NOT itself contain or rely on its own pointers to the application's IOB.
Requirement: When running a testbench the stdout messages issued by an application should be re-directed to a file. However, after the module under test has completed then stdout messages should be re-redirected to the console.
This routine was tested and is currently used on Windows XP/Pro system.
void SwapIOB(FILE *A, FILE *B) {
FILE temp;
// make a copy of IOB A (usually this is "stdout")
memcpy(&temp, A, sizeof(struct _iobuf));
// copy IOB B to A's location, now any output
// sent to A is redirected thru B's IOB.
memcpy(A, B, sizeof(struct _iobuf));
// copy A into B, the swap is complete
memcpy(B, &temp, sizeof(struct _iobuf));
} // end SwapIOB;
Application code uses SwapIOB() similar to:
FILE *fp;
fp = fopen("X", "w");
SwapIOB(stdout, fp);
printf("text to file X");
SwapIOB(stdout, fp);
fclose(fp);
printf("text to console works, again!");