Write through a pipe with fputc - c

For some reason when I try to write through a pipe with fputc my program doesn't work; however, it works fine when I use the write system call. Here is the part of my code using fputc:
FILE *input = fopen(argv[1], "rb");
FILE *toSort = fdopen(ps_fd[1], "wb");
/* close the side of pipe I am not going to use */
close (ps_fd[0]);
char temp;
char buf[1];
while ((temp=fgetc(input)) != EOF)
{
buf[0] = (char)temp;
fputs(buf, toSort);
buf[0] = '\0';
}
fputs(buf, toSort);
close(ps_fd[1]);

use fflush(toSort) after fputs()

The question title asks about fputc() but the code (mis)uses fputs().
Note that fputs() expects a null-terminated string. It is not appropriate for binary data; it won't write a zero (or null) byte.
Additionally, you are not null terminating the string. You are not providing enough storage for the null termination. You are not closing the file correctly. You should use int temp since fgetc() returns an int, not a char. The minimum changes needed to use fputs() are:
FILE *input = fopen(argv[1], "rb");
FILE *toSort = fdopen(ps_fd[1], "wb");
close(ps_fd[0]);
int temp;
char buf[2] = ""; // Two characters allocated; null terminated
while ((temp = fgetc(input)) != EOF)
{
buf[0] = (char)temp;
fputs(buf, toSort);
}
fclose(toSort); // fclose() to flush the buffered data
Or, using fputc():
FILE *input = fopen(argv[1], "rb");
FILE *toSort = fdopen(ps_fd[1], "wb");
close(ps_fd[0]);
int temp;
while ((temp = fgetc(input)) != EOF)
fputc(temp, toSort);
fclose(toSort);

Related

Using stdin and stdout if no file is given in C

