Reading data from stdin in C - c

I'm trying to read from stdin and output the data, things work, EXCEPT that it's not outputting the new incoming data. I'm not quite sure where is the issue. I'm guessing it has something to do when determining the stdin size. Any help would be greatly appreciated! Thanks
tail -f file | my_prog
Updated
#include <stdio.h>
#include <sys/stat.h>
long size(FILE *st_in) {
struct stat st;
if (fstat(fileno(st_in), &st) == 0)
return st.st_size;
return -1;
}
int main (){
FILE *file = stdin;
char line [ 128 ];
while ( fgets ( line, sizeof line, file ) != NULL )
fputs ( line, stdout ); /* write the line */
long s1, s2;
s1 = size(file);
for (;;) {
s2 = size (file);
if (s2 != s1) {
if (!fseek (file, s1, SEEK_SET)) {
while ( fgets ( line, sizeof line, file ) != NULL ) {
fputs ( line, stdout ); /* write the line */
}
}
s1 = s2;
usleep(300000);
}
}
return 0;
}
Edit: Fixed!

After a FILE * has reached EOF, it stays in a state where it will read no more data until you clear the 'EOF' bit either with clearerr() or with fseek(). However, if standard input is connected to a terminal, then that is not a seekable device, so instead of clearing the error, it might not do anything useful:
POSIX says:
The behavior of fseek() on devices which are incapable of seeking is implementation-defined.
Your loop entry condition is suspect; you need to sleep before starting it, and you need to sleep on each iteration. Indeed, normally you write tail -f without worrying about the file size; you sleep, try to read until the next 'EOF', reset the file EOF indicator, and repeat. Note, too, that the size of a pipe or terminal is not defined.
Separately, it is aconventional to call a FILE * argument to a function filename; it has completely the wrong connotations. A filename is a string.

This is not really standard C:
size(file);
Call stat() to get file information - organization type of a file, file size and permissions.
What your code does is to eventually set the file pointer to the end of the file, as it tries to read through it. Consider stat() (or fstat() on a an open file) instead.
rewind() resets the file pointer to the start of the file, fseek() will place it anywhere you need.
tail -f repeatedly tries the file at the EOF point with a short sleep in between tries.... It does not "consider" EOF to be an error. It remembers the current file offset for the EOF, then fseeks() using SEEK_END, then calls ftell(), and compares the offsets. If there is a difference it then fseek()-s back to the last known endpoint and reads the data.
This description is from old unix source. I'm sure it has been tweaked since then.

Related

Why is my program perceiving an EOF condition way before my file actually ends?

My code reads line by line from a text file and stores the lines in a massive array of char pointers. When I use an ordinary text file, this works with no issues. However, when I try to read from the 'dictionary.txt' file I'm supposed to be using, my program detects EOF after reading the first of MANY lines in the file.
int i = 0;
while( 1 ) {
size_t size = 50;
fseek( dicFile, 0L, getline( &dictionary[i++], &size, dicFile) );
printf( "%d:\t%s", i, dictionary[i - 1] );
if( feof( dicFile ) ) {
fclose( dicFile );
break;
}
}
puts("finished loading dictionary");
Here is the start of the dictionary file I'm attempting to load:
A
A's
AA's
AB's
ABM's
AC's
ACTH's
AI's
AIDS's
AM's
AOL
AOL's
ASCII's
ASL's
ATM's
ATP's
AWOL's
AZ's
The output is get from this portion of the program is:
1: A
2: finished loading dictionary
Thanks for any help.
Your third argument to fseek() is nuts. I've seen at least one implementation that treated every out of range third argument as SEEK_END. Oops.
You should just call getline() in the loop instead. In fact, just check the return value of getline() for -1 and get rid of that feof().

does the read call in linux add a newline at EOF?

