Print with less(1) from C - c

I would like to print a big matrix of data which I have in a linked list. It doesn't fit into a terminal (80 lines), so it is inconvenient to print it with standard printing functions; and less is already invented, so I wouldn't want to be reinventing it using ncurses; so I want to pass some printfd lines to less.
My first guess would be to write to a file, and then system("less -S file");, and then delete the file.
A more complicated solution would be to rewrite less so that its main() is converted to a less() function that I can call from C, and instead of a filename string I could provide it with a file descriptor or a stream.
Is there any way that doesn't involve needing to create a file and also not needing to rewrite (part of) less?

You could consider using POSIX functions popen() and pclose().
You'd use:
FILE *fp = popen("less", "w");
if (fp != NULL)
{
…write output to fp…
pclose(fp);
}
else
…report error…
Note that the pclose() will wait for less to exit. If you want to, you can capture the return value from pclose() and analyze it. See How to detect if shell failed to execute a command after popen()? for discussion of this.

Related

Can a file descriptor be duplicated multiple times?

I've been looking for quite a while and cannot find the answer to my question.
I'm trying to reproduce a shell in C, with full redirections. In order to do this, I wanted to open the file before executing my command.
For example, in ls > file1 > file2, I use dup2(file1_fd, 1) and dup2(file2_fd, 1) and then I execute ls to fill the files, but it seems a standard output can only be open once so only file2 will be filled, because it was the last one to be duplicated.
Is there a way to redirect standard output to multiple file?
Is there something I am missing? Thanks!
Is there a way to redirect standard output to multiple files?
Many file descriptors cannot be made one file descriptor. You need to write into each file descriptor separately. This is what tee utility does for you.
What you are asking for is the exact reason why the tee command exists (you can take a look at its source code here).
You cannot duplicate a file descriptor using dup2() multiple times. As you already saw, the last one overwrites any previous duplication. Therefore you cannot redirect the output of a program to multiple files directly using dup2().
In order to do this, you really need multiple descriptors, and therefore you would have to open both files, launch the command using popen() and then read from the pipe and write to both files.
Here is a very simple example of how you could do it:
#include <stdio.h>
#include <stdlib.h>
#define N 4096
int main(int argc, const char *argv[]) {
FILE *fp1, *fp2, *pipe;
fp1 = fopen("out1.txt", "w");
if (fp1 == NULL) {
perror("fopen out1 failed");
return 1;
}
fp2 = fopen("out2.txt", "w");
if (fp2 == NULL) {
perror("fopen out2 failed");
return 1;
}
// Run `ls -l` just as an example.
pipe = popen("ls -l", "r");
if (pipe == NULL) {
perror("popen failed");
return 1;
}
size_t nread, nwrote;
char buf[N];
while ((nread = fread(buf, 1, N, pipe))) {
nwrote = 0;
while (nwrote < nread)
nwrote += fwrite(buf + nwrote, 1, nread - nwrote, fp1);
nwrote = 0;
while (nwrote < nread)
nwrote += fwrite(buf + nwrote, 1, nread - nwrote, fp2);
}
pclose(pipe);
fclose(fp2);
fclose(fp1);
return 0;
}
The above code is only to give a rough estimate on how the whole thing works, it doesn't check for some errors on fread, fwrite, etc: you should of course check for errors in your final program.
It's also easy to see how this could be extended to support an arbitrary number of output files (just using an array of FILE *).
Standard output is not different from any other open file, the only special characteristic is for it to be file descriptor 1 (so only one file descriptor with index 1 can be in your process) You can dup(2) file descriptor 1 to get, let´s say file descriptor 6. That's the mission of dup() just to get another file descriptor (with a different number) than the one you use as source, but for the same source. Dupped descriptors allow you to use any of the dupped descriptors indifferently to output, or to change open flags like close on exec flag or non block or append flag (not all are shared, I'm not sure which ones can be changed without affecting the others in a dup). They share the file pointer, so every write() you attempt to any of the file descriptors will be updated in the others.
But the idea of redirection is not that. A convention in unix says that every program will receive three descriptors already open from its parent process. So to use forking, first you need to consider how to write notation to express that a program will receive (already opened) more than one output stream (so you can redirect any of them properly, before calling the program) The same also applies for joining streams. Here, the problem is more complex, as you'll need to express how the data flows might be merged into one, and this makes the merging problem, problem dependant.
File dup()ping is not a way to make a file descriptor to write in two files... but the reverse, it is a way to make two different file descriptors to reference the same file.
The only way to do what you want is to duplicate write(2) calls on every file descriptor you are going to use.
As some answer has commented, tee(1) command allows you to fork the flow of data in a pipe, but not with file descriptors, tee(1) just opens a file, and write(2)s there all the input, in addition to write(2)`ing it to stdout also.
There's no provision to fork data flows in the shell, as there's no provision to join (in paralell) dataflows on input. I think this is some abandoned idea in the shell design by Steve Bourne, and you'll probably get to the same point.
BTW, just study the possibility of using the general dup2() operator, which is <n>&m>, but again, consider that, for the redirecting program, 2>&3 2>&4 2>&5 2>&6 mean that you have pre-opened 7 file descriptors, 0...6 in which stderr is an alias of descpritors 3 to 6 (so any data written to any of those descriptors will appear into what was stderr) or you can use 2<file_a 3<file_b 4<file_c meaning your program will be executed with file descriptor 2 (stderr) redirected from file_a, and file descriptors 3 and 4 already open from files file_b and file_c. Probably, some notation should be designed (and it doesn't come easily to my mind now, how to devise it) to allow for piping (with the pipe(2) system call) between different processes that have been launched to do some task, but you need to build a general graph to allow for generality.

how to completely close the file write before starting another process which uses it?

My program creates a linux shell file, then it call 'popen' to execute it. To my surprise from time to time I am getting the following message: /bin/bash: bad interpreter: Text file busy. So, am looking for a way to solve this problem. Any suggestions?
Here is a skeleton code of what i am doing:
FILE *f = fopen(shFile, "w");
fprintf(f, ...);
...
fclose(f);
FILE *job = popen(shFile, "r");
...
So, both processes run on the same machine, there is no 'nfs' involved, but still the popen process thinks that the file is opened for write, even after i did close. So, some system buffers are not flushed yet.
It looks like sync() works (though it is difficult to tell). However it slows down everything significantly.
When you leave the kernel to determine the interpreter to be used with a script file using a shebang, the kernel must take a similar "lock" on the script file as it does for binaries. (This is a kernel-internal "lock" that you can only observe from userspace. If the file is open for writing by anyone, the lock fails with ETXTBUSY.)
It is trivially to avoid that. You are free to edit script files even when they are being interpreted, if you execute the interpreter instead with the script name as a parameter.
In OP's case, it means executing bash %s, where %s is replaced with the contents of shFile. This also means the file referred to by shFile does not need to be executable; only readable.
If we assume shFile does not contain any ' characters, then in Linux it is sufficient to use
char *jobcmd = NULL;
FILE *job;
if (asprintf(&jobcmd, "bash '%s'", shFile) == -1) {
/* Typically an out of memory error. */
fprintf(stderr, "%s.\n", strerror(errno));
exit(EXIT_FAILURE);
}
errno = ENOMEM;
job = popen(jobcmd, "r");
if (!job) {
fprintf(stderr, "Cannot execute %s: %s.\n", shFile, strerror(errno));
exit(EXIT_FAILURE);
}
free(jobcmd);
jobcmd = NULL;
In general, you should consider a custom routine that constructs the sh shell command needed to execute the desired interpreter with the file name as a parameter, applying any escaping as necessary. (In POSIX sh shells, you can escape single quotes in a single-quoted string using '"'"'.)
If the script is executed only once, a custom replacement for popen()/getline() or fread() or fgetc()/pclose() can be used to write the script to the standard input of the interpreter (here, bash -s), while also retrieving the output of the script into a single array, line per line (perhaps using a callback function?), or character-by-character. This approach has the benefit of the script never being stored on any filesystem.
In general, it is much more common, and definitely recommended, to install the scripts as part of the binary, and supply any specifics to it via command-line parameters (for example, bash /usr/share/yourapp/somescript.bash 'arg1' 'arg2').
In Linux and BSDs, these scripts are usually put somewhere under /usr/lib/yourapp/ or /usr/share/yourapp/.

How to store a variable out of a program in C? [duplicate]

This question already has an answer here:
I want to store a value even after my program ends
(1 answer)
Closed 7 years ago.
I am writing a program to organize some items. It starts off by getting the date/time and randomly generating a list of some items. But the next time you run it, the program shouldn't generate any of the same items as last time. So basically the date and time is like a seed for random generation.
But is there a way to store the data outside of the program? That way I can close the program and my PC, but when I return it still remembers the variable.
I've thought about it and it seems like the only way is to go in the program and manually define the variable. So I haven't tried anything yet and it would be pointless to show my code. Please tell me if there is a way to externally store the variable or if you have any alternate solutions.
You have two choices :
Using a file
It's the easiest way to do this :
The first time, you just need to open (and create) a file (man fopen), write your variable in it (man fwrite).
Every next time, you'll need to open the file, and read your variable from it (man fread).
Using a database
Harder, but better if you need to store many datas. This isn't your case, so just go with a file
General Idea is to use Non Volatile RAM .
You can mimic the same by using a file.
Need to take care of writing the contents of the context before closing the program and reading the same during the program startup.
For programming with Files ,you can refer any of good sites.
To store the data externally, so that it is saved, use a file.(http://www.cplusplus.com/reference/cstdio/fopen/)
FILE *fp;
/* open a file in write mode */
if (fp = fopen("myfilename", "w")) {
fprintf(fp, "Hello world");
if (fclose(fp) == EOF) /* fclose returns EOF on error */
perror("fclose");
} else
perror("fopen"); /* error */
/* open the file in read mode */
char line[80];
if (fp = fopen("myfilename", "r")) {
fgets(line, 79, fp); /* read the first line */
printf("%s", line);
if (fclose(fp))
perror("fclose");
} else
perror("fopen"); /* error */
Classical way to save many variables of different types is serialization. But there are no standard serialization method in C, so you need to implement your own or use existent (for example, tpl or gwser). If you need to save only one-two variables it is simplier to use fopen() + printf() + fclose().

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 Programming linux , read system inputs like ping or ls -l

i trying make a custom method what causes return a char with system output.
the pseudocode like this.
char *my_Out(char *in ){
in = system ("ping %s",in);
return in;
}
thanks for the help.
You can use popen, which returns you a stream that you can read the output from. By reading until end-of-file, into a string (probably one that dynamically grows as necessary), you can implement what you're asking for.
A few things
system() is not a printf style function. You'll need to use sprintf() to create your argument before.
system()'s return value is an int, non a char
It's generally not a good idea to overwrite function parameters.
What are you trying to do? It looks like all this function does is run ping (which, without the -c argument, will never finish running on linux).
Duplicate the stdout to some other file descriptor by using dup2.After the execution of the command read all the lines from the file using that file descriptor and return it.

Resources