how to make getc() on stdin be binary - c

I'm using a while loop with getc() to read from a file handle and it works fine. Now I'm adding support for pipes.
My problem is that while x0A, X0D, and x0A0D pass just fine, any cases of x0D0A get reduced to just x0A. Also x1A seems to stop the process entirely when encountered.
I'm piping in the output of tar, and is messing the files up.
FILE *FH;
FH=stdin;
int buff;
while((buff=getc(FH))!=EOF) {
//stuff
}
That's simplified, as FH needs to point to either a file or stdin. For testing I'm just writing the buff out to a file to see the changes. The code works perfectly if FH is a file.
I've seen the same behavior on using tar, type, and cat as the pipe source

You will need to fopen with a binary mode. I'm not sure if you can use freopen on stdin, but give it a try:
freopen(NULL, "rb", stdin);

You have to open the file in binary mode you are writing into. The combination 0d0a is a carriage return followed by new line and depending on the system will get changed when you write in text mode.

Related

Reading a string from a file with C. Fopen with w+ mode is not working

I made a C program that reads a string from a .txt file, then it encrypts the string, and finally it writes the string in the same file.
The thing is that if I use fopen("D:\\Prueba.txt","w+"), the program doesn't work, it prints garbage like this )PHI N.
I've debugged and I know the error is there in that line, because if I use fopen("D:\\Prueba.txt","r+"), the program works, and it writes what it should.
But I want to use w+ because it will rewrite what the .txt file had. Why is w+ not working?
If you're opening with w+ to first read the content, that's not going to work. From C11:
w+: truncate to zero length or create text file for update.
What's probably happening is that you read data from the now empty file but don't correctly check that it worked. That would explain the weird "content" you see of )PHI N.
One solution is to open the file as with r, open another file with w, and transfer the contents, encrypting them as part of that process. Then close both, delete the original, and rename the new one to the original name. This will allow you to process arbitrarily-sized files since you process them a bit at a time.
If you don't want to use a temporary file, and you're sure you can store the entire content in memory, you could open it r+, get the content, the reopen it with a new mode, such as with:
FILE *readFh = fopen( "myfile.txt", "r+");
// Read in content, massage as needed.
FILE *writeFh = frepoen( NULL, "w+", readFh);
// Provided that worked, you should now have an empty file to write to.
// Write back your massaged data.

File is not written on disk until program ends

I'm writing a file using a c code on a unix system . I open it , write a few lines and close it. Then i call a shell script, say code B where this file is to be used and then return back to main program. However, when code B tries to read the file, the file is empty.
I checked the file on the file system, its size is shown as 0 and no data is present in file. However after killing the running c code process, file has data present in it.
Here is the piece of code -
void writefile(){
FILE *fp;
fp = fopen("ABC.txt","w");
fputs("Some lines...\n",fp);
fclose(fp);
system("code_B ABC.txt");
}
Please advise how can I read the file in the shell script without stopping the c code process.
If there's some time between the fputs and fclose, add
fflush(fp);
This will cause the contents of the disk file to be written.
You should do fsync() after the fclose(), to guarantee the writing of the file to the disk.
Take a look at this question:
Does Linux guarantee the contents of a file is flushed to disc after close()?
The kernel ensures that data which is written to a file can be read back afterwards from a different process, even if it is not physically written to the disc yet. So, in usual scenarios, there is no need to call fsync() - still, even with fsync(), the filesystem could decide to further delay physical writes.
One common problem is that the C library has not flushed its buffers yet, in which case you would need to call fflush() - however, you are calling fclose() before launching your sub process, and fclose() internally calls fflush().
Actually, since system() is using a shell to launch the command passed as parameter, you can use the following simple SSCCE to verify that it works:
#include <stdio.h>
void writefile(){
FILE *fp;
fp = fopen("ABC.txt","w");
fputs("Some lines...\n",fp);
fclose(fp);
system("cat ABC.txt");
}
int main() {
writefile();
return 0;
}
Here, system() simply calls the cat command to print the file contents. The output is:
$ ./writefile
Some lines...

Writing line to a file using C