why does read() on a file in linux add a newline character at EOF even if the file really does not have a newline character ?
my file data is :
1hello2hello3hello4hello5hello6hello7hello8hello9hello10hello11hello12hello13hello14hello15hello
my read() call on this file should hit EOF after reading the last 'o' in "15hello". I use the below :
while( (n = read(fd2, src, read_size-1)) != 0) // read_size = 21
{
//... some code
printf("%s",src);
//... some code
}
where fd2 is the file's descriptor. At the last loop, n was 17 and i had src[16] = '\n'. So......, does the read call in linux add a newline at EOF?
does the read call in linux add a newline at EOF?
No.
Your input file likely has a terminating newline in it - most well-formatted text files do, so multiple files can be concatenated without lines running together.
You could also be running into a stray newline character that was already in your buffer, because read() does not terminate the data read with a NUL character to create an actual C-style string. And I'd guess your code doesn't either, else you would have posted it. Which means your
printf("%s",src);
is quite likely undefined behavior.
why does read() on a file in linux add a newline character at EOF even if the file really does not have a newline character ? No, read() system call doesn't add any new line at end of file.
You are experiencing this kind of behavior because may be you have created text file using vi command and note that default new line gets added if you have created file using vi.
You can validate this on your system by creating a empty text file using vi and then run wc command on that.
Also you can read file data using read() system call all at once if you know the file size(find size using stat() system call) and can avoid while loop.
This
while( (n = read(fd2, src, read_size-1)) != 0) {
/* some code */
}
Change to
struct stat var;
stat(filename, &var); /* check the retuen value of stat()..having all file info now */
off_t size = var.st_size;
Now you have size of file, create one dynamic or stack array equal to size and read the data from file.
char *ptr = malloc(size + 1);
Now read all data at once like
read(fd,ptr,size);/*now ptr having all file contents */
And at last once work done, Don't forgot to free the ptr by calling free(ptr).

How to move the position pointer to next line in the file using fseek