I have a program that copies a source file to a destination file.
In the event that only 1 or neither of these files are provided by the user, I'd like to use stdin or stdout.
For example: The source file name is not provided in command line arguments, but the destination file is. The program should read input from stdin and write to the given destination file.
I know of freopen() but I don't know how I should use it in this case.
Below is my boilerplate code for how I think the logic is done, but I can't find any examples of this that are helpful for me to learn. Any insight is appreciated.
char *src = NULL; (unless user provides in preceding code not shown)
char *dest = NULL; (^^)
// open files based on availability
// src and dest not provided, read from stdin and write to stdout
if (src == NULL && dest == NULL) {
FILE *in = freopen(src, "r", stdin);
FILE *out = freopen(dest, "w", stdout);
// TODO
fclose(in);
fclose(out);
// src not provided, read from stdin
} else if (src == NULL) {
FILE *in = freopen(src, "r", stdin);
// TODO
fclose(in);
// dest not provided, write result to stdout
} else {
FILE *out = freopen(dest, "w", stdout);
// TODO
fclose(out);
}
I tend to avoid freopen and use a different approach. I define two FILE * variables and either use fopen() if the filename is provided or set them to stdin or stdout as appropriate if not:
#include <stdio.h>
/* copying files: 0, 1 or 2 arguments */
int main(int argc, char *argv[]) {
FILE *in = stdin;
FILE *out = stdout;
char *srcfile = NULL;
char *destfile = NULL;
int c;
if (argc > 1) {
srcfile = argv[1];
if (argc > 2)
destfile = argv[2];
}
if (srcfile && strcmp(srcfile, "-")) {
if ((in = fopen(srcfile, "r")) == NULL) {
perror(srcfile);
return 1;
}
}
if (destfile && strcmp(destfile, "-")) {
if ((out = fopen(destfile, "w")) == NULL) {
perror(destfile);
return 1;
}
}
while ((c = getc(in)) != EOF) {
putc(c, out);
}
if (in != stdin)
fclose(in);
if (out != stdout)
fclose(out);
return 0;
}
Just if statements that's it. Verify if the src is NULL, if so fopen(stdin, "r") but don't close it after or it will cause undefined behaviour (I'm talking about stdin).
For stdout you don't even have to open it so you can write in it just like that. Example:
int is_in = src == NULL;
FILE *in = fopen(is_in ? stdin : src, "r")
if (!is_in)
fclose(in);

How to read until EOF from STDOUT in C?

#1: I do not know the size of output produced by stdout, given a command.
#2: I don't want to use char array like
char buffer[1024];
as it will result in memory shortage or wastage.
#3: If I use character pointer like
char *buffer;
I will have to allocate allocate memory for it like
buffer = (char *)malloc(1024 * sizeof(char));
#4: If I use getc() within while loop like
char *buf, c;
int i=0, j=1;
int pipefd[2];
int stdout_bk;
code[message_read] = '\0';
stdout_bk = dup(fileno(stdout));
pipe(pipefd);
dup2(pipefd[1], STDOUT_FILENO);
system(code);
close(pipefd[1]);
dup2(stdout_bk, STDOUT_FILENO);
buf = (char*)malloc(sizeof(char));
while(c!=End_Of_File) // What should I replace End_Of_File with?
{
c = getc(pipefd[0]);
buf = (char*)realloc(buf, j * sizeof(char));
buf[i] = c;
i++;
j++;
}
I do not know what is the End_Of_file for the stdout data.
P.S.: the program runs a command, e.g., system("setarch x86_64 -R dd if=/proc/self/maps | grep bin/dd") or system("ls -al") and I need to get the STDOUT. For that I have used dup2 and need to pipe the output to a buffer.
NOTE: the output can be of variable length.
There are many issues with your code:
c must be defined with type int
getc() cannot take a system handle as an argument, you must wrap that in a FILE* with fdopen().
End_Of_File for data returned by getc() is simply EOF and c must have type int for end of file testing to be reliable.
reallocating the array one byte at a time is inefficient and might be more wasteful than reallocating by chunks
more importantly you might want to allocate one extra byte for a null terminator if you intend to use this buffer as a C string.
the output of the system() command will be limited to the size of the system pipe buffers, usually around 5KB, so your program will get stuck for any larger output.
it is much simpler to use popen() for your purpose.
Here is a simplified version:
#include <stdio.h>
#include <stdlib.h>
int main() {
char code[] = "ls -lR";
char *buf = NULL;
int c;
int i = 0;
FILE *fp;
fp = popen(code, "r");
if (fp == NULL) {
fprintf(stderr, "popen error\n");
return 1;
}
while ((c = getc(fp)) != EOF) {
buf = (char *)realloc(buf, i + 2);
if (buf == NULL) {
fprintf(stderr, "out of memory\n");
pclose(fp);
return 1;
}
buf[i++] = (char)c;
}
pclose(fp);
printf("output: %d bytes\n", i);
if (buf != NULL) {
buf[i] = '\0';
fputs(buf, stdout);
}
free(buf);
return 0;
}

fread position cursor does not seem to advance as expected

I'm trying to dynamically realloc memory for a file being read one character at a time. It is not printing the buffer character by character. It looks like the fread function is not advancing 1 character at a time.
int main() {
FILE *fp;
char *newBuffer;
char *buffer = malloc(sizeof(char));
int count = 0;
/* Open file for both reading and writing */
fp = fopen("test.txt", "r");
if (!fp) {
exit(99);
}
/* Seek to the beginning of the file */
fseek(fp, SEEK_SET, 0);
/* Read into memory and display the buffer as its read */
while (1) {
newBuffer = (char*)realloc(buffer, (sizeof(char) * (++count)));
if (newBuffer) {
buffer = newBuffer;
buffer += (count - 1);
fread(buffer, sizeof(char), 1, fp);
if (feof(fp)) {
buffer = newBuffer;
break;
}
buffer = newBuffer;
printf(" %s\n", buffer);
} else {
// realloc failed
free(buffer);
exit(1);
}
}
fclose(fp);
free(newBuffer);
return(0);
}
You do not null terminate the buffer before using it as a string in printf, this is a problem.
Note that you can simplify or improve the code in various ways:
no need to fseek(fp, SEEK_SET, 0); after fopen, the FILE is already at the starting position. Note that you interverted the arguments to fseek: it should be fseek(fp, 0L, SEEK_SET); but you are lucky SEEK_SET is #defined as 0.
reading one byte from the file is much simpler with getc than fread(buffer, sizeof(char), 1, fp);. It allows for a simpler and better test for end of file. Using feof() only works in your example because you only attempt to read a single byte.
no need for the initial malloc, set buffer toNULL.reallocacceptsNULLand behaves likemallocwith such as argument,freeaccepts aNULL` argument and does nothing.
do not cast the return value of malloc, nor realloc.
sizeof(char) is 1 by definition: either use sizeof(*buffer) or elide the sizeof completely.
do not parenthesize the return expression.
the prototype for main without arguments is int main(void)
Here is a simpler version:
int main(void) {
FILE *fp;
char *newBuffer;
char *buffer = NULL;
int count = 0, c;
/* Open file for both reading */
fp = fopen("test.txt", "r");
if (!fp) {
exit(99);
}
/* Read into memory and display the buffer read */
while ((c = getc(fp)) != EOF) {
newBuffer = realloc(buffer, count + 2);
if (newBuffer) {
buffer = newBuffer;
buffer[count++] = c;
buffer[count] = '\0';
printf(" %s\n", buffer);
} else {
// realloc failed
fclose(fp);
free(buffer);
exit(1);
}
}
fclose(fp);
free(buffer);
return 0;
}
Your printf(" %s\n", buffer); expects buffer to end with a '\0' (null) character. Your code doesn't provide the required null.

Search for a word in file line by line in C programming

I am trying to write code to search for a word in a file line by line and print the line containing the word.
Functions fgets and getline didn't seem to work.
void FindWord(char *word , char *file){
char *line ;
line = (char*)malloc(1024) ;
int fd ;
fd = open(file , O_RDONLY );
while (fgets(line , sizeof(line) ,fd )!= NULL)
{
if (strstr(line , word )!= NULL)
{
printf("%s",line);
}
}
}
Problem 1
fgets() needs a FILE* not a file descriptor.
Change
int fd ;
fd = open(file , O_RDONLY );
to
FILE* fp = fopen(file, "r");
and use fp as the argument to fgets.
Problem 2
sizeof(line) doesn't evaluate to 1024, as you are probably expecting. It just evaluates to the size of a pointer, which is most likely 4 or 8.
Change
while (fgets(line , sizeof(line) ,fd )!= NULL)
to
while (fgets(line , 1024, fp )!= NULL)
Update
Also, since you are hard coding 1024 in the call to malloc, you might as well use an array. Then, you can use sizeof(line).
void FindWord(char *word , char *file){
char line[1024] ;
FILE* fp = fopen(file, "r") ;
while (fgets(line , sizeof(line) , fp )!= NULL)
{
if (strstr(line , word )!= NULL)
{
printf("%s",line);
}
}
}
Couple of things are wrong.
You should not use open and work with file descriptors, if you don't have to.
Also, fgets needs FILE as 3. argument, not file descriptor. Use FILE macro:
FILE *f = fopen("myfile.txt", "r");
// Use f here
fclose(f);
Second, you allocated memory and never release it.
char *line = malloc(1024 /* *sizeof(char)*/);
//Some code here
free(line);
sizeof(line) returns size of pointer, not buffer size.
fgets(line , n , f) reads n bytes, not line. It reads at most n bytes, stops on '\n' or EOF. Use getline instead.
char *line_buffer = NULL;
size_t n = 0;
FILE *f = fopen(...);
getline(&line_buffer, &n, f);
//use here
fclose(f);
free(line_buffer);
All combined:
void FindWord(char *word , char *file){
char *line = NULL;
size_t n = 0;
FILE *f = fopen(file, "r") ;
while (getline(&line_buffer, &n, f) != -1)
{
if (strstr(line , word )!= NULL)
{
printf("%s",line);
}
}
fclose(f);
free(line);
}

Reading a file character by character in C

I'm writing a BF interpreter in C and I've run into a problem reading files. I used to use scanf in order to read the first string, but then you couldn't have spaces or comments in your BF code.
Right now here is what I have.
char *readFile(char *fileName)
{
FILE *file;
char *code = malloc(1000 * sizeof(char));
file = fopen(fileName, "r");
do
{
*code++ = (char)fgetc(file);
} while(*code != EOF);
return code;
}
I know the problem arises in how I'm assigning the next char in the file to the code pointer but I'm just not sure what that is.
My pointer knowledge is lacking which is the point of this exercise.
The interpreter works fine, all using pointers, I'm just having a problem reading files in to it.
(I'm going to implement only reading +-><[]., into the file later, although if anyone has a good way to do it, it would be great if you'd let me know!)
There are a number of things wrong with your code:
char *readFile(char *fileName)
{
FILE *file;
char *code = malloc(1000 * sizeof(char));
file = fopen(fileName, "r");
do
{
*code++ = (char)fgetc(file);
} while(*code != EOF);
return code;
}
What if the file is greater than 1,000 bytes?
You are increasing code each time you read a character, and you return code back to the caller (even though it is no longer pointing at the first byte of the memory block as it was returned by malloc).
You are casting the result of fgetc(file) to char. You need to check for EOF before casting the result to char.
It is important to maintain the original pointer returned by malloc so that you can free it later. If we disregard the file size, we can achieve this still with the following:
char *readFile(char *fileName)
{
FILE *file = fopen(fileName, "r");
char *code;
size_t n = 0;
int c;
if (file == NULL)
return NULL; //could not open file
code = malloc(1000);
while ((c = fgetc(file)) != EOF)
{
code[n++] = (char) c;
}
// don't forget to terminate with the null character
code[n] = '\0';
return code;
}
There are various system calls that will give you the size of a file; a common one is stat.
Expanding upon the above code from #dreamlax
char *readFile(char *fileName) {
FILE *file = fopen(fileName, "r");
char *code;
size_t n = 0;
int c;
if (file == NULL) return NULL; //could not open file
fseek(file, 0, SEEK_END);
long f_size = ftell(file);
fseek(file, 0, SEEK_SET);
code = malloc(f_size);
while ((c = fgetc(file)) != EOF) {
code[n++] = (char)c;
}
code[n] = '\0';
return code;
}
This gives you the length of the file, then proceeds to read it character by character.
Here's one simple way to ignore everything but valid brainfuck characters:
#define BF_VALID "+-><[].,"
if (strchr(BF_VALID, c))
code[n++] = c;
the file is being opened and not closed for each call to the function also
I think the most significant problem is that you're incrementing code as you read stuff in, and then returning the final value of code, i.e. you'll be returning a pointer to the end of the string. You probably want to make a copy of code before the loop, and return that instead.
Also, C strings need to be null-terminated. You need to make sure that you place a '\0' directly after the final character that you read in.
Note: You could just use fgets() to get the entire line in one hit.
Either of the two should do the trick -
char *readFile(char *fileName)
{
FILE *file;
char *code = malloc(1000 * sizeof(char));
char *p = code;
file = fopen(fileName, "r");
do
{
*p++ = (char)fgetc(file);
} while(*p != EOF);
*p = '\0';
return code;
}
char *readFile(char *fileName)
{
FILE *file;
int i = 0;
char *code = malloc(1000 * sizeof(char));
file = fopen(fileName, "r");
do
{
code[i++] = (char)fgetc(file);
} while(code[i-1] != EOF);
code[i] = '\0'
return code;
}
Like the other posters have pointed out, you need to ensure that the file size does not exceed 1000 characters. Also, remember to free the memory when you're done using it.
The problem here is twofold
a) you increment the pointer before you check the value read in, and
b) you ignore the fact that fgetc() returns an int instead of a char.
The first is easily fixed:
char *orig = code; // the beginning of the array
// ...
do {
*code = fgetc(file);
} while(*code++ != EOF);
*code = '\0'; // nul-terminate the string
return orig; // don't return a pointer to the end
The second problem is more subtle -fgetc returns an int so that the EOF value can be distinguished from any possible char value. Fixing this uses a temporary int for the EOF check and probably a regular while loop instead of do / while.

Resources