I'm currently doing this:
FILE *fOut;
fOut = fopen("fileOut.txt", "w");
char line[255];
...
strcat(line, "\n");
fputs(line, fOut);
but find that when I open the file in a text editor I get
line 1
line 2
If I remove the strcat(line, "\n"); then I get.
line 1line2
How do I get fOut to be
line 1
line 2
The puts() function appends a newline to the string it is given to write to stdout; the fputs() function does not do that.
Since you've not shown us all the code, we can only hypothesize about what you've done. But:
strcpy(line, "line1");
fputs(line, fOut);
putc('\n', fOut);
strcpy(line, "line2\n");
fputs(line, fOut);
would produce the result you require, in two slightly different ways that could each be used twice to achieve consistency (and your code should be consistent — leave 'elegant variation' for your literature writing, not for your programming).
In a comment, you say:
I'm actually looping through a file encrypting each line and then writing that line to a new file.
Oh boy! Are you base-64 encoding the encrypted data? If not, then:
You must include b in the fopen() mode (as in fOut = fopen("fileout.bin", "wb");) because encrypted data is binary data, not text data. This (the b) is safe for both Unix and Windows, but is critical on Windows and immaterial on Unix.
You must not use fputs() to write the data; there will be zero bytes ('\0') amongst the encrypted values and fputs() will stop at the first of those that it encounters. You probably need to use fwrite() instead, telling it exactly how many bytes to write each time.
You must not insert newlines anywhere; the encrypted data might contain newlines, but those must be preserved, and no extraneous one can be added.
When you read this file back in, you must open it as a binary file "rb" and read it using fread().
If you are base-64 encoding your encrypted data, then you can go back to treating the output as text; that's the point of base-64 encoding.
When files are opened with w (or wt) Windows replaces the \n with \r\n.
To avoid this, open the file with wb (instead of w).
...
fOut = fopen("fileOut.txt", "wb");
...
Unlike many other OSs, Windows makes a distinction between binary and text mode, and -- confusingly -- the Windows C runtime handles both modes differently.
You can try using \r instead of \n. What platform are you running this on, Windows?

executing a command and getting o/p to a variable

popen stores o/p of the specified command into a file. How can I get similar functionality but o/p into a variable (i.e. in a char*) ?
No, popen() does not store output into a file. It specifies a stream, which might represent to a file on disk but which might also be at e.g. a pipe or socket. Streams are more abstract than files.
To have a pipe, you would open the pipe using e.g. pipe() and then call fdopen() on the proper end of the resulting pipe.
I could not find anything that returns o/p in a variable. It kind of makes sense as some commands' o/p can be large so to make the behavior consistent, o/p is stored in the file. I actually ended up reading from file returned by popen.
Thanks for all the help.
you can replace STDOUT and STDERR for the launched command with a stream that you control
Do you want to run a unix command from a C program, and store the output?
If so, then the sequence is to call FILE* pipe = popen("wc -l filename", "r"); and then read from the FILE* pipe just as you would read from a file opened using fopen. That is, you use functions like fgets or fscanf to read the output, just as you would if the output of the command were in a file.

Inserting data to file in c

I need to add a string before the 45th byte in an existing file. I tried using fseek as shown below.
int main()
{
FILE *fp;
char str[] = "test";
fp = fopen(FILEPATH,"a");
fseek(fp,-45, SEEK_END);
fprintf(fp,"%s",str);
fclose(fp);
return(0);
}
I expected that this code will add "test" before the 45th char from EOF, instead, it just appends "test" to the EOF.
Please help me to find the solution.
This is continuation of my previous question
Append item to a file before last line in c
Open it with mode r+ (if it already exists) or a+ (if it doesn't exist and you want to create it). Since you're seeking to 45 bytes before the end of file, I'm assuming it already exists.
fp = fopen(FILEPATH,"r+");
The rest of your code is fine. Also note that this will not insert the text, but will overwrite whatever is currently at that position in the file.
ie, if your file looks like this:
xxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxx
Then after running this code, it will look like this:
xxxxxxxtestxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxx
If you really want to insert and not overwrite, then you need to read all the text from SEEK_END-45 to EOF into memory, write test and then write the text back
Don't open it as append (a) if you plan to write at arbitrary positions; it will force all writes to the end of the file. You can use r+ to read or write anywhere.
To avoid platform-specific configurations, always explicitely indicate the binary or text mode in your fopen() call.
This will save you hours of desperations if you port your code one day.

Resources