I have seen programs for file handling and in one of the program using fseek as shown below:
/* This example opens a file myfile.dat for reading.
After performing input operations (not shown), it moves the file
pointer to the beginning of the file.
*/
#include <stdio.h>
int main(void)
{
FILE *stream;
int result;
if (stream = fopen("myfile.dat", "r"))
{ /* successful */
if (fseek(stream, 0L, SEEK_SET)); /* moves pointer to */
/* the beginning of the file */
{ /* if not equal to 0
then error ... */
}
else {
/* fseek() successful */
}
}
Like this can one move the file pointer to the next line immediately after that line
BO_ 377 FC_DM_MISC: 8 FC
SG_ DATA3 m11 : 31|8#0+ (1,0) [0|0] "" DM
These are the two lines and I want to program in a way that when one identifies the number 377 the pointer should now go to the next line i.e., to the line SG_ DATA3 inspite of the white spaces after 8 FC. How can one do that using fseek in C?
Try this code . It may help you .Here the Each line of the Input file is converted to string ,since string manipulation is very simple comparing to complex fseek() function.This may not be perfect answer but this will be very simple solution.
#include <stdio.h>
#include <string.h>
int main(void)
{
FILE *stream;
int result;
char tmp[100]; // assuming that max length of a line in myfile.dat is 100.
if (stream = fopen("myfile.dat", "r"))
{ /* successful */
fscanf(stream, "%100[^\n]", tmp); // assuming that max length of a line in myfile.dat is 100.
printf("%s", tmp);
if (strstr(tmp, "377"))
{ // check for 337
fscanf(stream, "%100[^\n]", tmp); // next line is in the string tmp .
// continue your program.
//printf("%s", tmp);
}
}
}
fseek is used for binary data, if you work on a text file you should use either fgets or getline(recommended to use getline).
There's an open discussion of "fgets() vs getline" and many say that "fgets is deprecated" is only a gcc propaganda in favor to their specific getline().
A possible flaw in fgets() is that it doesn't tell you anything if there are null bytes being read, something you can get away with getline().
But then again if you don't like gcc, or use something different, use fgets(). If you are stuck with gcc, then use getline().

C File management error

I wanted to write, read and print to and from the same file. But when the program executes, it can write but it can't read or print the data I have written. When I execute the program, it stops working after writing to the file. I have verified that the file (penny.txt) contains data after the write operation.
I don't know where this is going wrong - how can I read and print the data?
I'm quite new to this, so please take that in mind when answering.
#include<stdio.h>
int main()
{
char ch;
char penny[50],pen[50];
FILE *Object;
Object = fopen("Penny.txt","w+");
fgets(penny, sizeof penny, stdin);
fprintf(Object,penny);
fscanf(Object,"%s",pen);
printf("%s",pen);
return 0;
}
You're at the end of the file when you call fscanf(). Use fseek to return to the beginning:
/* this ignores a whole host of other issues */
fprintf(Object,penny);
/* optional: fflush(Object); */
/* after the call to fprintf you're at the end of the "stream" in this case,
* go back to the beginning:
*/
fseek(Object, 0, SEEK_SET);
/* now we have something to read! */
fscanf(Object,"%s",pen);
printf("%s\n",pen);
You did not notice this problem due to a complete lack of error checking. fopen, fprintf, and fscanf all have error conditions listed, and all use their return value to signal a problem. You ignore these return values at your own peril.
#include<stdio.h>
int main()
{
//char ch;//unused!
char penny[50],pen[50];
FILE *Object;
Object = fopen("Penny.txt","w+");
fgets(penny, sizeof penny, stdin);
fprintf(Object,"%s", penny);//it troubled indicator(%) is included
fflush(Object);//Buffer flush : So that there is no wrote
rewind(Object);//rewind the position of access to the file
fscanf(Object,"%s",pen);
printf("%s",pen);
return 0;
}
You need to Use fseek() to move back the file current position inside the file.
int fseek ( FILE * stream, long int offset, int origin );
Reposition stream position indicator
Sets the position indicator associated with the stream to a new position.
stream
Pointer to a FILE object that identifies the stream.
offset
Binary files: Number of bytes to offset from origin.
Text files: Either zero, or a value returned by ftell.
origin
Position used as reference for the offset. It is specified by one of the following constants defined in exclusively to be used as arguments for this function:
Constant Reference position
SEEK_SET Beginning of file
SEEK_CUR Current position of the file pointer
SEEK_END End of file
*
try this:
#include<stdio.h>
int main()
{
char ch;
char penny[50],pen[50];
FILE *Object;
Object = fopen("Penny.txt","w+");
fgets(penny, sizeof penny, stdin);
fprintf(Object,penny);//now the file is in EOF
fseek(Object,-1*(strlen(penny),SEEK_CUR);//<===move back |penny| in the file
/* optional or:fseek(Object,0,SEEK_SET);<===move to start of file */
fscanf(Object,"%s",pen);
printf("%s",pen);
return 0;
}

Reading a C file, read an extra line, why?

I don't know exactly why a file pointer reads an extra line from a file, specifically the last line, here is the code:
FILE *fp ;
fp = fopen ("mac_ip.txt", "r") ;
int mac;
char *ip = (char *) malloc(15);
while(!feof(fp)){
fscanf(fp,"%i",&mac);
fscanf(fp,"%s",ip);
printf("MAC: %i\n",mac);
printf("IP: %s\n",ip);
}
and the file has exactly 20 lines, but the line 20, is printed twice.
Which is the error?
Thanks in advance.
Because after reading the last two values, you still haven't hit EOF. So the loop goes on. In the next pass of the loop, fscanf actually does not read the last line for the second time like it appears, the fscanfs fail, but the printfs print out the values from the previous pass of the loop.
feof does not "know" it's at the end of file until you try to read some more. Since fscanf tells you how many items it got, you can use this simple trick:
for(;;){
if (fscanf(fp,"%i%s", &mac, ip) != 2) break;
printf("MAC: %i\n",mac);
printf("IP: %s\n",ip);
}
After you have done the two reads on the twentieth line, you have got to the end of the file but the system doesn't know this. feof will only trigger when you try to get past the end of the file, not when you are exactly on it ...
Also, you may have a line-end (CR or CR-LF) on the 20th line which it will only get past with another attempted read.
The solution is to read the line in one go (there is a specific C command for this) and then parse that to get your data. If the whole-line read fails, then you've got to the end.
Your code resembles to the following example
#include <stdio.h>
int main(void)
{
char buffer[256];
FILE * myfile;
myfile = fopen("some.txt","r");
while (!feof(myfile))
{
fgets(buffer,256,myfile);
printf("%s",buffer);
}
fclose(myfile);
return 0;
}
from
http://www.friedspace.com/feof.html
You better test for fscanf return value before printing result. I bet that in the last iteration of your loop, fscanf calls fail and you print the last returned results.
FILE *fp ;
int mac;
char ip[15];
fp = fopen ("mac_ip.txt", "r") ;
if (!fp) return;
while(1){
if (fscanf(fp,"%i",&mac) < 1) break;
if (fscanf(fp,"%s",ip) < 1) break;
printf("MAC: %i\n",mac);
printf("IP: %s\n",ip);
}
fclose (fp);
fscanf() returns the number of assignments it mad (or -1 on eof). By using the return value, you don't need the eof() function. BTW I don't think you can read a MAC address into an int. Maybe you need to read that into a string, too ?
Explanation: feof() does not do what the OP expects. feof() should only be inspected after one of the file operations failed. In most cases you don't need feof().

Resources